From 7616c4d06d2eb75021d7de389c0f17ffdc097b6e Mon Sep 17 00:00:00 2001 From: "bruceallenfb@gmail.com" Date: Fri, 18 Jan 2013 20:14:03 +0000 Subject: [PATCH] re-port to c#, picking up 3 years of changes. Client folder classes may need some work git-svn-id: https://zxing.googlecode.com/svn/trunk@2558 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- csharp/AssemblyInfo.cs | 2 + csharp/BarcodeFormat.cs | 192 ++- csharp/Binarizer.cs | 174 ++- csharp/BinaryBitmap.cs | 298 ++-- csharp/DecodeHintType.cs | 137 +- csharp/EncodeHintType.cs | 95 +- csharp/LuminanceSource.cs | 265 ++-- csharp/MultiFormatReader.cs | 348 +++-- csharp/MultiFormatWriter.cs | 132 +- csharp/RGBLuminanceSource.cs | 314 ++-- csharp/Reader.cs | 109 +- csharp/ReaderException.cs | 140 +- csharp/Result.cs | 293 ++-- csharp/ResultMetadataType.cs | 134 +- csharp/ResultPoint.cs | 279 ++-- csharp/ResultPointCallback.cs | 45 +- csharp/Writer.cs | 102 +- csharp/WriterException.cs | 67 +- .../result/AbstractDoCoMoResultParser.cs | 64 +- .../result/AddressBookAUResultParser.cs | 132 +- .../result/AddressBookDoCoMoResultParser.cs | 127 +- .../client/result/AddressBookParsedResult.cs | 364 +++-- csharp/client/result/BizcardResultParser.cs | 163 +- .../result/BookmarkDoCoMoResultParser.cs | 79 +- csharp/client/result/CalendarParsedResult.cs | 424 ++++-- .../client/result/EmailAddressParsedResult.cs | 162 +- .../client/result/EmailAddressResultParser.cs | 121 +- .../client/result/EmailDoCoMoResultParser.cs | 140 +- csharp/client/result/GeoParsedResult.cs | 228 ++- csharp/client/result/GeoResultParser.cs | 133 +- csharp/client/result/ISBNParsedResult.cs | 90 +- csharp/client/result/ISBNResultParser.cs | 96 +- csharp/client/result/ParsedResult.cs | 145 +- csharp/client/result/ParsedResultType.cs | 97 +- csharp/client/result/ProductParsedResult.cs | 119 +- csharp/client/result/ProductResultParser.cs | 120 +- csharp/client/result/ResultParser.cs | 599 ++++---- csharp/client/result/SMSMMSResultParser.cs | 214 ++- csharp/client/result/SMSParsedResult.cs | 234 +-- csharp/client/result/TelParsedResult.cs | 139 +- csharp/client/result/TelResultParser.cs | 77 +- csharp/client/result/TextParsedResult.cs | 112 +- csharp/client/result/URIParsedResult.cs | 257 ++-- csharp/client/result/URIResultParser.cs | 144 +- csharp/client/result/URLTOResultParser.cs | 77 +- csharp/client/result/VCardResultParser.cs | 573 ++++--- csharp/client/result/VEventResultParser.cs | 174 ++- csharp/common/BitArray.cs | 522 ++++--- csharp/common/BitMatrix.cs | 530 ++++--- csharp/common/BitSource.cs | 197 +-- csharp/common/CharacterSetECI.cs | 340 +++-- csharp/common/DecoderResult.cs | 143 +- csharp/common/DefaultGridSampler.cs | 149 +- csharp/common/DetectorResult.cs | 98 +- csharp/common/GlobalHistogramBinarizer.cs | 417 +++-- csharp/common/GridSampler.cs | 325 ++-- csharp/common/HybridBinarizer.cs | 381 +++-- csharp/common/PerspectiveTransform.cs | 248 ++- .../detector/MonochromeRectangleDetector.cs | 452 +++--- .../common/reedsolomon/ReedSolomonDecoder.cs | 367 ++--- .../common/reedsolomon/ReedSolomonEncoder.cs | 149 +- .../reedsolomon/ReedSolomonException.cs | 54 +- csharp/datamatrix/DataMatrixReader.cs | 327 ++-- csharp/datamatrix/decoder/BitMatrixParser.cs | 1029 ++++++------- csharp/datamatrix/decoder/DataBlock.cs | 246 ++- .../decoder/DecodedBitStreamParser.cs | 1163 +++++++------- csharp/datamatrix/decoder/Decoder.cs | 277 ++-- csharp/datamatrix/decoder/Version.cs | 429 +++--- csharp/datamatrix/detector/Detector.cs | 733 +++++---- csharp/multi/ByQuadrantReader.cs | 190 +-- csharp/multi/GenericMultipleBarcodeReader.cs | 303 ++-- csharp/multi/MultipleBarcodeReader.cs | 70 +- csharp/multi/qrcode/QRCodeMultiReader.cs | 170 ++- csharp/multi/qrcode/detector/MultiDetector.cs | 152 +- .../detector/MultiFinderPatternFinder.cs | 646 ++++---- csharp/oned/Code128Reader.cs | 791 +++++----- csharp/oned/Code39Reader.cs | 711 +++++---- csharp/oned/Code39Writer.cs | 174 ++- csharp/oned/EAN13Reader.cs | 280 ++-- csharp/oned/EAN13Writer.cs | 162 +- csharp/oned/EAN8Reader.cs | 151 +- csharp/oned/EAN8Writer.cs | 138 +- csharp/oned/ITFReader.cs | 689 +++++---- csharp/oned/MultiFormatOneDReader.cs | 204 ++- csharp/oned/MultiFormatUPCEANReader.cs | 227 +-- csharp/oned/OneDReader.cs | 642 ++++---- csharp/oned/UPCAReader.cs | 167 +- csharp/oned/UPCEANReader.cs | 694 +++++---- csharp/oned/UPCEANWriter.cs | 168 +-- csharp/oned/UPCEReader.cs | 318 ++-- csharp/pdf417/PDF417Reader.cs | 362 +++-- csharp/pdf417/decoder/BitMatrixParser.cs | 926 ++++-------- .../pdf417/decoder/DecodedBitStreamParser.cs | 1338 ++++++++--------- csharp/pdf417/decoder/Decoder.cs | 289 ++-- csharp/pdf417/detector/Detector.cs | 1097 +++++++------- csharp/qrcode/QRCodeReader.cs | 361 +++-- csharp/qrcode/QRCodeWriter.cs | 285 ++-- csharp/qrcode/decoder/BitMatrixParser.cs | 440 +++--- csharp/qrcode/decoder/DataBlock.cs | 259 ++-- csharp/qrcode/decoder/DataMask.cs | 255 ++-- .../qrcode/decoder/DecodedBitStreamParser.cs | 815 +++++----- csharp/qrcode/decoder/Decoder.cs | 292 ++-- csharp/qrcode/decoder/ErrorCorrectionLevel.cs | 166 +- csharp/qrcode/decoder/FormatInformation.cs | 262 ++-- csharp/qrcode/decoder/Mode.cs | 292 ++-- csharp/qrcode/decoder/Version.cs | 560 ++++--- csharp/qrcode/detector/AlignmentPattern.cs | 98 +- .../qrcode/detector/AlignmentPatternFinder.cs | 589 ++++---- csharp/qrcode/detector/Detector.cs | 755 +++++----- csharp/qrcode/detector/FinderPattern.cs | 151 +- csharp/qrcode/detector/FinderPatternFinder.cs | 1247 +++++++-------- csharp/qrcode/detector/FinderPatternInfo.cs | 115 +- csharp/qrcode/encoder/BlockPair.cs | 89 +- csharp/qrcode/encoder/Encoder.cs | 1248 +++++++-------- csharp/qrcode/encoder/MaskUtil.cs | 393 +++-- csharp/qrcode/encoder/MatrixUtil.cs | 979 ++++++------ csharp/qrcode/encoder/QRCode.cs | 421 ++---- csharp/zxing.csproj | 112 +- 118 files changed, 19494 insertions(+), 18855 deletions(-) diff --git a/csharp/AssemblyInfo.cs b/csharp/AssemblyInfo.cs index aaf882e55..4578d7fa1 100755 --- a/csharp/AssemblyInfo.cs +++ b/csharp/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -60,3 +61,4 @@ using System.Runtime.CompilerServices; [assembly: AssemblyKeyName("")] +[assembly: ComVisibleAttribute(false)] diff --git a/csharp/BarcodeFormat.cs b/csharp/BarcodeFormat.cs index 811419df1..a483818b2 100755 --- a/csharp/BarcodeFormat.cs +++ b/csharp/BarcodeFormat.cs @@ -1,108 +1,98 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// Enumerates barcode formats known to this package. - /// - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class BarcodeFormat + /// + /// Enumerates barcode formats known to this package. Please keep alphabetized. + /// + /// @author Sean Owen + /// + public enum BarcodeFormat { - public System.String Name - { - get - { - return name; - } - - } - - // No, we can't use an enum here. J2ME doesn't support it. - - //UPGRADE_NOTE: Final was removed from the declaration of 'VALUES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly System.Collections.Hashtable VALUES = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); - - /// QR Code 2D barcode format. - //UPGRADE_NOTE: Final was removed from the declaration of 'QR_CODE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat QR_CODE = new BarcodeFormat("QR_CODE"); - - /// DataMatrix 2D barcode format. - //UPGRADE_NOTE: Final was removed from the declaration of 'DATAMATRIX '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat DATAMATRIX = new BarcodeFormat("DATAMATRIX"); - - /// UPC-E 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'UPC_E '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat UPC_E = new BarcodeFormat("UPC_E"); - - /// UPC-A 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'UPC_A '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat UPC_A = new BarcodeFormat("UPC_A"); - - /// EAN-8 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'EAN_8 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat EAN_8 = new BarcodeFormat("EAN_8"); - - /// EAN-13 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'EAN_13 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat EAN_13 = new BarcodeFormat("EAN_13"); - - /// Code 128 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'CODE_128 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat CODE_128 = new BarcodeFormat("CODE_128"); - - /// Code 39 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'CODE_39 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat CODE_39 = new BarcodeFormat("CODE_39"); - - /// ITF (Interleaved Two of Five) 1D format. - //UPGRADE_NOTE: Final was removed from the declaration of 'ITF '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat ITF = new BarcodeFormat("ITF"); - - /// PDF417 format. - //UPGRADE_NOTE: Final was removed from the declaration of 'PDF417 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly BarcodeFormat PDF417 = new BarcodeFormat("PDF417"); - - //UPGRADE_NOTE: Final was removed from the declaration of 'name '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String name; - - private BarcodeFormat(System.String name) - { - this.name = name; - VALUES[name] = this; - } - - public override System.String ToString() - { - return name; - } - - public static BarcodeFormat valueOf(System.String name) - { - BarcodeFormat format = (BarcodeFormat) VALUES[name]; - if (format == null) - { - throw new System.ArgumentException(); - } - return format; - } + + /// + /// Aztec 2D barcode format. + AZTEC, + + /// + /// CODABAR 1D format. + CODABAR, + + /// + /// Code 39 1D format. + CODE_39, + + /// + /// Code 93 1D format. + CODE_93, + + /// + /// Code 128 1D format. + CODE_128, + + /// + /// Data Matrix 2D barcode format. + DATA_MATRIX, + + /// + /// EAN-8 1D format. + EAN_8, + + /// + /// EAN-13 1D format. + EAN_13, + + /// + /// ITF (Interleaved Two of Five) 1D format. + ITF, + + /// + /// MaxiCode 2D barcode format. + MAXICODE, + + /// + /// PDF417 format. + PDF_417, + + /// + /// QR Code 2D barcode format. + QR_CODE, + + /// + /// RSS 14 + RSS_14, + + /// + /// RSS EXPANDED + RSS_EXPANDED, + + /// + /// UPC-A 1D format. + UPC_A, + + /// + /// UPC-E 1D format. + UPC_E, + + /// + /// UPC/EAN extension format. Not a stand-alone format. + UPC_EAN_EXTENSION + } + } \ No newline at end of file diff --git a/csharp/Binarizer.cs b/csharp/Binarizer.cs index 5e5b92851..e2f3760ef 100755 --- a/csharp/Binarizer.cs +++ b/csharp/Binarizer.cs @@ -1,93 +1,105 @@ +using System.Collections; + /* -* 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. -*/ -using System; -using BitArray = com.google.zxing.common.BitArray; -using BitMatrix = com.google.zxing.common.BitMatrix; + * 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. + */ + namespace com.google.zxing { - - /// This class hierarchy provides a set of methods to convert luminance data to 1 bit data. + + using BitArray = com.google.zxing.common.BitArray; + using BitMatrix = com.google.zxing.common.BitMatrix; + + /// + /// 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) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public abstract class Binarizer { - virtual public LuminanceSource LuminanceSource - { - get - { - return source; - } - - } - /// 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. - /// - /// - /// The 2D array of bits for the image (true means black). - /// - public abstract BitMatrix BlackMatrix{get;} - - //UPGRADE_NOTE: Final was removed from the declaration of 'source '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private LuminanceSource source; - - protected internal Binarizer(LuminanceSource source) - { - if (source == null) - { - throw new System.ArgumentException("Source must be non-null."); - } - this.source = 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. - /// - /// - /// The row to fetch, 0 <= y < bitmap height. - /// - /// 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. - /// - /// The array of bits for this row (true means black). - /// - public abstract BitArray getBlackRow(int y, BitArray row); - - /// 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. - /// - /// - /// The LuminanceSource this Binarizer will operate on. - /// - /// A new concrete Binarizer implementation object. - /// - public abstract Binarizer createBinarizer(LuminanceSource source); + + private readonly LuminanceSource source; + + protected internal Binarizer(LuminanceSource source) + { + this.source = source; + } + + public LuminanceSource LuminanceSource + { + get + { + 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. + /// + /// The row to fetch, 0 <= y < bitmap height. + /// 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. + /// The array of bits for this row (true means black). +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public abstract com.google.zxing.common.BitArray getBlackRow(int y, com.google.zxing.common.BitArray row) throws NotFoundException; + public abstract BitArray getBlackRow(int y, BitArray row); + + /// + /// 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. + /// + /// The 2D array of bits for the image (true means black). +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public abstract com.google.zxing.common.BitMatrix getBlackMatrix() throws NotFoundException; + public abstract BitMatrix BlackMatrix {get;} + + /// + /// 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. + /// + /// The LuminanceSource this Binarizer will operate on. + /// A new concrete Binarizer implementation object. + public abstract Binarizer createBinarizer(LuminanceSource source); + + public int Width + { + get + { + return source.Width; + } + } + + public int Height + { + get + { + return source.Height; + } + } + } + } \ No newline at end of file diff --git a/csharp/BinaryBitmap.cs b/csharp/BinaryBitmap.cs index aee771b07..36b8d0f02 100755 --- a/csharp/BinaryBitmap.cs +++ b/csharp/BinaryBitmap.cs @@ -1,161 +1,163 @@ +using System.Collections; + /* -* 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. -*/ -using System; -using BitArray = com.google.zxing.common.BitArray; -using BitMatrix = com.google.zxing.common.BitMatrix; + * 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. + */ + namespace com.google.zxing { - - /// This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects + + using BitArray = com.google.zxing.common.BitArray; + using BitMatrix = com.google.zxing.common.BitMatrix; + + /// + /// 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) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class BinaryBitmap { - /// The width of the bitmap. - /// - public int Width + + private readonly Binarizer binarizer; + private BitMatrix matrix; + + public BinaryBitmap(Binarizer binarizer) + { + if (binarizer == null) { - get + throw new System.ArgumentException("Binarizer must be non-null."); + } + this.binarizer = binarizer; + } + + /// The width of the bitmap. + public int Width + { + get + { + return binarizer.Width; + } + } + + /// The height of the bitmap. + public int Height + { + get + { + return binarizer.Height; + } + } + + /// + /// 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. + /// + /// The row to fetch, 0 <= y < bitmap height. + /// 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. + /// The array of bits for this row (true means black). +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitArray getBlackRow(int y, com.google.zxing.common.BitArray row) throws NotFoundException + public BitArray getBlackRow(int y, BitArray row) + { + 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. + /// + /// The 2D array of bits for the image (true means black). +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix getBlackMatrix() throws NotFoundException + public BitMatrix BlackMatrix + { + get + { + // 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) { - return binarizer.LuminanceSource.Width; + matrix = binarizer.BlackMatrix; } - - } - /// The height of the bitmap. - /// - public int Height - { - get - { - return binarizer.LuminanceSource.Height; - } - - } - /// 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. - /// - /// - /// The 2D array of bits for the image (true means black). - /// - public BitMatrix BlackMatrix - { - get - { - // 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.BlackMatrix; - } - return matrix; - } - - } - /// Whether this bitmap can be cropped. - /// - public bool CropSupported - { - get - { - return binarizer.LuminanceSource.CropSupported; - } - - } - /// Whether this bitmap supports counter-clockwise rotation. - /// - public bool RotateSupported - { - get - { - return binarizer.LuminanceSource.RotateSupported; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'binarizer '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Binarizer binarizer; - private BitMatrix matrix; - - public BinaryBitmap(Binarizer binarizer) - { - if (binarizer == null) - { - throw new System.ArgumentException("Binarizer must be non-null."); - } - this.binarizer = binarizer; - matrix = null; - } - - /// 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. - /// - /// - /// The row to fetch, 0 <= y < bitmap height. - /// - /// 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. - /// - /// The array of bits for this row (true means black). - /// - public BitArray getBlackRow(int y, BitArray row) - { - return binarizer.getBlackRow(y, row); - } - - /// 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. - /// - /// - /// The left coordinate, 0 <= left < getWidth(). - /// - /// The top coordinate, 0 <= top <= getHeight(). - /// - /// The width of the rectangle to crop. - /// - /// The height of the rectangle to crop. - /// - /// A cropped version of this object. - /// - public BinaryBitmap crop(int left, int top, int width, int height) - { - LuminanceSource newSource = binarizer.LuminanceSource.crop(left, top, width, height); - return new BinaryBitmap(binarizer.createBinarizer(newSource)); - } - - /// Returns a new object with rotated image data. Only callable if isRotateSupported() is true. - /// - /// - /// A rotated version of this object. - /// - public BinaryBitmap rotateCounterClockwise() - { - LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise(); - return new BinaryBitmap(binarizer.createBinarizer(newSource)); - } + return matrix; + } + } + + /// Whether this bitmap can be cropped. + public bool CropSupported + { + get + { + return binarizer.LuminanceSource.CropSupported; + } + } + + /// + /// 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. + /// + /// The left coordinate, 0 <= left < getWidth(). + /// The top coordinate, 0 <= top <= getHeight(). + /// The width of the rectangle to crop. + /// The height of the rectangle to crop. + /// A cropped version of this object. + public BinaryBitmap crop(int left, int top, int width, int height) + { + LuminanceSource newSource = binarizer.LuminanceSource.crop(left, top, width, height); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + + /// Whether this bitmap supports counter-clockwise rotation. + public bool RotateSupported + { + get + { + return binarizer.LuminanceSource.RotateSupported; + } + } + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + public BinaryBitmap rotateCounterClockwise() + { + LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise(); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + + /// + /// Returns a new object with rotated image data by 45 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + public BinaryBitmap rotateCounterClockwise45() + { + LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise45(); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + } + } \ No newline at end of file diff --git a/csharp/DecodeHintType.cs b/csharp/DecodeHintType.cs index ec55fac05..39b2eaec5 100755 --- a/csharp/DecodeHintType.cs +++ b/csharp/DecodeHintType.cs @@ -1,78 +1,77 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// Encapsulates a type of hint that a caller may pass to a barcode reader to help it + + /// + /// 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. /// - /// - /// Sean Owen - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - /// - /// - public sealed class DecodeHintType + /// @author Sean Owen + /// @author dswitkin@google.com (Daniel Switkin) + /// + public enum DecodeHintType { - - // No, we can't use an enum here. J2ME doesn't support it. - - /// Unspecified, application-specific hint. Maps to an unspecified {@link Object}. - //UPGRADE_NOTE: Final was removed from the declaration of 'OTHER '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType OTHER = new DecodeHintType(); - - /// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; - /// use {@link Boolean#TRUE}. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'PURE_BARCODE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType PURE_BARCODE = 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. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'POSSIBLE_FORMATS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType POSSIBLE_FORMATS = 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}. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'TRY_HARDER '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType TRY_HARDER = new DecodeHintType(); - - /// Allowed lengths of encoded data -- reject anything else. Maps to an int[]. - //UPGRADE_NOTE: Final was removed from the declaration of 'ALLOWED_LENGTHS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType ALLOWED_LENGTHS = new DecodeHintType(); - - /// Assume Code 39 codes employ a check digit. Maps to {@link Boolean}. - //UPGRADE_NOTE: Final was removed from the declaration of 'ASSUME_CODE_39_CHECK_DIGIT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType ASSUME_CODE_39_CHECK_DIGIT = new DecodeHintType(); - - /// The caller needs to be notified via callback when a possible {@link ResultPoint} - /// is found. Maps to a {@link ResultPointCallback}. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'NEED_RESULT_POINT_CALLBACK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly DecodeHintType NEED_RESULT_POINT_CALLBACK = new DecodeHintType(); - - private DecodeHintType() - { - } + + /// + /// Unspecified, application-specific hint. Maps to an unspecified . + /// + OTHER, + + /// + /// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; + /// use . + /// + PURE_BARCODE, + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a of s. + /// + POSSIBLE_FORMATS, + + /// + /// Spend more time to try to find a barcode; optimize for accuracy, not speed. + /// Doesn't matter what it maps to; use . + /// + TRY_HARDER, + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + CHARACTER_SET, + + /// + /// Allowed lengths of encoded data -- reject anything else. Maps to an int[]. + /// + ALLOWED_LENGTHS, + + /// + /// Assume Code 39 codes employ a check digit. Maps to . + /// + ASSUME_CODE_39_CHECK_DIGIT, + + /// + /// The caller needs to be notified via callback when a possible + /// is found. Maps to a . + /// + NEED_RESULT_POINT_CALLBACK, + } + } \ No newline at end of file diff --git a/csharp/EncodeHintType.cs b/csharp/EncodeHintType.cs index 9060bdc9e..74e4c49fc 100755 --- a/csharp/EncodeHintType.cs +++ b/csharp/EncodeHintType.cs @@ -1,43 +1,66 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// These are a set of hints that you may pass to Writers to specify their behavior. - /// - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EncodeHintType + /// + /// These are a set of hints that you may pass to Writers to specify their behavior. + /// + /// @author dswitkin@google.com (Daniel Switkin) + /// + public enum EncodeHintType { - - /// Specifies what degree of error correction to use, for example in QR Codes (type Integer). - //UPGRADE_NOTE: Final was removed from the declaration of 'ERROR_CORRECTION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly EncodeHintType ERROR_CORRECTION = new EncodeHintType(); - - /// Specifies what character encoding to use where applicable (type String) - //UPGRADE_NOTE: Final was removed from the declaration of 'CHARACTER_SET '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly EncodeHintType CHARACTER_SET = new EncodeHintType(); - - private EncodeHintType() - { - } + + /// + /// Specifies what degree of error correction to use, for example in QR Codes. + /// Type depends on the encoder. For example for QR codes it's type + /// . + /// + ERROR_CORRECTION, + + /// + /// Specifies what character encoding to use where applicable (type ) + /// + CHARACTER_SET, + + /// + /// Specifies margin, in pixels, to use when generating the barcode. The meaning can vary + /// by format; for example it controls margin before and after the barcode horizontally for + /// most 1D formats. (Type ). + /// + MARGIN, + + /// + /// Specifies whether to use compact mode for PDF417 (type ). + /// + PDF417_COMPACT, + + /// + /// Specifies what compaction mode to use for PDF417 (type + /// ). + /// + PDF417_COMPACTION, + + /// + /// Specifies the minimum and maximum number of rows and columns for PDF417 (type + /// ). + /// + PDF417_DIMENSIONS, + } + } \ No newline at end of file diff --git a/csharp/LuminanceSource.cs b/csharp/LuminanceSource.cs index e87b4280a..947cd8603 100755 --- a/csharp/LuminanceSource.cs +++ b/csharp/LuminanceSource.cs @@ -1,140 +1,171 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// The purpose of this class hierarchy is to abstract different bitmap implementations across + + /// + /// 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) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public abstract class LuminanceSource { - /// Fetches luminance data for the underlying bitmap. Values should be fetched using: - /// int luminance = array[y * width + x] & 0xff; - /// - /// - /// 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 abstract sbyte[] Matrix{get;} - /// The width of the bitmap. - /// - virtual public int Width + + private readonly int width; + private readonly int height; + + protected internal LuminanceSource(int width, int height) + { + 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 preferable 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. + /// + /// The row to fetch, 0 <= y < getHeight(). + /// 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. + /// An array containing the luminance data. + public abstract sbyte[] getRow(int y, sbyte[] row); + + /// + /// Fetches luminance data for the underlying bitmap. Values should be fetched using: + /// int luminance = array[y * width + x] & 0xff; + /// + /// 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 abstract sbyte[] Matrix {get;} + + /// The width of the bitmap. + public int Width + { + get + { + return width; + } + } + + /// The height of the bitmap. + public int Height + { + get + { + return height; + } + } + + /// Whether this subclass supports cropping. + public virtual bool CropSupported + { + get + { + 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. + /// + /// The left coordinate, 0 <= left < getWidth(). + /// The top coordinate, 0 <= top <= getHeight(). + /// The width of the rectangle to crop. + /// The height of the rectangle to crop. + /// A cropped version of this object. + public virtual LuminanceSource crop(int left, int top, int width, int height) + { + throw new System.NotSupportedException("This luminance source does not support cropping."); + } + + /// Whether this subclass supports counter-clockwise rotation. + public virtual bool RotateSupported + { + get + { + return false; + } + } + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + public virtual LuminanceSource rotateCounterClockwise() + { + throw new System.NotSupportedException("This luminance source does not support rotation by 90 degrees."); + } + + /// + /// Returns a new object with rotated image data by 45 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + public virtual LuminanceSource rotateCounterClockwise45() + { + throw new System.NotSupportedException("This luminance source does not support rotation by 45 degrees."); + } + + public override string ToString() + { + sbyte[] row = new sbyte[width]; + StringBuilder result = new StringBuilder(height * (width + 1)); + for (int y = 0; y < height; y++) { - get + row = getRow(y, row); + for (int x = 0; x < width; x++) + { + int luminance = row[x] & 0xFF; + char c; + if (luminance < 0x40) { - return width; + c = '#'; } - - } - /// The height of the bitmap. - /// - virtual public int Height - { - get + else if (luminance < 0x80) { - return height; + c = '+'; } - - } - /// Whether this subclass supports cropping. - /// - virtual public bool CropSupported - { - get + else if (luminance < 0xC0) { - return false; + c = '.'; } - - } - /// Whether this subclass supports counter-clockwise rotation. - /// - virtual public bool RotateSupported - { - get + else { - return false; + c = ' '; } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'width '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int width; - //UPGRADE_NOTE: Final was removed from the declaration of 'height '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int height; - - protected internal LuminanceSource(int width, int height) - { - 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 preferable 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. - /// - /// - /// The row to fetch, 0 <= y < getHeight(). - /// - /// 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. - /// - /// An array containing the luminance data. - /// - public abstract sbyte[] getRow(int y, sbyte[] row); - - /// 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. - /// - /// - /// The left coordinate, 0 <= left < getWidth(). - /// - /// The top coordinate, 0 <= top <= getHeight(). - /// - /// The width of the rectangle to crop. - /// - /// The height of the rectangle to crop. - /// - /// A cropped version of this object. - /// - public virtual LuminanceSource crop(int left, int top, int width, int height) - { - throw new System.SystemException("This luminance source does not support cropping."); - } - - /// Returns a new object with rotated image data. Only callable if isRotateSupported() is true. - /// - /// - /// A rotated version of this object. - /// - public virtual LuminanceSource rotateCounterClockwise() - { - throw new System.SystemException("This luminance source does not support rotation."); + result.Append(c); + } + result.Append('\n'); } + return result.ToString(); + } + } + } \ No newline at end of file diff --git a/csharp/MultiFormatReader.cs b/csharp/MultiFormatReader.cs index 958fb7467..3f30c7ef8 100755 --- a/csharp/MultiFormatReader.cs +++ b/csharp/MultiFormatReader.cs @@ -1,175 +1,207 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using MultiFormatOneDReader = com.google.zxing.oned.MultiFormatOneDReader; -using PDF417Reader = com.google.zxing.pdf417.PDF417Reader; -using QRCodeReader = com.google.zxing.qrcode.QRCodeReader; -using DataMatrixReader = com.google.zxing.datamatrix.DataMatrixReader; + * 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. + */ + namespace com.google.zxing { - - /// MultiFormatReader is a convenience class and the main entry point into the library for most uses. + + using AztecReader = com.google.zxing.aztec.AztecReader; + using DataMatrixReader = com.google.zxing.datamatrix.DataMatrixReader; + using MaxiCodeReader = com.google.zxing.maxicode.MaxiCodeReader; + using MultiFormatOneDReader = com.google.zxing.oned.MultiFormatOneDReader; + using PDF417Reader = com.google.zxing.pdf417.PDF417Reader; + using QRCodeReader = com.google.zxing.qrcode.QRCodeReader; + + + /// + /// 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) /// - /// Sean Owen - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class MultiFormatReader : Reader { - /// 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. - /// - /// - /// The set of hints to use for subsequent calls to decode(image) - /// - public System.Collections.Hashtable Hints + +//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET: +//ORIGINAL LINE: private java.util.Map hints; + private IDictionary hints; + private Reader[] readers; + + /// + /// This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it + /// passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly. + /// Use setHints() followed by decodeWithState() for continuous scan applications. + /// + /// The pixel data to decode + /// The contents of the image + /// Any errors which occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public Result decode(BinaryBitmap image) throws NotFoundException + public Result decode(BinaryBitmap image) + { + Hints = null; + return decodeInternal(image); + } + + /// + /// Decode an image using the hints provided. Does not honor existing state. + /// + /// The pixel data to decode + /// The hints to use, clearing the previous state. + /// The contents of the image + /// Any errors which occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public Result decode(BinaryBitmap image, java.util.Map hints) throws NotFoundException + public Result decode(BinaryBitmap image, IDictionary hints) + { + Hints = hints; + return decodeInternal(image); + } + + /// + /// Decode an image using the state set up by calling setHints() previously. Continuous scan + /// clients will get a large speed increase by using this instead of decode(). + /// + /// The pixel data to decode + /// The contents of the image + /// Any errors which occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public Result decodeWithState(BinaryBitmap image) throws NotFoundException + public Result decodeWithState(BinaryBitmap image) + { + // Make sure to set up the default state so we don't crash + if (readers == null) { - set + Hints = 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. + /// + /// The set of hints to use for subsequent calls to decode(image) + public IDictionary Hints + { + set + { + this.hints = value; + + bool tryHarder = value != null && value.ContainsKey(DecodeHintType.TRY_HARDER); + + //ICollection formats = value == null ? null : (ICollection) value[DecodeHintType.POSSIBLE_FORMATS]; + ICollection formats = null; + if (value != null && value.ContainsKey(DecodeHintType.POSSIBLE_FORMATS)) + { + formats = (ICollection)value[DecodeHintType.POSSIBLE_FORMATS]; + } + List readers = new List(); + if (formats != null) { - this.hints = value; - - bool tryHarder = value != null && value.ContainsKey(DecodeHintType.TRY_HARDER); - System.Collections.ArrayList formats = value == null?null:(System.Collections.ArrayList) value[DecodeHintType.POSSIBLE_FORMATS]; - readers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - if (formats != null) - { - bool addOneDReader = formats.Contains(BarcodeFormat.UPC_A) || formats.Contains(BarcodeFormat.UPC_E) || formats.Contains(BarcodeFormat.EAN_13) || formats.Contains(BarcodeFormat.EAN_8) || formats.Contains(BarcodeFormat.CODE_39) || formats.Contains(BarcodeFormat.CODE_128) || formats.Contains(BarcodeFormat.ITF); - // Put 1D readers upfront in "normal" mode - if (addOneDReader && !tryHarder) - { - readers.Add(new MultiFormatOneDReader(value)); - } - if (formats.Contains(BarcodeFormat.QR_CODE)) - { - readers.Add(new QRCodeReader()); - } - if (formats.Contains(BarcodeFormat.DATAMATRIX)) - { - readers.Add(new DataMatrixReader()); - } - if (formats.Contains(BarcodeFormat.PDF417)) - { - readers.Add(new PDF417Reader()); - } - // At end in "try harder" mode - if (addOneDReader && tryHarder) - { - readers.Add(new MultiFormatOneDReader(value)); - } - } - if ((readers.Count == 0)) - { - if (!tryHarder) - { - readers.Add(new MultiFormatOneDReader(value)); - } - readers.Add(new QRCodeReader()); - - // TODO re-enable once Data Matrix is ready - // readers.addElement(new DataMatrixReader()); - - // TODO: Enable once PDF417 has passed QA - //readers.addElement(new PDF417Reader()); - - if (tryHarder) - { - readers.Add(new MultiFormatOneDReader(value)); - } - } + bool addOneDReader = formats.Contains(BarcodeFormat.UPC_A) || formats.Contains(BarcodeFormat.UPC_E) || formats.Contains(BarcodeFormat.EAN_13) || formats.Contains(BarcodeFormat.EAN_8) || formats.Contains(BarcodeFormat.CODABAR) || formats.Contains(BarcodeFormat.CODE_39) || formats.Contains(BarcodeFormat.CODE_93) || formats.Contains(BarcodeFormat.CODE_128) || formats.Contains(BarcodeFormat.ITF) || formats.Contains(BarcodeFormat.RSS_14) || formats.Contains(BarcodeFormat.RSS_EXPANDED); + // Put 1D readers upfront in "normal" mode + if (addOneDReader && !tryHarder) + { + readers.Add(new MultiFormatOneDReader(value)); + } + if (formats.Contains(BarcodeFormat.QR_CODE)) + { + readers.Add(new QRCodeReader()); + } + if (formats.Contains(BarcodeFormat.DATA_MATRIX)) + { + readers.Add(new DataMatrixReader()); + } + if (formats.Contains(BarcodeFormat.AZTEC)) + { + readers.Add(new AztecReader()); + } + if (formats.Contains(BarcodeFormat.PDF_417)) + { + readers.Add(new PDF417Reader()); + } + if (formats.Contains(BarcodeFormat.MAXICODE)) + { + readers.Add(new MaxiCodeReader()); + } + // At end in "try harder" mode + if (addOneDReader && tryHarder) + { + readers.Add(new MultiFormatOneDReader(value)); + } } - - } - - private System.Collections.Hashtable hints; - private System.Collections.ArrayList readers; - - /// This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it - /// passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly. - /// Use setHints() followed by decodeWithState() for continuous scan applications. - /// - /// - /// The pixel data to decode - /// - /// The contents of the image - /// - /// ReaderException Any errors which occurred - public Result decode(BinaryBitmap image) - { - Hints = null; - return decodeInternal(image); - } - - /// Decode an image using the hints provided. Does not honor existing state. - /// - /// - /// The pixel data to decode - /// - /// The hints to use, clearing the previous state. - /// - /// The contents of the image - /// - /// ReaderException Any errors which occurred - public Result decode(BinaryBitmap image, System.Collections.Hashtable hints) - { - Hints = hints; - return decodeInternal(image); - } - - /// Decode an image using the state set up by calling setHints() previously. Continuous scan - /// clients will get a large speed increase by using this instead of decode(). - /// - /// - /// The pixel data to decode - /// - /// The contents of the image - /// - /// ReaderException Any errors which occurred - public Result decodeWithState(BinaryBitmap image) - { - // Make sure to set up the default state so we don't crash - if (readers == null) + if (readers.Count == 0) { - Hints = null; + if (!tryHarder) + { + readers.Add(new MultiFormatOneDReader(value)); + } + + readers.Add(new QRCodeReader()); + readers.Add(new DataMatrixReader()); + readers.Add(new AztecReader()); + readers.Add(new PDF417Reader()); + readers.Add(new MaxiCodeReader()); + + if (tryHarder) + { + readers.Add(new MultiFormatOneDReader(value)); + } } - return decodeInternal(image); - } - - private Result decodeInternal(BinaryBitmap image) + this.readers = readers.ToArray(/*new Reader[readers.Count]*/); + } + } + + public void reset() + { + if (readers != null) { - int size = readers.Count; - for (int i = 0; i < size; i++) - { - Reader reader = (Reader) readers[i]; - try - { - return reader.decode(image, hints); - } - catch (ReaderException) - { - // continue - } - } - - throw ReaderException.Instance; + foreach (Reader reader in readers) + { + reader.reset(); + } } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private Result decodeInternal(BinaryBitmap image) throws NotFoundException + private Result decodeInternal(BinaryBitmap image) + { + if (readers != null) + { + foreach (Reader reader in readers) + { + try + { + return reader.decode(image, hints); + } + catch (ReaderException re) + { + // continue + } + } + } + throw NotFoundException.NotFoundInstance; + } + } -} + +} \ No newline at end of file diff --git a/csharp/MultiFormatWriter.cs b/csharp/MultiFormatWriter.cs index 160c45375..2e6e217ef 100755 --- a/csharp/MultiFormatWriter.cs +++ b/csharp/MultiFormatWriter.cs @@ -1,63 +1,93 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -using EAN13Writer = com.google.zxing.oned.EAN13Writer; -using EAN8Writer = com.google.zxing.oned.EAN8Writer; -using QRCodeWriter = com.google.zxing.qrcode.QRCodeWriter; + * 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. + */ + namespace com.google.zxing { - - /// This is a factory class which finds the appropriate Writer subclass for the BarcodeFormat + + using BitMatrix = com.google.zxing.common.BitMatrix; + using CodaBarWriter = com.google.zxing.oned.CodaBarWriter; + using Code128Writer = com.google.zxing.oned.Code128Writer; + using Code39Writer = com.google.zxing.oned.Code39Writer; + using EAN13Writer = com.google.zxing.oned.EAN13Writer; + using EAN8Writer = com.google.zxing.oned.EAN8Writer; + using ITFWriter = com.google.zxing.oned.ITFWriter; + using UPCAWriter = com.google.zxing.oned.UPCAWriter; + using PDF417Writer = com.google.zxing.pdf417.encoder.PDF417Writer; + using QRCodeWriter = com.google.zxing.qrcode.QRCodeWriter; + + + /// + /// This is a factory class which finds the appropriate Writer subclass for the BarcodeFormat /// requested and encodes the barcode with the supplied contents. /// + /// @author dswitkin@google.com (Daniel Switkin) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class MultiFormatWriter : Writer { - - public ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height) + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, BarcodeFormat format, int width, int height) throws WriterException + public BitMatrix encode(string contents, BarcodeFormat format, int width, int height) + { + return encode(contents, format, width, height, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, BarcodeFormat format, int width, int height, java.util.Map hints) throws WriterException + public BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints) + { + + Writer writer; + switch (format) { - - return encode(contents, format, width, height, null); - } - - public ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints) - { - - 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 System.ArgumentException("No encoder available for format " + format); - } + case com.google.zxing.BarcodeFormat.EAN_8: + writer = new EAN8Writer(); + break; + case com.google.zxing.BarcodeFormat.EAN_13: + writer = new EAN13Writer(); + break; + case com.google.zxing.BarcodeFormat.UPC_A: + writer = new UPCAWriter(); + break; + case com.google.zxing.BarcodeFormat.QR_CODE: + writer = new QRCodeWriter(); + break; + case com.google.zxing.BarcodeFormat.CODE_39: + writer = new Code39Writer(); + break; + case com.google.zxing.BarcodeFormat.CODE_128: + writer = new Code128Writer(); + break; + case com.google.zxing.BarcodeFormat.ITF: + writer = new ITFWriter(); + break; + case com.google.zxing.BarcodeFormat.PDF_417: + writer = new PDF417Writer(); + break; + case com.google.zxing.BarcodeFormat.CODABAR: + writer = new CodaBarWriter(); + break; + default: + throw new System.ArgumentException("No encoder available for format " + format); } + return writer.encode(contents, format, width, height, hints); + } + } + } \ No newline at end of file diff --git a/csharp/RGBLuminanceSource.cs b/csharp/RGBLuminanceSource.cs index 5e65a4b7b..61ade47f6 100755 --- a/csharp/RGBLuminanceSource.cs +++ b/csharp/RGBLuminanceSource.cs @@ -1,163 +1,177 @@ -using com.google.zxing; -using com.google.zxing.common; -using System.Drawing.Imaging; -using System.Drawing; using System; +using System.Drawing; -public class RGBLuminanceSource : LuminanceSource +/* + * 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. + */ + +namespace com.google.zxing { - private sbyte[] luminances; - private bool isRotated = false; - private bool __isRegionSelect = false; - private Rectangle __Region; + /// + /// This class is used to help decode images from files which arrive as RGB data from + /// an ARGB pixel array. It does not support rotation. + /// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Betaminos + /// + public sealed class RGBLuminanceSource : LuminanceSource + { - override public int Height - { - get - { - if (!isRotated) - return __height; - else - return __width; - } + private readonly sbyte[] luminances; + private readonly int dataWidth; + private readonly int dataHeight; + private readonly int left; + private readonly int top; - } - override public int Width - { - get - { - if (!isRotated) - return __width; - else - return __height; - } + public RGBLuminanceSource(int width, int height, int[] pixels) : base(width, height) + { - } - private int __height; - private int __width; + dataWidth = width; + dataHeight = height; + left = 0; + top = 0; - public RGBLuminanceSource(byte[] d, int W, int H) - : base(W, H) - { - __width = W; - __height = H; - int width = W; - int height = H; - // In order to measure pure decoding speed, we convert the entire image to a greyscale array - // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. - luminances = new sbyte[width * height]; - for (int y = 0; y < height; y++) - { - int offset = y * width; - for (int x = 0; x < width; x++) - { - int r = d[offset * 3 + x * 3]; - int g = d[offset * 3 + x * 3 + 1]; - int b = d[offset * 3 + x * 3 + 2]; - if (r == g && g == b) - { - // Image is already greyscale, so pick any channel. - luminances[offset + x] = (sbyte)r; - } - else - { - // Calculate luminance cheaply, favoring green. - luminances[offset + x] = (sbyte)((r + g + g + b) >> 2); - } - } - } - } - public RGBLuminanceSource(byte[] d, int W, int H,bool Is8Bit) - : base(W, H) - { - __width = W; - __height = H; - luminances = new sbyte[W * H]; - Buffer.BlockCopy(d,0, luminances,0, W * H); - } + // In order to measure pure decoding speed, we convert the entire image to a greyscale array + // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + luminances = new sbyte[width * height]; + for (int y = 0; y < height; y++) + { + int offset = y * width; + for (int x = 0; x < width; x++) + { + int pixel = pixels[offset + x]; + int r = (pixel >> 16) & 0xff; + int g = (pixel >> 8) & 0xff; + int b = pixel & 0xff; + if (r == g && g == b) + { + // Image is already greyscale, so pick any channel. + luminances[offset + x] = (sbyte) r; + } + else + { + // Calculate luminance cheaply, favoring green. + luminances[offset + x] = (sbyte)((r + g + g + b) >> 2); + } + } + } + } + + private RGBLuminanceSource(sbyte[] pixels, int dataWidth, int dataHeight, int left, int top, int width, int height) : base(width, height) + { + if (left + width > dataWidth || top + height > dataHeight) + { + throw new System.ArgumentException("Crop rectangle does not fit within image data."); + } + this.luminances = pixels; + this.dataWidth = dataWidth; + this.dataHeight = dataHeight; + this.left = left; + this.top = top; + } + + public RGBLuminanceSource(Bitmap d, int W, int H) + : base(W, H) + { + int width = dataWidth = W; + int height = dataHeight = H; + // In order to measure pure decoding speed, we convert the entire image to a greyscale array + // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + luminances = new sbyte[width * height]; + //if (format == PixelFormat.Format8bppIndexed) + { + Color c; + for (int y = 0; y < height; y++) + { + int offset = y * width; + for (int x = 0; x < width; x++) + { + c = d.GetPixel(x, y); + luminances[offset + x] = (sbyte)(((int)c.R) << 16 | ((int)c.G) << 8 | ((int)c.B)); + } + } + } + } + + public override sbyte[] getRow(int y, sbyte[] row) + { + if (y < 0 || y >= Height) + { + throw new System.ArgumentException("Requested row is outside the image: " + y); + } + int width = Width; + if (row == null || row.Length < width) + { + row = new sbyte[width]; + } + int offset = (y + top) * dataWidth + left; + Array.Copy(luminances, offset, row, 0, width); + return row; + } + + public override sbyte[] Matrix + { + get + { + int width = Width; + int height = Height; - public RGBLuminanceSource(byte[] d, int W, int H, bool Is8Bit,Rectangle Region) - : base(W, H) - { - __width = Region.Width; - __height = Region.Height; - __Region = Region; - __isRegionSelect = true; - //luminances = Red.Imaging.Filters.CropArea(d, W, H, Region); - } + // If the caller asks for the entire underlying image, save the copy and give them the + // original data. The docs specifically warn that result.length must be ignored. + if (width == dataWidth && height == dataHeight) + { + return luminances; + } + + int area = width * height; + sbyte[] matrix = new sbyte[area]; + int inputOffset = top * dataWidth + left; + + // If the width matches the full width of the underlying data, perform a single copy. + if (width == dataWidth) + { + Array.Copy(luminances, inputOffset, matrix, 0, area); + return matrix; + } + + // Otherwise copy one cropped row at a time. + sbyte[] rgb = luminances; + for (int y = 0; y < height; y++) + { + int outputOffset = y * width; + Array.Copy(rgb, inputOffset, matrix, outputOffset, width); + inputOffset += dataWidth; + } + return matrix; + } + } + public override bool CropSupported + { + get + { + return true; + } + } - public RGBLuminanceSource(Bitmap d, int W, int H) - : base(W, H) - { - int width = __width = W; - int height = __height = H; - // In order to measure pure decoding speed, we convert the entire image to a greyscale array - // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. - luminances = new sbyte[width * height]; - //if (format == PixelFormat.Format8bppIndexed) - { - Color c; - for (int y = 0; y < height; y++) - { - int offset = y * width; - for (int x = 0; x < width; x++) - { - c = d.GetPixel(x, y); - luminances[offset + x] = (sbyte)(((int)c.R) << 16 | ((int)c.G) << 8 | ((int)c.B)); - } - } - } - } - override public sbyte[] getRow(int y, sbyte[] row) - { - if (isRotated == false) - { - int width = Width; - if (row == null || row.Length < width) - { - row = new sbyte[width]; - } - for (int i = 0; i < width; i++) - row[i] = luminances[y * width + i]; - //System.arraycopy(luminances, y * width, row, 0, width); - return row; - } - else - { - int width = __width; - int height = __height; - if (row == null || row.Length < height) - { - row = new sbyte[height]; - } - for (int i = 0; i < height; i++) - row[i] = luminances[i * width + y]; - //System.arraycopy(luminances, y * width, row, 0, width); - return row; - } - } - public override sbyte[] Matrix - { - get { return luminances; } - } + public override LuminanceSource crop(int left, int top, int width, int height) + { + return new RGBLuminanceSource(luminances, dataWidth, dataHeight, this.left + left, this.top + top, width, height); + } - public override LuminanceSource crop(int left, int top, int width, int height) - { - return base.crop(left, top, width, height); - } - public override LuminanceSource rotateCounterClockwise() - { - isRotated = true; - return this; - } - public override bool RotateSupported - { - get - { - return true; - } + } - } -} +} \ No newline at end of file diff --git a/csharp/Reader.cs b/csharp/Reader.cs index c72e70a70..870429b60 100755 --- a/csharp/Reader.cs +++ b/csharp/Reader.cs @@ -1,65 +1,70 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; + * 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. + */ + namespace 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 + + + /// + /// Implementations of this interface can decode an image of a barcode in some format into + /// the String it encodes. For example, 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 + /// See , 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) /// - /// Sean Owen - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public interface Reader { - - /// Locates and decodes a barcode in some format within an image. - /// - /// - /// image of barcode to decode - /// - /// String which the barcode encodes - /// - /// ReaderException if the barcode cannot be located or decoded for any reason - Result decode(BinaryBitmap image); - - /// 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. - /// - /// - /// image of barcode to decode - /// - /// passed as a {@link java.util.Hashtable} from {@link com.google.zxing.DecodeHintType} - /// to arbitrary data. The - /// meaning of the data depends upon the hint type. The implementation may or may not do - /// anything with these hints. - /// - /// String which the barcode encodes - /// - /// ReaderException if the barcode cannot be located or decoded for any reason - Result decode(BinaryBitmap image, System.Collections.Hashtable hints); + + /// + /// Locates and decodes a barcode in some format within an image. + /// + /// image of barcode to decode + /// String which the barcode encodes + /// if the barcode cannot be located or decoded for any reason +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException; + Result decode(BinaryBitmap image); + + /// + /// 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. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// String which the barcode encodes + /// if the barcode cannot be located or decoded for any reason +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: Result decode(BinaryBitmap image, java.util.Map hints) throws NotFoundException, ChecksumException, FormatException; + Result decode(BinaryBitmap image, IDictionary hints); + + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + void reset(); + } } \ No newline at end of file diff --git a/csharp/ReaderException.cs b/csharp/ReaderException.cs index 1db04364b..a0b50b00d 100755 --- a/csharp/ReaderException.cs +++ b/csharp/ReaderException.cs @@ -1,113 +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. -*/ using System; + +/* + * 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. + */ + namespace com.google.zxing { - - /// The general exception class throw when something goes wrong during decoding of a barcode. + + /// + /// 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 /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - - [Serializable] - public sealed class ReaderException:System.Exception + public abstract class ReaderException : Exception { - public static ReaderException Instance - { - get - { - // Exception e = new Exception(); - // // Take the stack frame before this one. - // StackTraceElement stack = e.getStackTrace()[1]; - // String key = stack.getClassName() + "." + stack.getMethodName() + "(), line " + - // stack.getLineNumber(); - // if (throwers.containsKey(key)) { - // Integer value = throwers.get(key); - // value++; - // throwers.put(key, value); - // } else { - // throwers.put(key, 1); - // } - // exceptionCount++; - - return instance; - } - - } - - // 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. - - //UPGRADE_NOTE: Final was removed from the declaration of 'instance '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly ReaderException instance = new ReaderException(); - - // EXCEPTION TRACKING SUPPORT - // Identifies who is throwing exceptions and how often. To use: - // - // 1. Uncomment these lines and the code below which uses them. - // 2. Uncomment the two corresponding lines in j2se/CommandLineRunner.decode() - // 3. Change core to build as Java 1.5 temporarily - // private static int exceptionCount = 0; - // private static Map throwers = new HashMap(32); - - private ReaderException() - { - // do nothing - } - - // public static int getExceptionCountAndReset() { - // int temp = exceptionCount; - // exceptionCount = 0; - // return temp; - // } - // - // public static String getThrowersAndReset() { - // StringBuilder builder = new StringBuilder(1024); - // Object[] keys = throwers.keySet().toArray(); - // for (int x = 0; x < keys.length; x++) { - // String key = (String) keys[x]; - // Integer value = throwers.get(key); - // builder.append(key); - // builder.append(": "); - // builder.append(value); - // builder.append("\n"); - // } - // throwers.clear(); - // return builder.toString(); - // } - - // 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. - //UPGRADE_NOTE: Exception 'java.lang.Throwable' was converted to 'System.Exception' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'" - //UPGRADE_NOTE: The equivalent of method 'java.lang.Throwable.fillInStackTrace' is not an override method. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1143'" - public System.Exception fillInStackTrace() - { - return null; - } + + internal ReaderException() + { + // do nothing + } + + // 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 Exception fillInStackTrace() + { + return null; + } + } + } \ No newline at end of file diff --git a/csharp/Result.cs b/csharp/Result.cs index b09d9ac0f..90e877938 100755 --- a/csharp/Result.cs +++ b/csharp/Result.cs @@ -1,129 +1,174 @@ -/* -* 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. -*/ using System; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing { - - ///

Encapsulates the result of decoding a barcode within an image.

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class Result - { - /// raw text encoded by the barcode, if applicable, otherwise null - /// - public System.String Text - { - get - { - return text; - } - - } - /// raw bytes encoded by the barcode, if applicable, otherwise null - /// - public sbyte[] RawBytes - { - get - { - return rawBytes; - } - - } - /// 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 ResultPoint[] ResultPoints - { - get - { - return resultPoints; - } - - } - /// {@link BarcodeFormat} representing the format of the barcode that was decoded - /// - public BarcodeFormat BarcodeFormat - { - get - { - return format; - } - - } - /// {@link Hashtable} mapping {@link ResultMetadataType} keys to values. May be - /// null. This contains optional metadata about what was detected about the barcode, - /// like orientation. - /// - public System.Collections.Hashtable ResultMetadata - { - get - { - return resultMetadata; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'text '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String text; - //UPGRADE_NOTE: Final was removed from the declaration of 'rawBytes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte[] rawBytes; - //UPGRADE_NOTE: Final was removed from the declaration of 'resultPoints '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPoint[] resultPoints; - //UPGRADE_NOTE: Final was removed from the declaration of 'format '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BarcodeFormat format; - private System.Collections.Hashtable resultMetadata; - - public Result(System.String text, sbyte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format) - { - if (text == null && rawBytes == null) - { - throw new System.ArgumentException("Text and bytes are null"); - } - this.text = text; - this.rawBytes = rawBytes; - this.resultPoints = resultPoints; - this.format = format; - this.resultMetadata = null; - } - - public void putMetadata(ResultMetadataType type, System.Object value_Renamed) - { - if (resultMetadata == null) - { - resultMetadata = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(3)); - } - resultMetadata[type] = value_Renamed; - } - - public override System.String ToString() - { - if (text == null) - { - return "[" + rawBytes.Length + " bytes]"; - } - else - { - return text; - } - } - } + + /// + ///

Encapsulates the result of decoding a barcode within an image.

+ /// + /// @author Sean Owen + ///
+ public sealed class Result + { + + private readonly string text; + private readonly sbyte[] rawBytes; + private ResultPoint[] resultPoints; + private readonly BarcodeFormat format; + private IDictionary resultMetadata; + private readonly long timestamp; + + //public Result(string text, sbyte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format) + // : this(text, rawBytes, resultPoints, format, System.currentTimeMillis()) + + public Result(string text, sbyte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format) + : this(text, rawBytes, resultPoints, format, CurrentTimeMillis()) + { + } + + public Result(string text, sbyte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format, long timestamp) + { + this.text = text; + this.rawBytes = rawBytes; + this.resultPoints = resultPoints; + this.format = format; + this.resultMetadata = null; + this.timestamp = timestamp; + } + + /// raw text encoded by the barcode + public string Text + { + get + { + return text; + } + } + + /// raw bytes encoded by the barcode, if applicable, otherwise {@code null} + public sbyte[] RawBytes + { + get + { + return rawBytes; + } + } + + /// 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 ResultPoint[] ResultPoints + { + get + { + return resultPoints; + } + } + + /// representing the format of the barcode that was decoded + public BarcodeFormat BarcodeFormat + { + get + { + return format; + } + } + + /// mapping keys to values. May be + /// {@code null}. This contains optional metadata about what was detected about the barcode, + /// like orientation. + public IDictionary ResultMetadata + { + get + { + return resultMetadata; + } + } + + public void putMetadata(ResultMetadataType type, object value) + { + if (resultMetadata == null) + { + //resultMetadata = new EnumMap(typeof(ResultMetadataType)); + resultMetadata = new Dictionary(); + } + resultMetadata[type] = value; + } + + public void putAllMetadata(IDictionary metadata) + { + if (metadata != null) + { + if (resultMetadata == null) + { + resultMetadata = metadata; + } + else + { + //JAVA TO C# CONVERTER TODO TASK: There is no .NET Dictionary equivalent to the Java 'putAll' method: + //resultMetadata.putAll(metadata); + foreach (KeyValuePair kvp in metadata) + { + resultMetadata.Add(kvp); + } + } + } + } + + public void addResultPoints(ResultPoint[] newPoints) + { + ResultPoint[] oldPoints = resultPoints; + if (oldPoints == null) + { + resultPoints = newPoints; + } + else if (newPoints != null && newPoints.Length > 0) + { + ResultPoint[] allPoints = new ResultPoint[oldPoints.Length + newPoints.Length]; + Array.Copy(oldPoints, 0, allPoints, 0, oldPoints.Length); + Array.Copy(newPoints, 0, allPoints, oldPoints.Length, newPoints.Length); + resultPoints = allPoints; + } + } + + public long Timestamp + { + get + { + return timestamp; + } + } + + public override string ToString() + { + return text; + } + + private static readonly DateTime Jan1st1970 = new DateTime + (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static long CurrentTimeMillis() + { + return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; + } + } + } \ No newline at end of file diff --git a/csharp/ResultMetadataType.cs b/csharp/ResultMetadataType.cs index d57ae2778..a825966f9 100755 --- a/csharp/ResultMetadataType.cs +++ b/csharp/ResultMetadataType.cs @@ -1,68 +1,84 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// Represents some type of metadata about the result of the decoding that the decoder + + /// + /// Represents some type of metadata about the result of the decoding that the decoder /// wishes to communicate back to the caller. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - - public sealed class ResultMetadataType + public enum ResultMetadataType { - - // No, we can't use an enum here. J2ME doesn't support it. - - /// Unspecified, application-specific metadata. Maps to an unspecified {@link Object}. - //UPGRADE_NOTE: Final was removed from the declaration of 'OTHER '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ResultMetadataType OTHER = 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). - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'ORIENTATION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ResultMetadataType ORIENTATION = new ResultMetadataType(); - - ///

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.

- /// - ///

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.

- ///
- //UPGRADE_NOTE: Final was removed from the declaration of 'BYTE_SEGMENTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ResultMetadataType BYTE_SEGMENTS = new ResultMetadataType(); - - /// Error correction level used, if applicable. The value type depends on the - /// format, but is typically a String. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'ERROR_CORRECTION_LEVEL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ResultMetadataType ERROR_CORRECTION_LEVEL = new ResultMetadataType(); - - private ResultMetadataType() - { - } + + /// + /// Unspecified, application-specific metadata. Maps to an unspecified . + /// + OTHER, + + /// + /// 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 whose + /// value is in the range [0,360). + /// + ORIENTATION, + + /// + ///

2D barcode formats typically encode text, but allow for a sort of 'byte mode' + /// which is sometimes used to encode binary data. While makes available + /// the complete raw bytes in the barcode for these formats, it does not offer the bytes + /// from the byte segments alone.

+ /// + ///

This maps to a of byte arrays corresponding to the + /// raw bytes in the byte segments in the barcode, in order.

+ ///
+ BYTE_SEGMENTS, + + /// + /// Error correction level used, if applicable. The value type depends on the + /// format, but is typically a String. + /// + ERROR_CORRECTION_LEVEL, + + /// + /// For some periodicals, indicates the issue number as an . + /// + ISSUE_NUMBER, + + /// + /// For some products, indicates the suggested retail price in the barcode as a + /// formatted . + /// + SUGGESTED_PRICE, + + /// + /// For some products, the possible country of manufacture as a denoting the + /// ISO country code. Some map to multiple possible countries, like "US/CA". + /// + POSSIBLE_COUNTRY, + + /// + /// For some products, the extension text + /// + UPC_EAN_EXTENSION, + } + } \ No newline at end of file diff --git a/csharp/ResultPoint.cs b/csharp/ResultPoint.cs index def8e2f7a..b9feaefe4 100755 --- a/csharp/ResultPoint.cs +++ b/csharp/ResultPoint.cs @@ -1,157 +1,160 @@ -/* -* 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. -*/ using System; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing { - - ///

Encapsulates a point of interest in an image containing a barcode. Typically, this + + using MathUtils = com.google.zxing.common.detector.MathUtils; + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public class ResultPoint { - virtual public float X - { - get - { - return x; - } - - } - virtual public float Y - { - get - { - return y; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'x '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float x; - //UPGRADE_NOTE: Final was removed from the declaration of 'y '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float y; - - public ResultPoint(float x, float y) - { - this.x = x; - this.y = y; - } - - public override bool Equals(System.Object other) - { - if (other is ResultPoint) - { - ResultPoint otherPoint = (ResultPoint) other; - return x == otherPoint.x && y == otherPoint.y; - } - return false; - } - - public override int GetHashCode() - { - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Commented function body - //return 31 * Float.floatToIntBits(x) + Float.floatToIntBits(y); - return 0; - } - - public override System.String ToString() + private readonly float x; + private readonly float y; + + public ResultPoint(float x, float y) + { + this.x = x; + this.y = y; + } + + public float X + { + get + { + return x; + } + } + + public float Y + { + get + { + return y; + } + } + + public override bool Equals(object other) + { + if (other is ResultPoint) { - System.Text.StringBuilder result = new System.Text.StringBuilder(25); - result.Append('('); - result.Append(x); - result.Append(','); - result.Append(y); - result.Append(')'); - return result.ToString(); + ResultPoint otherPoint = (ResultPoint) other; + return x == otherPoint.x && y == otherPoint.y; } - - ///

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 void orderBestPatterns(ResultPoint[] patterns) + return false; + } + + public override int GetHashCode() + { + //return 31 * float.floatToIntBits(x) + float.floatToIntBits(y); + + int xbits = BitConverter.ToInt32(BitConverter.GetBytes(x), 0); + int ybits = BitConverter.ToInt32(BitConverter.GetBytes(y), 0); + return 31 * xbits + ybits; + } + + public override string ToString() + { + StringBuilder result = new StringBuilder(25); + result.Append('('); + result.Append(x); + result.Append(','); + result.Append(y); + result.Append(')'); + return result.ToString(); + } + + /// + ///

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 void orderBestPatterns(ResultPoint[] patterns) + { + + // Find distances between pattern centers + float zeroOneDistance = distance(patterns[0], patterns[1]); + float oneTwoDistance = distance(patterns[1], patterns[2]); + float zeroTwoDistance = distance(patterns[0], patterns[2]); + + ResultPoint pointA; + ResultPoint pointB; + ResultPoint pointC; + // Assume one closest to other two is B; A and C will just be guesses at first + if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { - - // Find distances between pattern centers - float zeroOneDistance = distance(patterns[0], patterns[1]); - float oneTwoDistance = distance(patterns[1], patterns[2]); - float zeroTwoDistance = distance(patterns[0], patterns[2]); - - ResultPoint pointA, pointB, pointC; - // 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.0f) - { - ResultPoint temp = pointA; - pointA = pointC; - pointC = temp; - } - - patterns[0] = pointA; - patterns[1] = pointB; - patterns[2] = pointC; + pointB = patterns[0]; + pointA = patterns[1]; + pointC = patterns[2]; } - - - /// distance between two points - /// - public static float distance(ResultPoint pattern1, ResultPoint pattern2) + else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { - float xDiff = pattern1.X - pattern2.X; - float yDiff = pattern1.Y - pattern2.Y; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (float) System.Math.Sqrt((double) (xDiff * xDiff + yDiff * yDiff)); + pointB = patterns[1]; + pointA = patterns[0]; + pointC = patterns[2]; } - - /// Returns the z component of the cross product between vectors BC and BA. - private static float crossProductZ(ResultPoint pointA, ResultPoint pointB, ResultPoint pointC) + else { - float bX = pointB.x; - float bY = pointB.y; - return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); + 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.0f) + { + ResultPoint temp = pointA; + pointA = pointC; + pointC = temp; + } + + patterns[0] = pointA; + patterns[1] = pointB; + patterns[2] = pointC; + } + + + /// distance between two points + public static float distance(ResultPoint pattern1, ResultPoint pattern2) + { + return MathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y); + } + + /// + /// Returns the z component of the cross product between vectors BC and BA. + /// + private static float crossProductZ(ResultPoint pointA, ResultPoint pointB, ResultPoint pointC) + { + float bX = pointB.x; + float bY = pointB.y; + return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); + } + + } + } \ No newline at end of file diff --git a/csharp/ResultPointCallback.cs b/csharp/ResultPointCallback.cs index e736c0a07..a7f7ecd99 100755 --- a/csharp/ResultPointCallback.cs +++ b/csharp/ResultPointCallback.cs @@ -1,31 +1,32 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing { - - /// Callback which is invoked when a possible result point (significant + + /// + /// Callback which is invoked when a possible result point (significant /// point in the barcode image such as a corner) is found. - /// /// - /// - /// + /// public interface ResultPointCallback { - - void foundPossibleResultPoint(ResultPoint point); + + void foundPossibleResultPoint(ResultPoint point); + } + } \ No newline at end of file diff --git a/csharp/Writer.cs b/csharp/Writer.cs index 540b91721..961490a15 100755 --- a/csharp/Writer.cs +++ b/csharp/Writer.cs @@ -1,62 +1,56 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using ByteMatrix = com.google.zxing.common.ByteMatrix; + * 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. + */ + namespace com.google.zxing { - - /// The base class for all objects which encode/generate a barcode image. - /// - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// + using BitMatrix = com.google.zxing.common.BitMatrix; + + + /// + /// The base class for all objects which encode/generate a barcode image. + /// + /// @author dswitkin@google.com (Daniel Switkin) + /// public interface Writer { - - /// Encode a barcode using the default settings. - /// - /// - /// The contents to encode in the barcode - /// - /// The barcode format to generate - /// - /// The preferred width in pixels - /// - /// The preferred height in pixels - /// - /// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) - /// - ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height); - - /// - /// The contents to encode in the barcode - /// - /// The barcode format to generate - /// - /// The preferred width in pixels - /// - /// The preferred height in pixels - /// - /// Additional parameters to supply to the encoder - /// - /// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white) - /// - ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints); + + /// + /// Encode a barcode using the default settings. + /// + /// The contents to encode in the barcode + /// The barcode format to generate + /// The preferred width in pixels + /// The preferred height in pixels +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: com.google.zxing.common.BitMatrix encode(String contents, BarcodeFormat format, int width, int height) throws WriterException; + BitMatrix encode(string contents, BarcodeFormat format, int width, int height); + + /// + /// The contents to encode in the barcode + /// The barcode format to generate + /// The preferred width in pixels + /// The preferred height in pixels + /// Additional parameters to supply to the encoder +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: com.google.zxing.common.BitMatrix encode(String contents, BarcodeFormat format, int width, int height, java.util.Map hints) throws WriterException; + BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints); + } + } \ No newline at end of file diff --git a/csharp/WriterException.cs b/csharp/WriterException.cs index e36569e98..c51b5106e 100755 --- a/csharp/WriterException.cs +++ b/csharp/WriterException.cs @@ -1,40 +1,45 @@ -/* -* 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. -*/ using System; + +/* + * 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. + */ + namespace com.google.zxing { - - /// A base class which covers the range of exceptions which may occur when encoding a barcode using + + /// + /// 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) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - [Serializable] - public sealed class WriterException:System.Exception + public sealed class WriterException : Exception { - - public WriterException():base() - { - } - - public WriterException(System.String message):base(message) - { - } + + public WriterException() + { + } + + public WriterException(string message) : base(message) + { + } + + public WriterException(Exception cause) : base(cause.Message,cause) + { + } + } + } \ No newline at end of file diff --git a/csharp/client/result/AbstractDoCoMoResultParser.cs b/csharp/client/result/AbstractDoCoMoResultParser.cs index c3640984e..5886f9ff7 100755 --- a/csharp/client/result/AbstractDoCoMoResultParser.cs +++ b/csharp/client/result/AbstractDoCoMoResultParser.cs @@ -1,45 +1,45 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - ///

See + + ///

+ ///

See /// /// DoCoMo's documentation about the result types represented by subclasses of this class.

/// ///

Thanks to Jeff Griffin for proposing rewrite of these classes that relies less /// on exception-based mechanisms during parsing.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - abstract class AbstractDoCoMoResultParser:ResultParser + public abstract class AbstractDoCoMoResultParser : ResultParser { - - internal static System.String[] matchDoCoMoPrefixedField(System.String prefix, System.String rawText, bool trim) - { - return matchPrefixedField(prefix, rawText, ';', trim); - } - - internal static System.String matchSingleDoCoMoPrefixedField(System.String prefix, System.String rawText, bool trim) - { - return matchSinglePrefixedField(prefix, rawText, ';', trim); - } + + internal static string[] matchDoCoMoPrefixedField(string prefix, string rawText, bool trim) + { + return matchPrefixedField(prefix, rawText, ';', trim); + } + + internal static string matchSingleDoCoMoPrefixedField(string prefix, string rawText, bool trim) + { + return matchSinglePrefixedField(prefix, rawText, ';', trim); + } + } + } \ No newline at end of file diff --git a/csharp/client/result/AddressBookAUResultParser.cs b/csharp/client/result/AddressBookAUResultParser.cs index f3ba7c670..c0abf0317 100755 --- a/csharp/client/result/AddressBookAUResultParser.cs +++ b/csharp/client/result/AddressBookAUResultParser.cs @@ -1,79 +1,83 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Implements KDDI AU's address book format. See + + using Result = com.google.zxing.Result; + + + /// + /// Implements KDDI AU's address book format. See /// /// http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html. /// (Thanks to Yuzo for translating!) /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class AddressBookAUResultParser:ResultParser + public sealed class AddressBookAUResultParser : ResultParser { - - public static AddressBookParsedResult parse(Result result) + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + // MEMORY is mandatory; seems like a decent indicator, as does end-of-record separator CR/LF + if (!rawText.Contains("MEMORY") || !rawText.Contains("\r\n")) { - System.String rawText = result.Text; - // 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. - System.String name = matchSinglePrefixedField("NAME1:", rawText, '\r', true); - System.String pronunciation = matchSinglePrefixedField("NAME2:", rawText, '\r', true); - - System.String[] phoneNumbers = matchMultipleValuePrefix("TEL", 3, rawText, true); - System.String[] emails = matchMultipleValuePrefix("MAIL", 3, rawText, true); - System.String note = matchSinglePrefixedField("MEMORY:", rawText, '\r', false); - System.String address = matchSinglePrefixedField("ADD:", rawText, '\r', true); - System.String[] addresses = address == null?null:new System.String[]{address}; - return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, emails, note, addresses, null, null, null, null); + return null; } - - private static System.String[] matchMultipleValuePrefix(System.String prefix, int max, System.String rawText, bool trim) + + // NAME1 and NAME2 have specific uses, namely written name and pronunciation, respectively. + // Therefore we treat them specially instead of as an array of names. + string name = matchSinglePrefixedField("NAME1:", rawText, '\r', true); + string pronunciation = matchSinglePrefixedField("NAME2:", rawText, '\r', true); + + string[] phoneNumbers = matchMultipleValuePrefix("TEL", 3, rawText, true); + string[] emails = matchMultipleValuePrefix("MAIL", 3, rawText, true); + string note = matchSinglePrefixedField("MEMORY:", rawText, '\r', false); + string address = matchSinglePrefixedField("ADD:", rawText, '\r', true); + string[] addresses = address == null ? null : new string[] {address}; + return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, null, emails, null, null, note, addresses, null, null, null, null, null); + } + + private static string[] matchMultipleValuePrefix(string prefix, int max, string rawText, bool trim) + { + List values = null; + for (int i = 1; i <= max; i++) { - System.Collections.ArrayList values = null; - for (int i = 1; i <= max; i++) - { - System.String value_Renamed = matchSinglePrefixedField(prefix + i + ':', rawText, '\r', trim); - if (value_Renamed == null) - { - break; - } - if (values == null) - { - values = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(max)); // lazy init - } - values.Add(value_Renamed); - } - if (values == null) - { - return null; - } - return toStringArray(values); + string value = matchSinglePrefixedField(prefix + i + ':', rawText, '\r', trim); + if (value == null) + { + break; + } + if (values == null) + { + values = new List(max); // lazy init + } + values.Add(value); } + if (values == null) + { + return null; + } + return values.ToArray(); + } + } + } \ No newline at end of file diff --git a/csharp/client/result/AddressBookDoCoMoResultParser.cs b/csharp/client/result/AddressBookDoCoMoResultParser.cs index 68b5f2396..7efdfe0f1 100755 --- a/csharp/client/result/AddressBookDoCoMoResultParser.cs +++ b/csharp/client/result/AddressBookDoCoMoResultParser.cs @@ -1,24 +1,26 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Implements the "MECARD" address book entry format. + + using Result = com.google.zxing.Result; + + /// + /// Implements the "MECARD" address book entry format. /// /// Supported keys: N, SOUND, TEL, EMAIL, NOTE, ADR, BDAY, URL, plus ORG /// Unsupported keys: TEL-AV, NICKNAME @@ -30,56 +32,55 @@ namespace com.google.zxing.client.result /// /// http://www.mobicode.org.tw/files/OMIA%20Mobile%20Bar%20Code%20Standard%20v3.2.1.doc /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class AddressBookDoCoMoResultParser:AbstractDoCoMoResultParser + public sealed class AddressBookDoCoMoResultParser : AbstractDoCoMoResultParser { - - public static AddressBookParsedResult parse(Result result) + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!rawText.StartsWith("MECARD:")) { - System.String rawText = result.Text; - if (rawText == null || !rawText.StartsWith("MECARD:")) - { - return null; - } - System.String[] rawName = matchDoCoMoPrefixedField("N:", rawText, true); - if (rawName == null) - { - return null; - } - System.String name = parseName(rawName[0]); - System.String pronunciation = matchSingleDoCoMoPrefixedField("SOUND:", rawText, true); - System.String[] phoneNumbers = matchDoCoMoPrefixedField("TEL:", rawText, true); - System.String[] emails = matchDoCoMoPrefixedField("EMAIL:", rawText, true); - System.String note = matchSingleDoCoMoPrefixedField("NOTE:", rawText, false); - System.String[] addresses = matchDoCoMoPrefixedField("ADR:", rawText, true); - System.String birthday = matchSingleDoCoMoPrefixedField("BDAY:", rawText, true); - if (birthday != null && !isStringOfDigits(birthday, 8)) - { - // No reason to throw out the whole card because the birthday is formatted wrong. - birthday = null; - } - System.String url = matchSingleDoCoMoPrefixedField("URL:", rawText, true); - - // Although ORG may not be strictly legal in MECARD, it does exist in VCARD and we might as well - // honor it when found in the wild. - System.String org = matchSingleDoCoMoPrefixedField("ORG:", rawText, true); - - return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, emails, note, addresses, org, birthday, null, url); + return null; } - - private static System.String parseName(System.String name) + string[] rawName = matchDoCoMoPrefixedField("N:", rawText, true); + if (rawName == null) { - int comma = name.IndexOf(','); - if (comma >= 0) - { - // Format may be last,first; switch it around - return name.Substring(comma + 1) + ' ' + name.Substring(0, (comma) - (0)); - } - return name; + return null; } + string name = parseName(rawName[0]); + string pronunciation = matchSingleDoCoMoPrefixedField("SOUND:", rawText, true); + string[] phoneNumbers = matchDoCoMoPrefixedField("TEL:", rawText, true); + string[] emails = matchDoCoMoPrefixedField("EMAIL:", rawText, true); + string note = matchSingleDoCoMoPrefixedField("NOTE:", rawText, false); + string[] addresses = matchDoCoMoPrefixedField("ADR:", rawText, true); + string birthday = matchSingleDoCoMoPrefixedField("BDAY:", rawText, true); + if (birthday != null && !isStringOfDigits(birthday, 8)) + { + // No reason to throw out the whole card because the birthday is formatted wrong. + birthday = null; + } + string url = matchSingleDoCoMoPrefixedField("URL:", rawText, true); + + // Although ORG may not be strictly legal in MECARD, it does exist in VCARD and we might as well + // honor it when found in the wild. + string org = matchSingleDoCoMoPrefixedField("ORG:", rawText, true); + + return new AddressBookParsedResult(maybeWrap(name), pronunciation, phoneNumbers, null, emails, null, null, note, addresses, null, org, birthday, null, url); + } + + private static string parseName(string name) + { + int comma =(int) name.IndexOf(','); + if (comma >= 0) + { + // Format may be last,first; switch it around + return name.Substring(comma + 1) + ' ' + name.Substring(0, comma); + } + return name; + } + } + } \ No newline at end of file diff --git a/csharp/client/result/AddressBookParsedResult.cs b/csharp/client/result/AddressBookParsedResult.cs index d26232788..57b6534b0 100755 --- a/csharp/client/result/AddressBookParsedResult.cs +++ b/csharp/client/result/AddressBookParsedResult.cs @@ -1,169 +1,207 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class AddressBookParsedResult:ParsedResult + + /// + /// @author Sean Owen + /// + public sealed class AddressBookParsedResult : ParsedResult { - public System.String[] Names - { - get - { - 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. - /// - /// - /// The pronunciation of the getNames() field, often in hiragana or katakana. - /// - public System.String Pronunciation - { - get - { - return pronunciation; - } - - } - public System.String[] PhoneNumbers - { - get - { - return phoneNumbers; - } - - } - public System.String[] Emails - { - get - { - return emails; - } - - } - public System.String Note - { - get - { - return note; - } - - } - public System.String[] Addresses - { - get - { - return addresses; - } - - } - public System.String Title - { - get - { - return title; - } - - } - public System.String Org - { - get - { - return org; - } - - } - public System.String URL - { - get - { - return url; - } - - } - /// birthday formatted as yyyyMMdd (e.g. 19780917) - /// - public System.String Birthday - { - get - { - return birthday; - } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(100); - maybeAppend(names, result); - maybeAppend(pronunciation, result); - maybeAppend(title, result); - maybeAppend(org, result); - maybeAppend(addresses, result); - maybeAppend(phoneNumbers, result); - maybeAppend(emails, result); - maybeAppend(url, result); - maybeAppend(birthday, result); - maybeAppend(note, result); - return result.ToString(); - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'names '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String[] names; - //UPGRADE_NOTE: Final was removed from the declaration of 'pronunciation '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String pronunciation; - //UPGRADE_NOTE: Final was removed from the declaration of 'phoneNumbers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String[] phoneNumbers; - //UPGRADE_NOTE: Final was removed from the declaration of 'emails '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String[] emails; - //UPGRADE_NOTE: Final was removed from the declaration of 'note '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String note; - //UPGRADE_NOTE: Final was removed from the declaration of 'addresses '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String[] addresses; - //UPGRADE_NOTE: Final was removed from the declaration of 'org '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String org; - //UPGRADE_NOTE: Final was removed from the declaration of 'birthday '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String birthday; - //UPGRADE_NOTE: Final was removed from the declaration of 'title '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String title; - //UPGRADE_NOTE: Final was removed from the declaration of 'url '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String url; - - public AddressBookParsedResult(System.String[] names, System.String pronunciation, System.String[] phoneNumbers, System.String[] emails, System.String note, System.String[] addresses, System.String org, System.String birthday, System.String title, System.String url):base(ParsedResultType.ADDRESSBOOK) - { - this.names = names; - this.pronunciation = pronunciation; - this.phoneNumbers = phoneNumbers; - this.emails = emails; - this.note = note; - this.addresses = addresses; - this.org = org; - this.birthday = birthday; - this.title = title; - this.url = url; - } + + private readonly string[] names; + private readonly string pronunciation; + private readonly string[] phoneNumbers; + private readonly string[] phoneTypes; + private readonly string[] emails; + private readonly string[] emailTypes; + private readonly string instantMessenger; + private readonly string note; + private readonly string[] addresses; + private readonly string[] addressTypes; + private readonly string org; + private readonly string birthday; + private readonly string title; + private readonly string url; + + public AddressBookParsedResult(string[] names, string pronunciation, string[] phoneNumbers, string[] phoneTypes, string[] emails, string[] emailTypes, string instantMessenger, string note, string[] addresses, string[] addressTypes, string org, string birthday, string title, string url) : base(ParsedResultType.ADDRESSBOOK) + { + this.names = names; + this.pronunciation = pronunciation; + this.phoneNumbers = phoneNumbers; + this.phoneTypes = phoneTypes; + this.emails = emails; + this.emailTypes = emailTypes; + this.instantMessenger = instantMessenger; + this.note = note; + this.addresses = addresses; + this.addressTypes = addressTypes; + this.org = org; + this.birthday = birthday; + this.title = title; + this.url = url; + } + + public string[] Names + { + get + { + 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. + /// + /// The pronunciation of the getNames() field, often in hiragana or katakana. + public string Pronunciation + { + get + { + return pronunciation; + } + } + + public string[] PhoneNumbers + { + get + { + return phoneNumbers; + } + } + + /// optional descriptions of the type of each phone number. It could be like "HOME", but, + /// there is no guaranteed or standard format. + public string[] PhoneTypes + { + get + { + return phoneTypes; + } + } + + public string[] Emails + { + get + { + return emails; + } + } + + /// optional descriptions of the type of each e-mail. It could be like "WORK", but, + /// there is no guaranteed or standard format. + public string[] EmailTypes + { + get + { + return emailTypes; + } + } + + public string InstantMessenger + { + get + { + return instantMessenger; + } + } + + public string Note + { + get + { + return note; + } + } + + public string[] Addresses + { + get + { + return addresses; + } + } + + /// optional descriptions of the type of each e-mail. It could be like "WORK", but, + /// there is no guaranteed or standard format. + public string[] AddressTypes + { + get + { + return addressTypes; + } + } + + public string Title + { + get + { + return title; + } + } + + public string Org + { + get + { + return org; + } + } + + public string URL + { + get + { + return url; + } + } + + /// birthday formatted as yyyyMMdd (e.g. 19780917) + public string Birthday + { + get + { + return birthday; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(100); + maybeAppend(names, result); + maybeAppend(pronunciation, result); + maybeAppend(title, result); + maybeAppend(org, result); + maybeAppend(addresses, result); + maybeAppend(phoneNumbers, result); + maybeAppend(emails, result); + maybeAppend(instantMessenger, result); + maybeAppend(url, result); + maybeAppend(birthday, result); + maybeAppend(note, result); + return result.ToString(); + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/BizcardResultParser.cs b/csharp/client/result/BizcardResultParser.cs index 2e4f48bf0..949903bb2 100755 --- a/csharp/client/result/BizcardResultParser.cs +++ b/csharp/client/result/BizcardResultParser.cs @@ -1,98 +1,97 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Implements the "BIZCARD" address book entry format, though this has been + + using Result = 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 /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class BizcardResultParser:AbstractDoCoMoResultParser + public sealed class BizcardResultParser : 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 AddressBookParsedResult parse(Result result) + + // 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 override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!rawText.StartsWith("BIZCARD:")) { - System.String rawText = result.Text; - if (rawText == null || !rawText.StartsWith("BIZCARD:")) - { - return null; - } - System.String firstName = matchSingleDoCoMoPrefixedField("N:", rawText, true); - System.String lastName = matchSingleDoCoMoPrefixedField("X:", rawText, true); - System.String fullName = buildName(firstName, lastName); - System.String title = matchSingleDoCoMoPrefixedField("T:", rawText, true); - System.String org = matchSingleDoCoMoPrefixedField("C:", rawText, true); - System.String[] addresses = matchDoCoMoPrefixedField("A:", rawText, true); - System.String phoneNumber1 = matchSingleDoCoMoPrefixedField("B:", rawText, true); - System.String phoneNumber2 = matchSingleDoCoMoPrefixedField("M:", rawText, true); - System.String phoneNumber3 = matchSingleDoCoMoPrefixedField("F:", rawText, true); - System.String email = matchSingleDoCoMoPrefixedField("E:", rawText, true); - - return new AddressBookParsedResult(maybeWrap(fullName), null, buildPhoneNumbers(phoneNumber1, phoneNumber2, phoneNumber3), maybeWrap(email), null, addresses, org, null, title, null); + return null; } - - private static System.String[] buildPhoneNumbers(System.String number1, System.String number2, System.String number3) + string firstName = matchSingleDoCoMoPrefixedField("N:", rawText, true); + string lastName = matchSingleDoCoMoPrefixedField("X:", rawText, true); + string fullName = buildName(firstName, lastName); + string title = matchSingleDoCoMoPrefixedField("T:", rawText, true); + string org = matchSingleDoCoMoPrefixedField("C:", rawText, true); + string[] addresses = matchDoCoMoPrefixedField("A:", rawText, true); + string phoneNumber1 = matchSingleDoCoMoPrefixedField("B:", rawText, true); + string phoneNumber2 = matchSingleDoCoMoPrefixedField("M:", rawText, true); + string phoneNumber3 = matchSingleDoCoMoPrefixedField("F:", rawText, true); + string email = matchSingleDoCoMoPrefixedField("E:", rawText, true); + + return new AddressBookParsedResult(maybeWrap(fullName), null, buildPhoneNumbers(phoneNumber1, phoneNumber2, phoneNumber3), null, maybeWrap(email), null, null, null, addresses, null, org, null, title, null); + } + + private static string[] buildPhoneNumbers(string number1, string number2, string number3) + { + List numbers = new List(3); + if (number1 != null) { - System.Collections.ArrayList numbers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(3)); - if (number1 != null) - { - numbers.Add(number1); - } - if (number2 != null) - { - numbers.Add(number2); - } - if (number3 != null) - { - numbers.Add(number3); - } - int size = numbers.Count; - if (size == 0) - { - return null; - } - System.String[] result = new System.String[size]; - for (int i = 0; i < size; i++) - { - result[i] = ((System.String) numbers[i]); - } - return result; + numbers.Add(number1); } - - private static System.String buildName(System.String firstName, System.String lastName) + if (number2 != null) { - if (firstName == null) - { - return lastName; - } - else - { - return lastName == null?firstName:firstName + ' ' + lastName; - } + numbers.Add(number2); } + if (number3 != null) + { + numbers.Add(number3); + } + int size = numbers.Count; + if (size == 0) + { + return null; + } + return numbers.ToArray(); + } + + private static string buildName(string firstName, string lastName) + { + if (firstName == null) + { + return lastName; + } + else + { + return lastName == null ? firstName : firstName + ' ' + lastName; + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/BookmarkDoCoMoResultParser.cs b/csharp/client/result/BookmarkDoCoMoResultParser.cs index da70093d5..69a40193f 100755 --- a/csharp/client/result/BookmarkDoCoMoResultParser.cs +++ b/csharp/client/result/BookmarkDoCoMoResultParser.cs @@ -1,53 +1,46 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class BookmarkDoCoMoResultParser:AbstractDoCoMoResultParser + + using Result = com.google.zxing.Result; + + /// + /// @author Sean Owen + /// + public sealed class BookmarkDoCoMoResultParser : AbstractDoCoMoResultParser { - - private BookmarkDoCoMoResultParser() + + public override ParsedResult parse(Result result) + { + string rawText = result.Text; + if (!rawText.StartsWith("MEBKM:")) { + return null; } - - public static URIParsedResult parse(Result result) + string title = matchSingleDoCoMoPrefixedField("TITLE:", rawText, true); + string[] rawUri = matchDoCoMoPrefixedField("URL:", rawText, true); + if (rawUri == null) { - System.String rawText = result.Text; - if (rawText == null || !rawText.StartsWith("MEBKM:")) - { - return null; - } - System.String title = matchSingleDoCoMoPrefixedField("TITLE:", rawText, true); - System.String[] rawUri = matchDoCoMoPrefixedField("URL:", rawText, true); - if (rawUri == null) - { - return null; - } - System.String uri = rawUri[0]; - if (!URIResultParser.isBasicallyValidURI(uri)) - { - return null; - } - return new URIParsedResult(uri, title); + return null; } + string uri = rawUri[0]; + return URIResultParser.isBasicallyValidURI(uri) ? new URIParsedResult(uri, title) : null; + } + } } \ No newline at end of file diff --git a/csharp/client/result/CalendarParsedResult.cs b/csharp/client/result/CalendarParsedResult.cs index e0786cde6..c1d9c3d45 100755 --- a/csharp/client/result/CalendarParsedResult.cs +++ b/csharp/client/result/CalendarParsedResult.cs @@ -1,172 +1,300 @@ -/* -* 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. -*/ using System; +using System.Text; +using System.Text.RegularExpressions; + +/* + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class CalendarParsedResult:ParsedResult + + + /// + /// @author Sean Owen + /// + public sealed class CalendarParsedResult : ParsedResult { - public System.String Summary + + private static readonly string RFC2445_DURATION = "P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?"; + private static readonly long[] RFC2445_DURATION_FIELD_UNITS = {7 * 24 * 60 * 60 * 1000L, 24 * 60 * 60 * 1000L, 60 * 60 * 1000L, 60 * 1000L, 1000L}; + + private static readonly string DATE_TIME = "[0-9]{8}(T[0-9]{6}Z?)?"; + + private static readonly string DATE_FORMAT = "yyyyMMdd"; + static CalendarParsedResult() + { + // For dates without a time, for purposes of interacting with Android, the resulting timestamp + // needs to be midnight of that day in GMT. See: + // http://code.google.com/p/android/issues/detail?id=8330 + string DATE_FORMAT_TimeZone = "GMT"; + } + private static readonly string DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmss"; + + private readonly string summary; + private readonly DateTime start; + private readonly bool startAllDay; + private readonly DateTime? end; + private readonly bool endAllDay; + private readonly string location; + private readonly string organizer; + private readonly string[] attendees; + private readonly string description; + private readonly double latitude; + private readonly double longitude; + + public CalendarParsedResult(string summary, string startString, string endString, string durationString, string location, string organizer, string[] attendees, string description, double latitude, double longitude) : base(ParsedResultType.CALENDAR) + { + this.summary = summary; + + try { - get - { - return summary; - } - + this.start = parseDate(startString); } - ///

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 java.text.SimpleDateFormat.

See validateDate() for the return format. - /// - ///
- /// start time formatted as a RFC 2445 DATE or DATE-TIME.

- ///
- public System.String Start + catch (FormatException pe) { - get - { - return start; - } - + throw new System.ArgumentException(pe.ToString()); } - /// - /// - public System.String End + + if (endString == null) { - get - { - return end; - } - + long durationMS = parseDurationMS(durationString); + end = durationMS < 0L ? null :(DateTime?) start.AddMilliseconds( durationMS); } - public System.String Location + else { - get - { - return location; - } - + try + { + this.end = parseDate(endString); + } + catch (FormatException pe) + { + throw new System.ArgumentException(pe.ToString()); + } } - public System.String Attendee + + this.startAllDay = startString.Length == 8; + this.endAllDay = endString != null && endString.Length == 8; + + this.location = location; + this.organizer = organizer; + this.attendees = attendees; + this.description = description; + this.latitude = latitude; + this.longitude = longitude; + } + + public string Summary + { + get + { + return summary; + } + } + + /// start time + public DateTime Start + { + get + { + return start; + } + } + + /// true if start time was specified as a whole day + public bool StartAllDay + { + get + { + return startAllDay; + } + } + + /// + /// May return null if the event has no duration. + /// + public DateTime? End + { + get + { + return end; + } + } + + /// true if end time was specified as a whole day + public bool EndAllDay + { + get + { + return endAllDay; + } + } + + public string Location + { + get + { + return location; + } + } + + public string Organizer + { + get + { + return organizer; + } + } + + public string[] Attendees + { + get + { + return attendees; + } + } + + public string Description + { + get + { + return description; + } + } + + public double Latitude + { + get + { + return latitude; + } + } + + public double Longitude + { + get + { + return longitude; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(100); + maybeAppend(summary, result); + maybeAppend(format(startAllDay, start), result); + maybeAppend(format(endAllDay, end), result); + maybeAppend(location, result); + maybeAppend(organizer, result); + maybeAppend(attendees, result); + maybeAppend(description, result); + return result.ToString(); + } + } + + /// + /// Parses a string as a date. 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). + /// + /// The string to parse + /// if not able to parse as a date +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static java.util.Date parseDate(String when) throws java.text.ParseException + private static DateTime parseDate(string when) + { + if (!(new Regex (DATE_TIME).IsMatch(when))) { - get - { - return attendee; - } - + throw FormatException.FormatInstance; } - public System.String Title + if (when.Length == 8) { - get - { - return title; - } - + // Show only year/month/day + return DateTime.Parse(when); } - override public System.String DisplayResult + else { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(100); - maybeAppend(summary, result); - maybeAppend(start, result); - maybeAppend(end, result); - maybeAppend(location, result); - maybeAppend(attendee, result); - maybeAppend(title, result); - return result.ToString(); - } - + // The when string can be local time, or UTC if it ends with a Z + DateTime date; + if (when.Length == 16 && when[15] == 'Z') + { + date = DateTime.Parse(when.Substring(0, 15)); + //DateTime calendar = new GregorianCalendar(); + // System.Globalization.GregorianCalendar calendar = new System.Globalization.GregorianCalendar() + //long milliseconds = date; + //// Account for time zone difference + //milliseconds += calendar.get(DateTime.ZONE_OFFSET); + //// Might need to correct for daylight savings time, but use target time since + //// now might be in DST but not then, or vice versa + //calendar = new DateTime(milliseconds); + //milliseconds += calendar.get(DateTime.DST_OFFSET); + TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(date); + + date = date + offset; + } + else + { + date = DateTime.Parse(when); + } + return date; } - - //UPGRADE_NOTE: Final was removed from the declaration of 'summary '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String summary; - //UPGRADE_NOTE: Final was removed from the declaration of 'start '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String start; - //UPGRADE_NOTE: Final was removed from the declaration of 'end '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String end; - //UPGRADE_NOTE: Final was removed from the declaration of 'location '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String location; - //UPGRADE_NOTE: Final was removed from the declaration of 'attendee '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String attendee; - //UPGRADE_NOTE: Final was removed from the declaration of 'title '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String title; - - public CalendarParsedResult(System.String summary, System.String start, System.String end, System.String location, System.String attendee, System.String title):base(ParsedResultType.CALENDAR) + } + + private static string format(bool allDay, DateTime? date) + { + if (date == null) + { + return null; + } + //DateFormat format = allDay ? DateFormat.getDateInstance(DateFormat.MEDIUM) : DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); + //return format.format(date); + if (allDay) + { + return String.Format("dd-MMM-yyyy",date); + } + else + { + return String.Format("dd-MMM-yyyy hh:mm:ss tt",date); + } + } + + private static long parseDurationMS(string durationString) + { + if (durationString == null) { - // Start is required, end is not - if (start == null) - { - throw new System.ArgumentException(); - } - validateDate(start); - validateDate(end); - this.summary = summary; - this.start = start; - this.end = end; - this.location = location; - this.attendee = attendee; - this.title = title; + return -1L; } - - /// 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). - /// - /// - /// The string to validate - /// - private static void validateDate(System.String date) + Regex m = new Regex(RFC2445_DURATION); + Match match = m.Match(durationString); + if (!match.Success) { - if (date != null) - { - int length = date.Length; - if (length != 8 && length != 15 && length != 16) - { - throw new System.ArgumentException(); - } - for (int i = 0; i < 8; i++) - { - if (!System.Char.IsDigit(date[i])) - { - throw new System.ArgumentException(); - } - } - if (length > 8) - { - if (date[8] != 'T') - { - throw new System.ArgumentException(); - } - for (int i = 9; i < 15; i++) - { - if (!System.Char.IsDigit(date[i])) - { - throw new System.ArgumentException(); - } - } - if (length == 16 && date[15] != 'Z') - { - throw new System.ArgumentException(); - } - } - } + return -1L; } + long durationMS = 0L; + for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.Length; i++) + { + string fieldValue = match.Groups[i + 1].Value; + if (fieldValue != null) + { + durationMS += RFC2445_DURATION_FIELD_UNITS[i] * Convert.ToInt32(fieldValue); + } + } + return durationMS; + } + } + } \ No newline at end of file diff --git a/csharp/client/result/EmailAddressParsedResult.cs b/csharp/client/result/EmailAddressParsedResult.cs index 3322012bc..9facf6e26 100755 --- a/csharp/client/result/EmailAddressParsedResult.cs +++ b/csharp/client/result/EmailAddressParsedResult.cs @@ -1,88 +1,86 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EmailAddressParsedResult:ParsedResult + + /// + /// @author Sean Owen + /// + public sealed class EmailAddressParsedResult : ParsedResult { - public System.String EmailAddress - { - get - { - return emailAddress; - } - - } - public System.String Subject - { - get - { - return subject; - } - - } - public System.String Body - { - get - { - return body; - } - - } - public System.String MailtoURI - { - get - { - return mailtoURI; - } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(30); - maybeAppend(emailAddress, result); - maybeAppend(subject, result); - maybeAppend(body, result); - return result.ToString(); - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'emailAddress '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String emailAddress; - //UPGRADE_NOTE: Final was removed from the declaration of 'subject '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String subject; - //UPGRADE_NOTE: Final was removed from the declaration of 'body '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String body; - //UPGRADE_NOTE: Final was removed from the declaration of 'mailtoURI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String mailtoURI; - - internal EmailAddressParsedResult(System.String emailAddress, System.String subject, System.String body, System.String mailtoURI):base(ParsedResultType.EMAIL_ADDRESS) - { - this.emailAddress = emailAddress; - this.subject = subject; - this.body = body; - this.mailtoURI = mailtoURI; - } + + private readonly string emailAddress; + private readonly string subject; + private readonly string body; + private readonly string mailtoURI; + + internal EmailAddressParsedResult(string emailAddress, string subject, string body, string mailtoURI) : base(ParsedResultType.EMAIL_ADDRESS) + { + this.emailAddress = emailAddress; + this.subject = subject; + this.body = body; + this.mailtoURI = mailtoURI; + } + + public string EmailAddress + { + get + { + return emailAddress; + } + } + + public string Subject + { + get + { + return subject; + } + } + + public string Body + { + get + { + return body; + } + } + + public string MailtoURI + { + get + { + return mailtoURI; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(30); + maybeAppend(emailAddress, result); + maybeAppend(subject, result); + maybeAppend(body, result); + return result.ToString(); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/EmailAddressResultParser.cs b/csharp/client/result/EmailAddressResultParser.cs index dff45462d..897e8d918 100755 --- a/csharp/client/result/EmailAddressResultParser.cs +++ b/csharp/client/result/EmailAddressResultParser.cs @@ -1,74 +1,73 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Represents a result that encodes an e-mail address, either as a plain address + + using Result = com.google.zxing.Result; + + + /// + /// 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 /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class EmailAddressResultParser:ResultParser + public sealed class EmailAddressResultParser : ResultParser { - - public static EmailAddressParsedResult parse(Result result) + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + string emailAddress; + if (rawText.StartsWith("mailto:") || rawText.StartsWith("MAILTO:")) { - System.String rawText = result.Text; - if (rawText == null) + // If it starts with mailto:, assume it is definitely trying to be an email address + emailAddress = rawText.Substring(7); + int queryStart = emailAddress.IndexOf('?'); + if (queryStart >= 0) + { + emailAddress = emailAddress.Substring(0, queryStart); + } + IDictionary nameValues = parseNameValuePairs(rawText); + string subject = null; + string body = null; + if (nameValues != null) + { + if (emailAddress.Length == 0) { - return null; - } - System.String emailAddress; - if (rawText.StartsWith("mailto:") || rawText.StartsWith("MAILTO:")) - { - // If it starts with mailto:, assume it is definitely trying to be an email address - emailAddress = rawText.Substring(7); - int queryStart = emailAddress.IndexOf('?'); - if (queryStart >= 0) - { - emailAddress = emailAddress.Substring(0, (queryStart) - (0)); - } - System.Collections.Hashtable nameValues = parseNameValuePairs(rawText); - System.String subject = null; - System.String body = null; - if (nameValues != null) - { - if (emailAddress.Length == 0) - { - emailAddress = ((System.String) nameValues["to"]); - } - subject = ((System.String) nameValues["subject"]); - body = ((System.String) nameValues["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); + emailAddress = nameValues["to"]; } + subject = nameValues["subject"]; + body = nameValues["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); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/EmailDoCoMoResultParser.cs b/csharp/client/result/EmailDoCoMoResultParser.cs index adb065f11..26da44691 100755 --- a/csharp/client/result/EmailDoCoMoResultParser.cs +++ b/csharp/client/result/EmailDoCoMoResultParser.cs @@ -1,101 +1,71 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Implements the "MATMSG" email message entry format. + + using Result = com.google.zxing.Result; + using System.Text.RegularExpressions; + + + /// + /// Implements the "MATMSG" email message entry format. /// /// Supported keys: TO, SUB, BODY /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class EmailDoCoMoResultParser:AbstractDoCoMoResultParser + public sealed class EmailDoCoMoResultParser : AbstractDoCoMoResultParser { - - //UPGRADE_NOTE: Final was removed from the declaration of 'ATEXT_SYMBOLS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] ATEXT_SYMBOLS = new char[]{'@', '.', '!', '#', '$', '%', '&', '\'', '*', '+', '-', '/', '=', '?', '^', '_', '`', '{', '|', '}', '~'}; - - public static EmailAddressParsedResult parse(Result result) + + private static readonly string ATEXT_ALPHANUMERIC = "[a-zA-Z0-9@.!#$%&'*+\\-/=?^_`{|}~]+"; + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!rawText.StartsWith("MATMSG:")) { - System.String rawText = result.Text; - if (rawText == null || !rawText.StartsWith("MATMSG:")) - { - return null; - } - System.String[] rawTo = matchDoCoMoPrefixedField("TO:", rawText, true); - if (rawTo == null) - { - return null; - } - System.String to = rawTo[0]; - if (!isBasicallyValidEmailAddress(to)) - { - return null; - } - System.String subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false); - System.String body = matchSingleDoCoMoPrefixedField("BODY:", rawText, false); - return new EmailAddressParsedResult(to, subject, body, "mailto:" + to); + return null; } - - /// 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. - /// - internal static bool isBasicallyValidEmailAddress(System.String email) + string[] rawTo = matchDoCoMoPrefixedField("TO:", rawText, true); + if (rawTo == null) { - if (email == null) - { - return false; - } - bool atFound = false; - for (int i = 0; i < email.Length; i++) - { - char c = email[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; + return null; } - - private static bool isAtextSymbol(char c) + string to = rawTo[0]; + if (!isBasicallyValidEmailAddress(to)) { - for (int i = 0; i < ATEXT_SYMBOLS.Length; i++) - { - if (c == ATEXT_SYMBOLS[i]) - { - return true; - } - } - return false; + return null; } + string subject = matchSingleDoCoMoPrefixedField("SUB:", rawText, false); + string body = 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 '@' and 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. + /// + internal static bool isBasicallyValidEmailAddress(string email) + { + //return email != null && ATEXT_ALPHANUMERIC.matcher(email).matches() && email.IndexOf('@') >= 0; + return email != null && new Regex( ATEXT_ALPHANUMERIC).IsMatch(email) && email.IndexOf('@') >= 0; + } + } } \ No newline at end of file diff --git a/csharp/client/result/GeoParsedResult.cs b/csharp/client/result/GeoParsedResult.cs index da4f217db..11e01a067 100755 --- a/csharp/client/result/GeoParsedResult.cs +++ b/csharp/client/result/GeoParsedResult.cs @@ -1,131 +1,125 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class GeoParsedResult:ParsedResult + + /// + /// @author Sean Owen + /// + public sealed class GeoParsedResult : ParsedResult { - public System.String GeoURI - { - get + + private readonly double latitude; + private readonly double longitude; + private readonly double altitude; + private readonly string query; + + internal GeoParsedResult(double latitude, double longitude, double altitude, string query) : base(ParsedResultType.GEO) + { + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + this.query = query; + } + + public string GeoURI + { + get + { + StringBuilder result = new StringBuilder(); + result.Append("geo:"); + result.Append(latitude); + result.Append(','); + result.Append(longitude); + if (altitude > 0) { - return geoURI; + result.Append(','); + result.Append(altitude); } - - } - /// latitude in degrees - /// - public double Latitude - { - get + if (query != null) { - return latitude; + result.Append('?'); + result.Append(query); } - - } - /// longitude in degrees - /// - public double Longitude - { - get + return result.ToString(); + } + } + + /// latitude in degrees + public double Latitude + { + get + { + return latitude; + } + } + + /// longitude in degrees + public double Longitude + { + get + { + return longitude; + } + } + + /// altitude in meters. If not specified, in the geo URI, returns 0.0 + public double Altitude + { + get + { + return altitude; + } + } + + /// query string associated with geo URI or null if none exists + public string Query + { + get + { + return query; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(20); + result.Append(latitude); + result.Append(", "); + result.Append(longitude); + if (altitude > 0.0) { - return longitude; + result.Append(", "); + result.Append(altitude); + result.Append('m'); } - - } - /// altitude in meters. If not specified, in the geo URI, returns 0.0 - /// - public double Altitude - { - get + if (query != null) { - return altitude; + result.Append(" ("); + result.Append(query); + result.Append(')'); } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(50); - result.Append(latitude); - result.Append(", "); - result.Append(longitude); - if (altitude > 0.0f) - { - result.Append(", "); - result.Append(altitude); - result.Append('m'); - } - return result.ToString(); - } - - /// 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(); - } - */ - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'geoURI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String geoURI; - //UPGRADE_NOTE: Final was removed from the declaration of 'latitude '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private double latitude; - //UPGRADE_NOTE: Final was removed from the declaration of 'longitude '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private double longitude; - //UPGRADE_NOTE: Final was removed from the declaration of 'altitude '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private double altitude; - - internal GeoParsedResult(System.String geoURI, double latitude, double longitude, double altitude):base(ParsedResultType.GEO) - { - this.geoURI = geoURI; - this.latitude = latitude; - this.longitude = longitude; - this.altitude = altitude; - } + return result.ToString(); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/GeoResultParser.cs b/csharp/client/result/GeoResultParser.cs index cd2e8498d..7658c3c28 100755 --- a/csharp/client/result/GeoResultParser.cs +++ b/csharp/client/result/GeoResultParser.cs @@ -1,78 +1,87 @@ -/* -* 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. -*/ using System; -using Result = com.google.zxing.Result; +using System.Text.RegularExpressions; + +/* + * 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. + */ + namespace com.google.zxing.client.result { - - /// Parses a "geo:" URI result, which specifies a location on the surface of + + using Result = com.google.zxing.Result; + + + /// + /// Parses a "geo:" URI result, which specifies a location on the surface of /// the Earth as well as an optional altitude above the surface. See /// /// http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class GeoResultParser:ResultParser + public sealed class GeoResultParser : ResultParser { - - private GeoResultParser() + + private static readonly string GEO_URL_PATTERN = "geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?"; + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + + Match matcher = Regex.Match(rawText,GEO_URL_PATTERN,RegexOptions.IgnoreCase); + if (!matcher.Success) { + return null; } - - public static GeoParsedResult parse(Result result) + + string query = matcher.Groups[4].Value; + + double latitude; + double longitude; + double altitude; + try { - System.String rawText = result.Text; - if (rawText == null || (!rawText.StartsWith("geo:") && !rawText.StartsWith("GEO:"))) + latitude = Convert.ToDouble(matcher.Groups[1].Value); + if (latitude > 90.0 || latitude < -90.0) + { + return null; + } + longitude = Convert.ToDouble(matcher.Groups[2].Value); + if (longitude > 180.0 || longitude < -180.0) + { + return null; + } + if (matcher.Groups[3].Value == null) + { + altitude = 0.0; + } + else + { + altitude = Convert.ToDouble(matcher.Groups[3].Value); + if (altitude < 0.0) { - return null; + return null; } - // Drop geo, query portion - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int queryStart = rawText.IndexOf('?', 4); - System.String geoURIWithoutQuery = queryStart < 0?rawText.Substring(4):rawText.Substring(4, (queryStart) - (4)); - int latitudeEnd = geoURIWithoutQuery.IndexOf(','); - if (latitudeEnd < 0) - { - return null; - } - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int longitudeEnd = geoURIWithoutQuery.IndexOf(',', latitudeEnd + 1); - double latitude, longitude, altitude; - try - { - latitude = System.Double.Parse(geoURIWithoutQuery.Substring(0, (latitudeEnd) - (0))); - if (longitudeEnd < 0) - { - longitude = System.Double.Parse(geoURIWithoutQuery.Substring(latitudeEnd + 1)); - altitude = 0.0; - } - else - { - longitude = System.Double.Parse(geoURIWithoutQuery.Substring(latitudeEnd + 1, (longitudeEnd) - (latitudeEnd + 1))); - altitude = System.Double.Parse(geoURIWithoutQuery.Substring(longitudeEnd + 1)); - } - } - catch (System.FormatException) - { - return null; - } - return new GeoParsedResult(rawText.StartsWith("GEO:")?"geo:" + rawText.Substring(4):rawText, latitude, longitude, altitude); + } } + catch (FormatException nfe) + { + return null; + } + return new GeoParsedResult(latitude, longitude, altitude, query); + } + } -} +} \ No newline at end of file diff --git a/csharp/client/result/ISBNParsedResult.cs b/csharp/client/result/ISBNParsedResult.cs index 75b5f8bd2..6e467c3bf 100755 --- a/csharp/client/result/ISBNParsedResult.cs +++ b/csharp/client/result/ISBNParsedResult.cs @@ -1,51 +1,51 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// jbreiden@google.com (Jeff Breidenbach) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class ISBNParsedResult:ParsedResult + + /// + /// @author jbreiden@google.com (Jeff Breidenbach) + /// + public sealed class ISBNParsedResult : ParsedResult { - public System.String ISBN - { - get - { - return isbn; - } - - } - override public System.String DisplayResult - { - get - { - return isbn; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'isbn '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String isbn; - - internal ISBNParsedResult(System.String isbn):base(ParsedResultType.ISBN) - { - this.isbn = isbn; - } + + private readonly string isbn; + + internal ISBNParsedResult(string isbn) : base(ParsedResultType.ISBN) + { + this.isbn = isbn; + } + + public string ISBN + { + get + { + return isbn; + } + } + + public override string DisplayResult + { + get + { + return isbn; + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/ISBNResultParser.cs b/csharp/client/result/ISBNResultParser.cs index 54f26d661..aa6249f26 100755 --- a/csharp/client/result/ISBNResultParser.cs +++ b/csharp/client/result/ISBNResultParser.cs @@ -1,63 +1,57 @@ /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Parses strings of digits that represent a ISBN. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using Result = com.google.zxing.Result; + + /// + /// Parses strings of digits that represent a ISBN. /// + /// @author jbreiden@google.com (Jeff Breidenbach) /// - /// jbreiden@google.com (Jeff Breidenbach) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public class ISBNResultParser:ResultParser + public sealed class ISBNResultParser : ResultParser { - - private ISBNResultParser() + + /// + /// See ISBN-13 For Dummies + /// + public override ParsedResult parse(Result result) + { + BarcodeFormat format = result.BarcodeFormat; + if (format != BarcodeFormat.EAN_13) { + return null; } - - // ISBN-13 For Dummies - // http://www.bisg.org/isbn-13/for.dummies.html - public static ISBNParsedResult parse(Result result) + string rawText = getMassagedText(result); + int length = rawText.Length; + if (length != 13) { - BarcodeFormat format = result.BarcodeFormat; - if (!BarcodeFormat.EAN_13.Equals(format)) - { - return null; - } - System.String rawText = result.Text; - if (rawText == null) - { - return null; - } - int length = rawText.Length; - if (length != 13) - { - return null; - } - if (!rawText.StartsWith("978") && !rawText.StartsWith("979")) - { - return null; - } - - return new ISBNParsedResult(rawText); + return null; } + if (!rawText.StartsWith("978") && !rawText.StartsWith("979")) + { + return null; + } + + return new ISBNParsedResult(rawText); + } + } + } \ No newline at end of file diff --git a/csharp/client/result/ParsedResult.cs b/csharp/client/result/ParsedResult.cs index 5c522d669..103b18f35 100755 --- a/csharp/client/result/ParsedResult.cs +++ b/csharp/client/result/ParsedResult.cs @@ -1,90 +1,91 @@ +using System.Text; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - ///

Abstract class representing the result of decoding a barcode, as more than + + ///

+ ///

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 + /// a URL, or an e-mail address. will turn a raw /// decoded string into the most appropriate type of structured representation.

/// ///

Thanks to Jeff Griffin for proposing rewrite of these classes that relies less /// on exception-based mechanisms during parsing.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public abstract class ParsedResult { - virtual public ParsedResultType Type + + private readonly ParsedResultType type; + + protected internal ParsedResult(ParsedResultType type) + { + this.type = type; + } + + public ParsedResultType Type + { + get + { + return type; + } + } + + public abstract string DisplayResult {get;} + + public override string ToString() + { + return DisplayResult; + } + + public static void maybeAppend(string value, StringBuilder result) + { + if (value != null && value.Length > 0) { - get + // Don't add a newline before the first value + if (result.Length > 0) + { + result.Append('\n'); + } + result.Append(value); + } + } + + public static void maybeAppend(string[] value, StringBuilder result) + { + if (value != null) + { + foreach (string s in value) + { + if (s != null && s.Length > 0) { - return type; - } - - } - public abstract System.String DisplayResult{get;} - - //UPGRADE_NOTE: Final was removed from the declaration of 'type '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ParsedResultType type; - - protected internal ParsedResult(ParsedResultType type) - { - this.type = type; - } - - public override System.String ToString() - { - return DisplayResult; - } - - public static void maybeAppend(System.String value_Renamed, System.Text.StringBuilder result) - { - if (value_Renamed != null && value_Renamed.Length > 0) - { - // Don't add a newline before the first value - if (result.Length > 0) - { - result.Append('\n'); - } - result.Append(value_Renamed); - } - } - - public static void maybeAppend(System.String[] value_Renamed, System.Text.StringBuilder result) - { - if (value_Renamed != null) - { - for (int i = 0; i < value_Renamed.Length; i++) - { - if (value_Renamed[i] != null && value_Renamed[i].Length > 0) - { - if (result.Length > 0) - { - result.Append('\n'); - } - result.Append(value_Renamed[i]); - } - } + if (result.Length > 0) + { + result.Append('\n'); + } + result.Append(s); } + } } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/ParsedResultType.cs b/csharp/client/result/ParsedResultType.cs index fd962b58f..5aa3e97af 100755 --- a/csharp/client/result/ParsedResultType.cs +++ b/csharp/client/result/ParsedResultType.cs @@ -1,72 +1,43 @@ /* -* 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. -*/ -using System; + * Copyright 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + namespace com.google.zxing.client.result { - - /// Represents the type of data encoded by a barcode -- from plain text, to a + + /// + /// Represents the type of data encoded by a barcode -- from plain text, to a /// URI, to an e-mail address, etc. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class ParsedResultType + public enum ParsedResultType { - - //UPGRADE_NOTE: Final was removed from the declaration of 'ADDRESSBOOK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType ADDRESSBOOK = new ParsedResultType("ADDRESSBOOK"); - //UPGRADE_NOTE: Final was removed from the declaration of 'EMAIL_ADDRESS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType EMAIL_ADDRESS = new ParsedResultType("EMAIL_ADDRESS"); - //UPGRADE_NOTE: Final was removed from the declaration of 'PRODUCT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType PRODUCT = new ParsedResultType("PRODUCT"); - //UPGRADE_NOTE: Final was removed from the declaration of 'URI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType URI = new ParsedResultType("URI"); - //UPGRADE_NOTE: Final was removed from the declaration of 'TEXT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType TEXT = new ParsedResultType("TEXT"); - //UPGRADE_NOTE: Final was removed from the declaration of 'ANDROID_INTENT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType ANDROID_INTENT = new ParsedResultType("ANDROID_INTENT"); - //UPGRADE_NOTE: Final was removed from the declaration of 'GEO '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType GEO = new ParsedResultType("GEO"); - //UPGRADE_NOTE: Final was removed from the declaration of 'TEL '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType TEL = new ParsedResultType("TEL"); - //UPGRADE_NOTE: Final was removed from the declaration of 'SMS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType SMS = new ParsedResultType("SMS"); - //UPGRADE_NOTE: Final was removed from the declaration of 'CALENDAR '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType CALENDAR = new ParsedResultType("CALENDAR"); - // "optional" types - //UPGRADE_NOTE: Final was removed from the declaration of 'NDEF_SMART_POSTER '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType NDEF_SMART_POSTER = new ParsedResultType("NDEF_SMART_POSTER"); - //UPGRADE_NOTE: Final was removed from the declaration of 'MOBILETAG_RICH_WEB '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType MOBILETAG_RICH_WEB = new ParsedResultType("MOBILETAG_RICH_WEB"); - //UPGRADE_NOTE: Final was removed from the declaration of 'ISBN '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ParsedResultType ISBN = new ParsedResultType("ISBN"); - - //UPGRADE_NOTE: Final was removed from the declaration of 'name '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String name; - - private ParsedResultType(System.String name) - { - this.name = name; - } - - public override System.String ToString() - { - return name; - } + + ADDRESSBOOK, + EMAIL_ADDRESS, + PRODUCT, + URI, + TEXT, + GEO, + TEL, + SMS, + CALENDAR, + WIFI, + ISBN, + } + } \ No newline at end of file diff --git a/csharp/client/result/ProductParsedResult.cs b/csharp/client/result/ProductParsedResult.cs index 3781f9308..758b763e8 100755 --- a/csharp/client/result/ProductParsedResult.cs +++ b/csharp/client/result/ProductParsedResult.cs @@ -1,66 +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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class ProductParsedResult:ParsedResult + + /// + /// @author dswitkin@google.com (Daniel Switkin) + /// + public sealed class ProductParsedResult : ParsedResult { - public System.String ProductID - { - get - { - return productID; - } - - } - public System.String NormalizedProductID - { - get - { - return normalizedProductID; - } - - } - override public System.String DisplayResult - { - get - { - return productID; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'productID '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String productID; - //UPGRADE_NOTE: Final was removed from the declaration of 'normalizedProductID '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String normalizedProductID; - - internal ProductParsedResult(System.String productID):this(productID, productID) - { - } - - internal ProductParsedResult(System.String productID, System.String normalizedProductID):base(ParsedResultType.PRODUCT) - { - this.productID = productID; - this.normalizedProductID = normalizedProductID; - } + + private readonly string productID; + private readonly string normalizedProductID; + + internal ProductParsedResult(string productID) : this(productID, productID) + { + } + + internal ProductParsedResult(string productID, string normalizedProductID) : base(ParsedResultType.PRODUCT) + { + this.productID = productID; + this.normalizedProductID = normalizedProductID; + } + + public string ProductID + { + get + { + return productID; + } + } + + public string NormalizedProductID + { + get + { + return normalizedProductID; + } + } + + public override string DisplayResult + { + get + { + return productID; + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/ProductResultParser.cs b/csharp/client/result/ProductResultParser.cs index 8a8092863..123842975 100755 --- a/csharp/client/result/ProductResultParser.cs +++ b/csharp/client/result/ProductResultParser.cs @@ -1,77 +1,67 @@ /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using Result = com.google.zxing.Result; -using UPCEReader = com.google.zxing.oned.UPCEReader; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Parses strings of digits that represent a UPC code. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using Result = com.google.zxing.Result; + using UPCEReader = com.google.zxing.oned.UPCEReader; + + /// + /// Parses strings of digits that represent a UPC code. /// + /// @author dswitkin@google.com (Daniel Switkin) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class ProductResultParser:ResultParser + public sealed class ProductResultParser : ResultParser { - - private ProductResultParser() + + // Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes. + public override ParsedResult parse(Result result) + { + BarcodeFormat format = result.BarcodeFormat; + if (!(format == BarcodeFormat.UPC_A || format == BarcodeFormat.UPC_E || format == BarcodeFormat.EAN_8 || format == BarcodeFormat.EAN_13)) { + return null; } - - // Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes. - public static ProductParsedResult parse(Result result) + string rawText = getMassagedText(result); + int length = rawText.Length; + for (int x = 0; x < length; x++) { - BarcodeFormat format = result.BarcodeFormat; - if (!(BarcodeFormat.UPC_A.Equals(format) || BarcodeFormat.UPC_E.Equals(format) || BarcodeFormat.EAN_8.Equals(format) || BarcodeFormat.EAN_13.Equals(format))) - { - return null; - } - // Really neither of these should happen: - System.String rawText = result.Text; - if (rawText == null) - { - return null; - } - - int length = rawText.Length; - for (int x = 0; x < length; x++) - { - char c = rawText[x]; - if (c < '0' || c > '9') - { - return null; - } - } - // Not actually checking the checksum again here - - System.String normalizedProductID; - // Expand UPC-E for purposes of searching - if (BarcodeFormat.UPC_E.Equals(format)) - { - normalizedProductID = UPCEReader.convertUPCEtoUPCA(rawText); - } - else - { - normalizedProductID = rawText; - } - - return new ProductParsedResult(rawText, normalizedProductID); + char c = rawText[x]; + if (c < '0' || c > '9') + { + return null; + } } + // Not actually checking the checksum again here + + string normalizedProductID; + // Expand UPC-E for purposes of searching + if (format == BarcodeFormat.UPC_E) + { + normalizedProductID = UPCEReader.convertUPCEtoUPCA(rawText); + } + else + { + normalizedProductID = rawText; + } + + return new ProductParsedResult(rawText, normalizedProductID); + } + } } \ No newline at end of file diff --git a/csharp/client/result/ResultParser.cs b/csharp/client/result/ResultParser.cs index 567df9b64..218daf46c 100755 --- a/csharp/client/result/ResultParser.cs +++ b/csharp/client/result/ResultParser.cs @@ -1,371 +1,282 @@ -/* -* 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. -*/ using System; -using Result = com.google.zxing.Result; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.client.result { - - ///

Abstract class representing the result of decoding a barcode, as more than + + using Result = com.google.zxing.Result; + using System.Text.RegularExpressions; + + + ///

+ ///

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 + /// a URL, or an e-mail address. will turn a raw /// decoded string into the most appropriate type of structured representation.

/// ///

Thanks to Jeff Griffin for proposing rewrite of these classes that relies less /// on exception-based mechanisms during parsing.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public abstract class ResultParser { - - public static ParsedResult parseResult(Result theResult) + + private static readonly ResultParser[] PARSERS = {new BookmarkDoCoMoResultParser(), new AddressBookDoCoMoResultParser(), new EmailDoCoMoResultParser(), new AddressBookAUResultParser(), new VCardResultParser(), new BizcardResultParser(), new VEventResultParser(), new EmailAddressResultParser(), new SMTPResultParser(), new TelResultParser(), new SMSMMSResultParser(), new SMSTOMMSTOResultParser(), new GeoResultParser(), new WifiResultParser(), new URLTOResultParser(), new URIResultParser(), new ISBNResultParser(), new ProductResultParser(), new ExpandedProductResultParser()}; + + private static readonly string DIGITS = "\\d*"; + private static readonly string ALPHANUM = "[a-zA-Z0-9]*"; + private static readonly string AMPERSAND = "&"; + private static readonly string EQUALS = "="; + private const string BYTE_ORDER_MARK = "\ufeff"; + + /// + /// Attempts to parse the raw 's contents as a particular type + /// of information (email, URL, etc.) and return a encapsulating + /// the result of parsing. + /// + public abstract ParsedResult parse(Result theResult); + + protected internal static string getMassagedText(Result result) + { + string text = result.Text; + if (text.StartsWith(BYTE_ORDER_MARK)) { - // Simplification of original if - if else logic using Null Coalescing operator ?? - // - // ?? Simply checks from left to right for a non null object - // when an object evaluates to null the next object after the ?? is evaluated - // This continues until a non null value is found or the last object is evaluated - return - BookmarkDoCoMoResultParser.parse(theResult) as ParsedResult ?? - AddressBookDoCoMoResultParser.parse(theResult) as ParsedResult ?? - EmailDoCoMoResultParser.parse(theResult) as ParsedResult ?? - AddressBookAUResultParser.parse(theResult) as ParsedResult ?? - VCardResultParser.parse(theResult) as ParsedResult ?? - BizcardResultParser.parse(theResult) as ParsedResult ?? - VEventResultParser.parse(theResult) as ParsedResult ?? - EmailAddressResultParser.parse(theResult) as ParsedResult ?? - TelResultParser.parse(theResult) as ParsedResult ?? - SMSMMSResultParser.parse(theResult) as ParsedResult ?? - GeoResultParser.parse(theResult) as ParsedResult ?? - URLTOResultParser.parse(theResult) as ParsedResult ?? - URIResultParser.parse(theResult) as ParsedResult ?? - ISBNResultParser.parse(theResult) as ParsedResult ?? - ProductResultParser.parse(theResult) as ParsedResult ?? - new TextParsedResult(theResult.Text, null) as ParsedResult; + text = text.Substring(1); } - - protected internal static void maybeAppend(System.String value_Renamed, System.Text.StringBuilder result) + return text; + } + + public static ParsedResult parseResult(Result theResult) + { + foreach (ResultParser parser in PARSERS) { - if (value_Renamed != null) - { - result.Append('\n'); - result.Append(value_Renamed); - } - } - - protected internal static void maybeAppend(System.String[] value_Renamed, System.Text.StringBuilder result) - { - if (value_Renamed != null) - { - for (int i = 0; i < value_Renamed.Length; i++) - { - result.Append('\n'); - result.Append(value_Renamed[i]); - } - } - } - - protected internal static System.String[] maybeWrap(System.String value_Renamed) - { - return value_Renamed == null?null:new System.String[]{value_Renamed}; - } - - protected internal static System.String unescapeBackslash(System.String escaped) - { - if (escaped != null) - { - int backslash = escaped.IndexOf('\\'); - if (backslash >= 0) - { - int max = escaped.Length; - System.Text.StringBuilder unescaped = new System.Text.StringBuilder(max - 1); - unescaped.Append(escaped.ToCharArray(), 0, backslash); - bool nextIsEscaped = false; - for (int i = backslash; i < max; i++) - { - char c = escaped[i]; - if (nextIsEscaped || c != '\\') - { - unescaped.Append(c); - nextIsEscaped = false; - } - else - { - nextIsEscaped = true; - } - } - return unescaped.ToString(); - } - } - return escaped; - } - - private static System.String urlDecode(System.String escaped) - { - - // No we can't use java.net.URLDecoder here. JavaME doesn't have it. - if (escaped == null) - { - return null; - } - char[] escapedArray = escaped.ToCharArray(); - - int first = findFirstEscape(escapedArray); - if (first < 0) - { - return escaped; - } - - int max = escapedArray.Length; - // final length is at most 2 less than original due to at least 1 unescaping - System.Text.StringBuilder unescaped = new System.Text.StringBuilder(max - 2); - // Can append everything up to first escape character - unescaped.Append(escapedArray, 0, first); - - for (int i = first; i < max; i++) - { - char c = 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 - { - int firstDigitValue = parseHexDigit(escapedArray[++i]); - int secondDigitValue = 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((char) ((firstDigitValue << 4) + secondDigitValue)); - } - } - else - { - unescaped.Append(c); - } - } - return unescaped.ToString(); - } - - private static int findFirstEscape(char[] escapedArray) - { - int max = escapedArray.Length; - for (int i = 0; i < max; i++) - { - char c = escapedArray[i]; - if (c == '+' || c == '%') - { - return i; - } - } - return - 1; - } - - private static int parseHexDigit(char c) - { - if (c >= 'a') - { - if (c <= 'f') - { - return 10 + (c - 'a'); - } - } - else if (c >= 'A') - { - if (c <= 'F') - { - return 10 + (c - 'A'); - } - } - else if (c >= '0') - { - if (c <= '9') - { - return c - '0'; - } - } - return - 1; - } - - protected internal static bool isStringOfDigits(System.String value_Renamed, int length) - { - if (value_Renamed == null) - { - return false; - } - int stringLength = value_Renamed.Length; - if (length != stringLength) - { - return false; - } - for (int i = 0; i < length; i++) - { - char c = value_Renamed[i]; - if (c < '0' || c > '9') - { - return false; - } - } - return true; - } - - protected internal static bool isSubstringOfDigits(System.String value_Renamed, int offset, int length) - { - if (value_Renamed == null) - { - return false; - } - int stringLength = value_Renamed.Length; - int max = offset + length; - if (stringLength < max) - { - return false; - } - for (int i = offset; i < max; i++) - { - char c = value_Renamed[i]; - if (c < '0' || c > '9') - { - return false; - } - } - return true; - } - - internal static System.Collections.Hashtable parseNameValuePairs(System.String uri) - { - int paramStart = uri.IndexOf('?'); - if (paramStart < 0) - { - return null; - } - System.Collections.Hashtable result = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(3)); - paramStart++; - int paramEnd; - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - while ((paramEnd = uri.IndexOf('&', paramStart)) >= 0) - { - appendKeyValue(uri, paramStart, paramEnd, result); - paramStart = paramEnd + 1; - } - appendKeyValue(uri, paramStart, uri.Length, result); + ParsedResult result = parser.parse(theResult); + if (result != null) + { return result; + } } - - private static void appendKeyValue(System.String uri, int paramStart, int paramEnd, System.Collections.Hashtable result) + return new TextParsedResult(theResult.Text, null); + } + + protected internal static void maybeAppend(string value, StringBuilder result) + { + if (value != null) { - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int separator = uri.IndexOf('=', paramStart); - if (separator >= 0) - { - // key = value - System.String key = uri.Substring(paramStart, (separator) - (paramStart)); - System.String value_Renamed = uri.Substring(separator + 1, (paramEnd) - (separator + 1)); - value_Renamed = urlDecode(value_Renamed); - result[key] = value_Renamed; - } - // Can't put key, null into a hashtable + result.Append('\n'); + result.Append(value); } - - internal static System.String[] matchPrefixedField(System.String prefix, System.String rawText, char endChar, bool trim) + } + + protected internal static void maybeAppend(string[] value, StringBuilder result) + { + if (value != null) { - System.Collections.ArrayList matches = null; - int i = 0; - int max = rawText.Length; - while (i < max) - { - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - i = rawText.IndexOf(prefix, i); - if (i < 0) - { - break; - } - i += prefix.Length; // Skip past this prefix we found to start - int start = i; // Found the start of a match here - bool done = false; - while (!done) - { - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - i = rawText.IndexOf((System.Char) 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[i - 1] == '\\') - { - // semicolon was escaped so continue - i++; - } - else - { - // found a match - if (matches == null) - { - matches = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(3)); // lazy init - } - System.String element = unescapeBackslash(rawText.Substring(start, (i) - (start))); - if (trim) - { - element = element.Trim(); - } - matches.Add(element); - i++; - done = true; - } - } - } - if (matches == null || (matches.Count == 0)) - { - return null; - } - return toStringArray(matches); + foreach (string s in value) + { + result.Append('\n'); + result.Append(s); + } } - - internal static System.String matchSinglePrefixedField(System.String prefix, System.String rawText, char endChar, bool trim) + } + + protected internal static string[] maybeWrap(string value) + { + return value == null ? null : new string[] {value}; + } + + protected internal static string unescapeBackslash(string escaped) + { + int backslash = (int) escaped.IndexOf('\\'); + if (backslash < 0) { - System.String[] matches = matchPrefixedField(prefix, rawText, endChar, trim); - return matches == null?null:matches[0]; + return escaped; } - - internal static System.String[] toStringArray(System.Collections.ArrayList strings) + int max = escaped.Length; + StringBuilder unescaped = new StringBuilder(max - 1); + unescaped.Append(escaped.ToCharArray(), 0, backslash); + bool nextIsEscaped = false; + for (int i = backslash; i < max; i++) { - int size = strings.Count; - System.String[] result = new System.String[size]; - for (int j = 0; j < size; j++) - { - result[j] = ((System.String) strings[j]); - } - return result; + char c = escaped[i]; + if (nextIsEscaped || c != '\\') + { + unescaped.Append(c); + nextIsEscaped = false; + } + else + { + nextIsEscaped = true; + } } + return unescaped.ToString(); + } + + protected internal static int parseHexDigit(char c) + { + if (c >= '0' && c <= '9') + { + return c - '0'; + } + if (c >= 'a' && c <= 'f') + { + return 10 + (c - 'a'); + } + if (c >= 'A' && c <= 'F') + { + return 10 + (c - 'A'); + } + return -1; + } + + protected internal static bool isStringOfDigits(string value, int length) + { + //return value != null && length == value.Length && DIGITS.matcher(value).matches(); + + return value != null && length == value.Length && new Regex(DIGITS).IsMatch(value); + } + + protected internal static bool isSubstringOfDigits(string value, int offset, int length) + { + if (value == null) + { + return false; + } + int max = offset + length; + string s = value.Substring(offset, length); + return isStringOfDigits(s, length); + //return value.Length >= max && DIGITS.matcher(value.subSequence(offset, max)).matches(); + } + + protected internal static bool isSubstringOfAlphaNumeric(string value, int offset, int length) + { + if (value == null) + { + return false; + } + int max = offset + length; + string s = value.Substring(offset, length); + return length == s.Length && new Regex(ALPHANUM).IsMatch(s); + //return value.Length >= max && ALPHANUM.matcher(value.subSequence(offset, max)).matches(); + } + + internal static IDictionary parseNameValuePairs(string uri) + { + int paramStart = uri.IndexOf('?'); + if (paramStart < 0) + { + return null; + } + IDictionary result = new Dictionary(3); + foreach (string keyValue in AMPERSAND.Split(new string[] {uri.Substring(paramStart + 1)},StringSplitOptions.None)) + { + appendKeyValue(keyValue, result); + } + return result; + } + + private static void appendKeyValue(string keyValue, IDictionary result) + { + string[] keyValueTokens = EQUALS.Split(new string[] {keyValue}, 2,StringSplitOptions.None); + if (keyValueTokens.Length == 2) + { + string key = keyValueTokens[0]; + string value = keyValueTokens[1]; + try + { + //value = URLDecoder.decode(value, "UTF-8"); + value = System.Web.HttpUtility.UrlDecode(value,Encoding.UTF8); + result[key] = value; + } + //catch (UnsupportedEncodingException uee) + //{ + // throw new IllegalStateException(uee); // can't happen + //} + catch (System.ArgumentException iae) + { + // continue; invalid data such as an escape like %0t + } + } + } + + internal static string[] matchPrefixedField(string prefix, string rawText, char endChar, bool trim) + { + List matches = null; + int i = 0; + int max = 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 + int start = i; // Found the start of a match here + bool more = true; + while (more) + { + i = (int)rawText.IndexOf( endChar, i); + if (i < 0) + { + // No terminating end character? uh, done. Set i such that loop terminates and break + i = rawText.Length; + more = false; + } + else if (rawText[i - 1] == '\\') + { + // semicolon was escaped so continue + i++; + } + else + { + // found a match + if (matches == null) + { + matches = new List(3); // lazy init + } + string element = unescapeBackslash(rawText.Substring(start, i - start)); + if (trim) + { + element = element.Trim(); + } + matches.Add(element); + i++; + more = false; + } + } + } + if (matches == null || matches.Count == 0) + { + return null; + } + return matches.ToArray(); + } + + internal static string matchSinglePrefixedField(string prefix, string rawText, char endChar, bool trim) + { + string[] matches = matchPrefixedField(prefix, rawText, endChar, trim); + return matches == null ? null : matches[0]; + } + } + } \ No newline at end of file diff --git a/csharp/client/result/SMSMMSResultParser.cs b/csharp/client/result/SMSMMSResultParser.cs index 3719e118d..ecc7ecdd8 100755 --- a/csharp/client/result/SMSMMSResultParser.cs +++ b/csharp/client/result/SMSMMSResultParser.cs @@ -1,123 +1,117 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - ///

Parses an "sms:" URI result, which specifies a number to SMS and optional - /// "via" number. See - /// the IETF draft on this.

+ + using Result = com.google.zxing.Result; + + + /// + ///

Parses an "sms:" URI result, which specifies a number to SMS. + /// See RFC 5724 on this.

/// - ///

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.

+ ///

This class supports "via" syntax for numbers, which is not part of the spec. + /// For example "+12125551212;via=+12124440101" may appear as a number. + /// It also supports a "subject" query parameter, which is not mentioned in the spec. + /// These are included since they were mentioned in earlier IETF drafts and might be + /// used.

/// + ///

This actually also parses URIs starting with "mms:" and treats them all the same way, + /// and effectively converts them to an "sms:" URI for purposes of forwarding to the platform.

+ /// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class SMSMMSResultParser:ResultParser + public sealed class SMSMMSResultParser : ResultParser { - - private SMSMMSResultParser() + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!(rawText.StartsWith("sms:") || rawText.StartsWith("SMS:") || rawText.StartsWith("mms:") || rawText.StartsWith("MMS:"))) { + return null; } - - public static SMSParsedResult parse(Result result) + + // Check up front if this is a URI syntax string with query arguments + IDictionary nameValuePairs = parseNameValuePairs(rawText); + string subject = null; + string body = null; + bool querySyntax = false; + if (nameValuePairs != null && nameValuePairs.Count > 0) { - System.String rawText = result.Text; - if (rawText == null) - { - return null; - } - int prefixLength; - if (rawText.StartsWith("sms:") || rawText.StartsWith("SMS:") || rawText.StartsWith("mms:") || rawText.StartsWith("MMS:")) - { - prefixLength = 4; - } - else if (rawText.StartsWith("smsto:") || rawText.StartsWith("SMSTO:") || rawText.StartsWith("mmsto:") || rawText.StartsWith("MMSTO:")) - { - prefixLength = 6; - } - else - { - return null; - } - - // Check up front if this is a URI syntax string with query arguments - System.Collections.Hashtable nameValuePairs = parseNameValuePairs(rawText); - System.String subject = null; - System.String body = null; - bool querySyntax = false; - if (nameValuePairs != null && !(nameValuePairs.Count == 0)) - { - subject = ((System.String) nameValuePairs["subject"]); - body = ((System.String) nameValuePairs["body"]); - querySyntax = true; - } - - // Drop sms, query portion - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int queryStart = rawText.IndexOf('?', prefixLength); - System.String smsURIWithoutQuery; - // 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) - (prefixLength)); - } - int numberEnd = smsURIWithoutQuery.IndexOf(';'); - System.String number; - System.String via; - if (numberEnd < 0) - { - number = smsURIWithoutQuery; - via = null; - } - else - { - number = smsURIWithoutQuery.Substring(0, (numberEnd) - (0)); - System.String maybeVia = smsURIWithoutQuery.Substring(numberEnd + 1); - if (maybeVia.StartsWith("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) - { - int bodyStart = number.IndexOf(':'); - if (bodyStart >= 0) - { - body = number.Substring(bodyStart + 1); - number = number.Substring(0, (bodyStart) - (0)); - } - } - return new SMSParsedResult("sms:" + number, number, via, subject, body, null); + subject = nameValuePairs["subject"]; + body = nameValuePairs["body"]; + querySyntax = true; } + + // Drop sms, query portion + int queryStart = rawText.IndexOf('?', 4); + string smsURIWithoutQuery; + // If it's not query syntax, the question mark is part of the subject or message + if (queryStart < 0 || !querySyntax) + { + smsURIWithoutQuery = rawText.Substring(4); + } + else + { + smsURIWithoutQuery = rawText.Substring(4, queryStart - 4); + } + + int lastComma = -1; + int comma; + List numbers = new List(1); + List vias = new List(1); + while ((comma = smsURIWithoutQuery.IndexOf(',', lastComma + 1)) > lastComma) + { + string numberPart = smsURIWithoutQuery.Substring(lastComma + 1, comma - (lastComma + 1)); + addNumberVia(numbers, vias, numberPart); + lastComma = comma; + } + addNumberVia(numbers, vias, smsURIWithoutQuery.Substring(lastComma + 1)); + + return new SMSParsedResult(numbers.ToArray(), vias.ToArray(), subject, body); + } + + private static void addNumberVia(ICollection numbers, ICollection vias, string numberPart) + { + int numberEnd = numberPart.IndexOf(';'); + if (numberEnd < 0) + { + numbers.Add(numberPart); + vias.Add(null); + } + else + { + numbers.Add(numberPart.Substring(0, numberEnd)); + string maybeVia = numberPart.Substring(numberEnd + 1); + string via; + if (maybeVia.StartsWith("via=")) + { + via = maybeVia.Substring(4); + } + else + { + via = null; + } + vias.Add(via); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/SMSParsedResult.cs b/csharp/client/result/SMSParsedResult.cs index c42eb2858..8cd1cb6a5 100755 --- a/csharp/client/result/SMSParsedResult.cs +++ b/csharp/client/result/SMSParsedResult.cs @@ -1,112 +1,142 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class SMSParsedResult:ParsedResult + + /// + /// @author Sean Owen + /// + public sealed class SMSParsedResult : ParsedResult { - public System.String SMSURI - { - get + + private readonly string[] numbers; + private readonly string[] vias; + private readonly string subject; + private readonly string body; + + public SMSParsedResult(string number, string via, string subject, string body) : base(ParsedResultType.SMS) + { + this.numbers = new string[] {number}; + this.vias = new string[] {via}; + this.subject = subject; + this.body = body; + } + + public SMSParsedResult(string[] numbers, string[] vias, string subject, string body) : base(ParsedResultType.SMS) + { + this.numbers = numbers; + this.vias = vias; + this.subject = subject; + this.body = body; + } + + public string SMSURI + { + get + { + StringBuilder result = new StringBuilder(); + result.Append("sms:"); + bool first = true; + for (int i = 0; i < numbers.Length; i++) { - return smsURI; + if (first) + { + first = false; + } + else + { + result.Append(','); + } + result.Append(numbers[i]); + if (vias != null && vias[i] != null) + { + result.Append(";via="); + result.Append(vias[i]); + } } - - } - public System.String Number - { - get + bool hasBody = body != null; + bool hasSubject = subject != null; + if (hasBody || hasSubject) { - return number; + result.Append('?'); + if (hasBody) + { + result.Append("body="); + result.Append(body); + } + if (hasSubject) + { + if (hasBody) + { + result.Append('&'); + } + result.Append("subject="); + result.Append(subject); + } } - - } - public System.String Via - { - get - { - return via; - } - - } - public System.String Subject - { - get - { - return subject; - } - - } - public System.String Body - { - get - { - return body; - } - - } - public System.String Title - { - get - { - return title; - } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(100); - maybeAppend(number, result); - maybeAppend(via, result); - maybeAppend(subject, result); - maybeAppend(body, result); - maybeAppend(title, result); - return result.ToString(); - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'smsURI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String smsURI; - //UPGRADE_NOTE: Final was removed from the declaration of 'number '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String number; - //UPGRADE_NOTE: Final was removed from the declaration of 'via '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String via; - //UPGRADE_NOTE: Final was removed from the declaration of 'subject '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String subject; - //UPGRADE_NOTE: Final was removed from the declaration of 'body '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String body; - //UPGRADE_NOTE: Final was removed from the declaration of 'title '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String title; - - public SMSParsedResult(System.String smsURI, System.String number, System.String via, System.String subject, System.String body, System.String title):base(ParsedResultType.SMS) - { - this.smsURI = smsURI; - this.number = number; - this.via = via; - this.subject = subject; - this.body = body; - this.title = title; - } + return result.ToString(); + } + } + + public string[] Numbers + { + get + { + return numbers; + } + } + + public string[] Vias + { + get + { + return vias; + } + } + + public string Subject + { + get + { + return subject; + } + } + + public string Body + { + get + { + return body; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(100); + maybeAppend(numbers, result); + maybeAppend(subject, result); + maybeAppend(body, result); + return result.ToString(); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/TelParsedResult.cs b/csharp/client/result/TelParsedResult.cs index 6c00ed40b..af017bebb 100755 --- a/csharp/client/result/TelParsedResult.cs +++ b/csharp/client/result/TelParsedResult.cs @@ -1,76 +1,75 @@ +using System.Text; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class TelParsedResult:ParsedResult + + /// + /// @author Sean Owen + /// + public sealed class TelParsedResult : ParsedResult { - public System.String Number - { - get - { - return number; - } - - } - public System.String TelURI - { - get - { - return telURI; - } - - } - public System.String Title - { - get - { - return title; - } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(20); - maybeAppend(number, result); - maybeAppend(title, result); - return result.ToString(); - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'number '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String number; - //UPGRADE_NOTE: Final was removed from the declaration of 'telURI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String telURI; - //UPGRADE_NOTE: Final was removed from the declaration of 'title '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String title; - - public TelParsedResult(System.String number, System.String telURI, System.String title):base(ParsedResultType.TEL) - { - this.number = number; - this.telURI = telURI; - this.title = title; - } + + private readonly string number; + private readonly string telURI; + private readonly string title; + + public TelParsedResult(string number, string telURI, string title) : base(ParsedResultType.TEL) + { + this.number = number; + this.telURI = telURI; + this.title = title; + } + + public string Number + { + get + { + return number; + } + } + + public string TelURI + { + get + { + return telURI; + } + } + + public string Title + { + get + { + return title; + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(20); + maybeAppend(number, result); + maybeAppend(title, result); + return result.ToString(); + } + } + } } \ No newline at end of file diff --git a/csharp/client/result/TelResultParser.cs b/csharp/client/result/TelResultParser.cs index 0a472dba5..39abb832a 100755 --- a/csharp/client/result/TelResultParser.cs +++ b/csharp/client/result/TelResultParser.cs @@ -1,51 +1,46 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Parses a "tel:" URI result, which specifies a phone number. + + using Result = com.google.zxing.Result; + + /// + /// Parses a "tel:" URI result, which specifies a phone number. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class TelResultParser:ResultParser + public sealed class TelResultParser : ResultParser { - - private TelResultParser() + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!rawText.StartsWith("tel:") && !rawText.StartsWith("TEL:")) { + return null; } - - public static TelParsedResult parse(Result result) - { - System.String rawText = result.Text; - if (rawText == null || (!rawText.StartsWith("tel:") && !rawText.StartsWith("TEL:"))) - { - return null; - } - // Normalize "TEL:" to "tel:" - System.String telURI = rawText.StartsWith("TEL:")?"tel:" + rawText.Substring(4):rawText; - // Drop tel, query portion - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int queryStart = rawText.IndexOf('?', 4); - System.String number = queryStart < 0?rawText.Substring(4):rawText.Substring(4, (queryStart) - (4)); - return new TelParsedResult(number, telURI, null); - } + // Normalize "TEL:" to "tel:" + string telURI = rawText.StartsWith("TEL:") ? "tel:" + rawText.Substring(4) : rawText; + // Drop tel, query portion + int queryStart = rawText.IndexOf('?', 4); + string number = queryStart < 0 ? rawText.Substring(4) : rawText.Substring(4, queryStart - 4); + return new TelParsedResult(number, telURI, null); + } + } } \ No newline at end of file diff --git a/csharp/client/result/TextParsedResult.cs b/csharp/client/result/TextParsedResult.cs index 806eb2c38..e9a6c07be 100755 --- a/csharp/client/result/TextParsedResult.cs +++ b/csharp/client/result/TextParsedResult.cs @@ -1,66 +1,64 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// A simple result type encapsulating a string that has no further + + /// + /// A simple result type encapsulating a string that has no further /// interpretation. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class TextParsedResult:ParsedResult + public sealed class TextParsedResult : ParsedResult { - public System.String Text - { - get - { - return text; - } - - } - public System.String Language - { - get - { - return language; - } - - } - override public System.String DisplayResult - { - get - { - return text; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'text '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String text; - //UPGRADE_NOTE: Final was removed from the declaration of 'language '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String language; - - public TextParsedResult(System.String text, System.String language):base(ParsedResultType.TEXT) - { - this.text = text; - this.language = language; - } + + private readonly string text; + private readonly string language; + + public TextParsedResult(string text, string language) : base(ParsedResultType.TEXT) + { + this.text = text; + this.language = language; + } + + public string Text + { + get + { + return text; + } + } + + public string Language + { + get + { + return language; + } + } + + public override string DisplayResult + { + get + { + return text; + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/URIParsedResult.cs b/csharp/client/result/URIParsedResult.cs index ea8cdffa5..6aadaa580 100755 --- a/csharp/client/result/URIParsedResult.cs +++ b/csharp/client/result/URIParsedResult.cs @@ -1,148 +1,127 @@ +using System.Text; +using System.Text.RegularExpressions; + /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.client.result { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class URIParsedResult:ParsedResult + + + /// + /// @author Sean Owen + /// + public sealed class URIParsedResult : ParsedResult { - public System.String URI - { - get - { - return uri; - } - - } - public System.String Title - { - get - { - return title; - } - - } - /// 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 bool PossiblyMaliciousURI - { - get - { - return containsUser(); - } - - } - override public System.String DisplayResult - { - get - { - System.Text.StringBuilder result = new System.Text.StringBuilder(30); - maybeAppend(title, result); - maybeAppend(uri, result); - return result.ToString(); - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'uri '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String uri; - //UPGRADE_NOTE: Final was removed from the declaration of 'title '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String title; - - public URIParsedResult(System.String uri, System.String title):base(ParsedResultType.URI) - { - this.uri = massageURI(uri); - this.title = title; - } - - private bool containsUser() - { - // This method is likely not 100% RFC compliant yet - int hostStart = uri.IndexOf(':'); // we should always have scheme at this point - hostStart++; - // Skip slashes preceding host - int uriLength = uri.Length; - while (hostStart < uriLength && uri[hostStart] == '/') - { - hostStart++; - } - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int hostEnd = uri.IndexOf('/', hostStart); - if (hostEnd < 0) - { - hostEnd = uriLength; - } - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int at = uri.IndexOf('@', hostStart); - return at >= hostStart && at < hostEnd; - } - - /// Transforms a string that represents a URI into something more proper, by adding or canonicalizing - /// the protocol. - /// - private static System.String massageURI(System.String uri) - { - int protocolEnd = 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) - (0)).ToLower() + uri.Substring(protocolEnd); - } + + private static readonly string USER_IN_HOST = ":/*([^/@]+)@[^/]+"; + + private readonly string uri; + private readonly string title; + + public URIParsedResult(string uri, string title) : base(ParsedResultType.URI) + { + this.uri = massageURI(uri); + this.title = title; + } + + public string URI + { + get + { return uri; - } - - private static bool isColonFollowedByPortNumber(System.String uri, int protocolEnd) + } + } + + public string Title + { + get + { + return title; + } + } + + /// 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 bool PossiblyMaliciousURI + { + get + { + //return USER_IN_HOST.matcher(uri).find(); + return new Regex(USER_IN_HOST).IsMatch(uri); + } + } + + public override string DisplayResult + { + get + { + StringBuilder result = new StringBuilder(30); + 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 string massageURI(string uri) + { + uri = uri.Trim(); + int protocolEnd = uri.IndexOf(':'); + if (protocolEnd < 0) { - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int nextSlash = uri.IndexOf('/', protocolEnd + 1); - if (nextSlash < 0) - { - nextSlash = uri.Length; - } - if (nextSlash <= protocolEnd + 1) - { - return false; - } - for (int x = protocolEnd + 1; x < nextSlash; x++) - { - if (uri[x] < '0' || uri[x] > '9') - { - return false; - } - } - return true; + // 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; + } + return uri; + } + + private static bool isColonFollowedByPortNumber(string uri, int protocolEnd) + { + int nextSlash = uri.IndexOf('/', protocolEnd + 1); + if (nextSlash < 0) + { + nextSlash = uri.Length; + } + if (nextSlash <= protocolEnd + 1) + { + return false; + } + for (int x = protocolEnd + 1; x < nextSlash; x++) + { + if (uri[x] < '0' || uri[x] > '9') + { + return false; + } + } + return true; + } + + } } \ No newline at end of file diff --git a/csharp/client/result/URIResultParser.cs b/csharp/client/result/URIResultParser.cs index 498513c76..0c97370aa 100755 --- a/csharp/client/result/URIResultParser.cs +++ b/csharp/client/result/URIResultParser.cs @@ -1,106 +1,62 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + +using System.Text.RegularExpressions; + namespace com.google.zxing.client.result { - - /// Tries to parse results that are a URI of some kind. + + using Result = com.google.zxing.Result; + + + /// + /// Tries to parse results that are a URI of some kind. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class URIResultParser:ResultParser + public sealed class URIResultParser : ResultParser { - - private URIResultParser() + + private const string ALPHANUM_PART = "[a-zA-Z0-9\\-]"; + private static readonly string URL_WITH_PROTOCOL_PATTERN = "[a-zA-Z0-9]{2,}:"; + private static readonly string URL_WITHOUT_PROTOCOL_PATTERN = '(' + ALPHANUM_PART + "+\\.)+" + ALPHANUM_PART + "{2,}" + "(:\\d{1,5})?" + "(/|\\?|$)"; // query, path or nothing - maybe port - host name elements + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + // We specifically handle the odd "URL" scheme here for simplicity and add "URI" for fun + // Assume anything starting this way really means to be a URI + if (rawText.StartsWith("URL:") || rawText.StartsWith("URI:")) { + return new URIParsedResult(rawText.Substring(4).Trim(), null); } - - public static URIParsedResult parse(Result result) + rawText = rawText.Trim(); + return isBasicallyValidURI(rawText) ? new URIParsedResult(rawText, null) : null; + } + + internal static bool isBasicallyValidURI(string uri) + { + Match m = Regex.Match(uri,URL_WITH_PROTOCOL_PATTERN) ; + if (m.Success && m.Index == 0) // match at start only { - System.String rawText = result.Text; - // We specifically handle the odd "URL" scheme here for simplicity - if (rawText != null && rawText.StartsWith("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. - /// - internal static bool isBasicallyValidURI(System.String uri) - { - if (uri == null || uri.IndexOf(' ') >= 0 || uri.IndexOf('\n') >= 0) - { - return false; - } - // Look for period in a domain but followed by at least a two-char TLD - // Forget strings that don't have a valid-looking protocol - int period = uri.IndexOf('.'); - if (period >= uri.Length - 2) - { - return false; - } - int colon = uri.IndexOf(':'); - if (period < 0 && colon < 0) - { - return false; - } - if (colon >= 0) - { - if (period < 0 || period > colon) - { - // colon ends the protocol - for (int i = 0; i < colon; i++) - { - char c = uri[i]; - if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) - { - return false; - } - } - } - else - { - // colon starts the port; crudely look for at least two numbers - if (colon >= uri.Length - 2) - { - return false; - } - for (int i = colon + 1; i < colon + 3; i++) - { - char c = uri[i]; - if (c < '0' || c > '9') - { - return false; - } - } - } - } - return true; + return true; } + m = Regex.Match(uri,URL_WITHOUT_PROTOCOL_PATTERN); + return m.Success && m.Index == 0; + } + } } \ No newline at end of file diff --git a/csharp/client/result/URLTOResultParser.cs b/csharp/client/result/URLTOResultParser.cs index 9f3eea62b..8e36591ec 100755 --- a/csharp/client/result/URLTOResultParser.cs +++ b/csharp/client/result/URLTOResultParser.cs @@ -1,55 +1,50 @@ /* -* 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. -*/ -using System; -using Result = com.google.zxing.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. + */ + namespace com.google.zxing.client.result { - - /// Parses the "URLTO" result format, which is of the form "URLTO:[title]:[url]". + + using Result = com.google.zxing.Result; + + /// + /// 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 /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class URLTOResultParser + public sealed class URLTOResultParser : ResultParser { - - private URLTOResultParser() + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + if (!rawText.StartsWith("urlto:") && !rawText.StartsWith("URLTO:")) { + return null; } - - public static URIParsedResult parse(Result result) + int titleEnd = rawText.IndexOf(':', 6); + if (titleEnd < 0) { - System.String rawText = result.Text; - if (rawText == null || (!rawText.StartsWith("urlto:") && !rawText.StartsWith("URLTO:"))) - { - return null; - } - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - int titleEnd = rawText.IndexOf(':', 6); - if (titleEnd < 0) - { - return null; - } - System.String title = titleEnd <= 6?null:rawText.Substring(6, (titleEnd) - (6)); - System.String uri = rawText.Substring(titleEnd + 1); - return new URIParsedResult(uri, title); + return null; } + string title = titleEnd <= 6 ? null : rawText.Substring(6, titleEnd - 6); + string uri = rawText.Substring(titleEnd + 1); + return new URIParsedResult(uri, title); + } + } } \ No newline at end of file diff --git a/csharp/client/result/VCardResultParser.cs b/csharp/client/result/VCardResultParser.cs index 66480e433..d55a5b529 100755 --- a/csharp/client/result/VCardResultParser.cs +++ b/csharp/client/result/VCardResultParser.cs @@ -1,230 +1,403 @@ -/* -* 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. -*/ using System; -using Result = com.google.zxing.Result; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using com.google.zxing.common; + +/* + * 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. + */ + namespace com.google.zxing.client.result { - - /// Parses contact information formatted according to the VCard (2.1) format. This is not a complete + + using Result = com.google.zxing.Result; + + + /// + /// 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 /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class VCardResultParser:ResultParser + public sealed class VCardResultParser : ResultParser { - - private VCardResultParser() + + private static readonly string BEGIN_VCARD = "BEGIN:VCARD"; + private static readonly string VCARD_LIKE_DATE = "\\d{4}-?\\d{2}-?\\d{2}"; + private static readonly string CR_LF_SPACE_TAB = "\r\n[ \t]"; + private static readonly string NEWLINE_ESCAPE = "\\\\[nN]"; + private static readonly string VCARD_ESCAPES = "\\\\([,;\\\\])"; + private static readonly string EQUALS = "="; + private static readonly string SEMICOLON = ";"; + private static readonly string UNESCAPED_SEMICOLONS = "(?> names = matchVCardPrefixedField("FN", rawText, true, false); + if (names == null) { - // Although we should insist on the raw text ending with "END:VCARD", there's no reason - // to throw out everything else we parsed just because this was omitted. In fact, Eclair - // is doing just that, and we can't parse its contacts without this leniency. - System.String rawText = result.Text; - if (rawText == null || !rawText.StartsWith("BEGIN:VCARD")) - { - return null; - } - System.String[] names = 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); - } - System.String[] phoneNumbers = matchVCardPrefixedField("TEL", rawText, true); - System.String[] emails = matchVCardPrefixedField("EMAIL", rawText, true); - System.String note = matchSingleVCardPrefixedField("NOTE", rawText, false); - System.String[] addresses = matchVCardPrefixedField("ADR", rawText, true); - if (addresses != null) - { - for (int i = 0; i < addresses.Length; i++) - { - addresses[i] = formatAddress(addresses[i]); - } - } - System.String org = matchSingleVCardPrefixedField("ORG", rawText, true); - System.String birthday = matchSingleVCardPrefixedField("BDAY", rawText, true); - if (!isLikeVCardDate(birthday)) - { - birthday = null; - } - System.String title = matchSingleVCardPrefixedField("TITLE", rawText, true); - System.String url = matchSingleVCardPrefixedField("URL", rawText, true); - return new AddressBookParsedResult(names, null, phoneNumbers, emails, note, addresses, org, birthday, title, url); + // If no display names found, look for regular name fields and format them + names = matchVCardPrefixedField("N", rawText, true, false); + formatNames(names); } - - private static System.String[] matchVCardPrefixedField(System.String prefix, System.String rawText, bool trim) + IList> phoneNumbers = matchVCardPrefixedField("TEL", rawText, true, false); + IList> emails = matchVCardPrefixedField("EMAIL", rawText, true, false); + IList note = matchSingleVCardPrefixedField("NOTE", rawText, false, false); + IList> addresses = matchVCardPrefixedField("ADR", rawText, true, true); + IList org = matchSingleVCardPrefixedField("ORG", rawText, true, true); + IList birthday = matchSingleVCardPrefixedField("BDAY", rawText, true, false); + if (birthday != null && !isLikeVCardDate(birthday[0])) { - System.Collections.ArrayList matches = null; - int i = 0; - int max = rawText.Length; - while (i < max) - { - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - i = rawText.IndexOf(prefix, i); - if (i < 0) - { - break; - } - if (i > 0 && rawText[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[i] != ':' && rawText[i] != ';') - { - continue; - } - while (rawText[i] != ':') - { - // Skip until a colon - i++; - } - i++; // skip colon - int start = i; // Found the start of a match here - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - 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 = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(3)); // lazy init - } - System.String element = rawText.Substring(start, (i) - (start)); - if (trim) - { - element = element.Trim(); - } - matches.Add(element); - i++; - } - else - { - i++; - } - } - if (matches == null || (matches.Count == 0)) - { - return null; - } - return toStringArray(matches); + birthday = null; } - - internal static System.String matchSingleVCardPrefixedField(System.String prefix, System.String rawText, bool trim) + IList title = matchSingleVCardPrefixedField("TITLE", rawText, true, false); + IList url = matchSingleVCardPrefixedField("URL", rawText, true, false); + IList instantMessenger = matchSingleVCardPrefixedField("IMPP", rawText, true, false); + return new AddressBookParsedResult(toPrimaryValues(names), null, toPrimaryValues(phoneNumbers), toTypes(phoneNumbers), toPrimaryValues(emails), toTypes(emails), toPrimaryValue(instantMessenger), toPrimaryValue(note), toPrimaryValues(addresses), toTypes(addresses), toPrimaryValue(org), toPrimaryValue(birthday), toPrimaryValue(title), toPrimaryValue(url)); + } + + internal static IList> matchVCardPrefixedField(string prefix, string rawText, bool trim, bool parseFieldDivider) + { + IList> matches = null; + int i = 0; + int max = rawText.Length; + + while (i < max) { - System.String[] values = matchVCardPrefixedField(prefix, rawText, trim); - return values == null?null:values[0]; - } - - private static bool isLikeVCardDate(System.String value_Renamed) - { - if (value_Renamed == null) + + // At start or after newline, match prefix, followed by optional metadata + // (led by ;) ultimately ending in colon + //Matcher matcher = Pattern.compile("(?:^|\n)" + prefix + "(?:;([^:]*))?:", Pattern.CASE_INSENSITIVE).matcher(rawText); + Regex matcher = new Regex("(?:^|\n)" + prefix + "(?:;([^:]*))?:", RegexOptions.IgnoreCase); + //(rawText); + if (i > 0) + { + i--; // Find from i-1 not i since looking at the preceding character + } + //if (!matcher.find(i)) + Match match = matcher.Match(rawText); + if (!match.Success) + { + break; + } + //i = matcher.end(0); // group 0 = whole pattern; end(0) is past final colon + + i = match.Groups[0].Index + match.Groups[0].Length; // group 0 = whole pattern; end(0) is past final colon + + string metadataString = match.Groups[1].Value; // group 1 = metadata substring + IList metadata = null; + bool quotedPrintable = false; + string quotedPrintableCharset = null; + if (metadataString != null) + { + foreach (string metadatum in SEMICOLON.Split(new string[] {metadataString},StringSplitOptions.None)) { - return true; - } - // Not really sure this is true but matches practice - // Mach YYYYMMDD - if (isStringOfDigits(value_Renamed, 8)) - { - return true; - } - // or YYYY-MM-DD - return value_Renamed.Length == 10 && value_Renamed[4] == '-' && value_Renamed[7] == '-' && isSubstringOfDigits(value_Renamed, 0, 4) && isSubstringOfDigits(value_Renamed, 5, 2) && isSubstringOfDigits(value_Renamed, 8, 2); - } - - private static System.String formatAddress(System.String address) - { - if (address == null) - { - return null; - } - int length = address.Length; - System.Text.StringBuilder newAddress = new System.Text.StringBuilder(length); - for (int j = 0; j < length; j++) - { - char c = address[j]; - if (c == ';') + if (metadata == null) + { + metadata = new List(1); + } + metadata.Add(metadatum); + //string[] metadatumTokens = EQUALS.Split(metadatum, 2); + string[] metadatumTokens = EQUALS.Split(new string[] {metadatum},2,StringSplitOptions.None); + if (metadatumTokens.Length > 1) + { + string key = metadatumTokens[0]; + string value = metadatumTokens[1]; + if ("ENCODING"== key.ToUpper() && "QUOTED-PRINTABLE"==value.ToUpper()) { - newAddress.Append(' '); + quotedPrintable = true; } - else + else if ("CHARSET" == key.ToUpper()) { - newAddress.Append(c); + quotedPrintableCharset = value; } + } } - return newAddress.ToString().Trim(); - } - - /// Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like - /// "Reverend John Q. Public III". - /// - /// - /// name values to format, in place - /// - private static void formatNames(System.String[] names) - { - if (names != null) + } + + int matchStart = i; // Found the start of a match here + + while ((i =(int) rawText.IndexOf( '\n', i)) >= 0) // Really, end in \r\n + { + if (i < rawText.Length - 1 && (rawText[i + 1] == ' ' || rawText[i + 1] == '\t')) // this is only a continuation - But if followed by tab or space, { - for (int i = 0; i < names.Length; i++) + i += 2; // Skip \n and continutation whitespace + } // If preceded by = in quoted printable + else if (quotedPrintable && ((i >= 1 && rawText[i - 1] == '=') || (i >= 2 && rawText[i - 2] == '='))) // this is a continuation + { + i++; // Skip \n + } + else + { + break; + } + } + + if (i < 0) + { + // No terminating end character? uh, done. Set i such that loop terminates and break + i = max; + } + else if (i > matchStart) + { + // found a match + if (matches == null) + { + matches = new List>(1); // lazy init + } + if (i >= 1 && rawText[i - 1] == '\r') + { + i--; // Back up over \r, which really should be there + } + string element = rawText.Substring(matchStart, i - matchStart); + if (trim) + { + element = element.Trim(); + } + if (quotedPrintable) + { + element = decodeQuotedPrintable(element, quotedPrintableCharset); + if (parseFieldDivider) + { + //element = UNESCAPED_SEMICOLONS.matcher(element).replaceAll("\n").Trim(); + element = new Regex(UNESCAPED_SEMICOLONS).Replace(element,("\n")).Trim(); + } + } + else + { + if (parseFieldDivider) + { + //element = UNESCAPED_SEMICOLONS.matcher(element).replaceAll("\n").Trim(); + element = new Regex(UNESCAPED_SEMICOLONS).Replace(element,"\n").Trim(); + } + //element = CR_LF_SPACE_TAB.matcher(element).replaceAll(""); + element = new Regex(CR_LF_SPACE_TAB).Replace(element,""); + //element = NEWLINE_ESCAPE.matcher(element).replaceAll("\n"); + element = new Regex(NEWLINE_ESCAPE).Replace(element,"\n"); + //element = VCARD_ESCAPES.matcher(element).replaceAll("$1"); + element = new Regex(VCARD_ESCAPES).Replace(element,"$1"); + } + if (metadata == null) + { + IList matchList = new List(1); + matchList.Add(element); + matches.Add(matchList); + } + else + { + metadata.Insert(0, element); + matches.Add(metadata); + } + i++; + } + else + { + i++; + } + + } + + return matches; + } + + private static string decodeQuotedPrintable(string value, string charset) + { + int length = value.Length; + StringBuilder result = new StringBuilder(length); + MemoryStream fragmentBuffer = new MemoryStream(); + for (int i = 0; i < length; i++) + { + char c = value[i]; + switch (c) + { + case '\r': + case '\n': + break; + case '=': + if (i < length - 2) + { + char nextChar = value[i + 1]; + if (nextChar != '\r' && nextChar != '\n') { - System.String name = names[i]; - System.String[] components = new System.String[5]; - int start = 0; - int end; - int componentIndex = 0; - //UPGRADE_WARNING: Method 'java.lang.String.indexOf' was converted to 'System.String.IndexOf' which may throw an exception. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1101'" - while ((end = name.IndexOf(';', start)) > 0) - { - components[componentIndex] = name.Substring(start, (end) - (start)); - componentIndex++; - start = end + 1; - } - components[componentIndex] = name.Substring(start); - System.Text.StringBuilder newName = new System.Text.StringBuilder(100); - maybeAppendComponent(components, 3, newName); - maybeAppendComponent(components, 1, newName); - maybeAppendComponent(components, 2, newName); - maybeAppendComponent(components, 0, newName); - maybeAppendComponent(components, 4, newName); - names[i] = newName.ToString().Trim(); + char nextNextChar = value[i + 2]; + int firstDigit = parseHexDigit(nextChar); + int secondDigit = parseHexDigit(nextNextChar); + if (firstDigit >= 0 && secondDigit >= 0) + { + fragmentBuffer.WriteByte((byte)((firstDigit << 4) + secondDigit)); + } // else ignore it, assume it was incorrectly encoded + i += 2; } - } + } + break; + default: + maybeAppendFragment(fragmentBuffer, charset, result); + result.Append(c); + break; + } } - - private static void maybeAppendComponent(System.String[] components, int i, System.Text.StringBuilder newName) + maybeAppendFragment(fragmentBuffer, charset, result); + return result.ToString(); + } + + private static void maybeAppendFragment(MemoryStream fragmentBuffer, string charset, StringBuilder result) + { + Encoding en = Encoding.GetEncoding(charset); + Encoding enFallback = Encoding.UTF8; + if (fragmentBuffer.Length > 0) { - if (components[i] != null) + sbyte[] fragmentBytes = fragmentBuffer.ToArray().ToSBytes(); + string fragment; + if (charset == null) + { + fragment = en.GetString((byte[])(Array)fragmentBytes); ; + } + else + { + try { - newName.Append(' '); - newName.Append(components[i]); + fragment = en.GetString((byte[])(Array)fragmentBytes); ; } + catch (ArgumentException e) + { + // Yikes, well try anyway: + //fragment = new string(fragmentBytes); + fragment = enFallback.GetString((byte[]) (Array) fragmentBytes); + } + } + fragmentBuffer.Position=0; + result.Append(fragment); } + } + + internal static IList matchSingleVCardPrefixedField(string prefix, string rawText, bool trim, bool parseFieldDivider) + { + IList> values = matchVCardPrefixedField(prefix, rawText, trim, parseFieldDivider); + return values == null || values.Count == 0 ? null : values[0]; + } + + private static string toPrimaryValue(IList list) + { + return list == null || list.Count == 0 ? null : list[0]; + } + + private static string[] toPrimaryValues(ICollection> lists) + { + if (lists == null || lists.Count == 0) + { + return null; + } + List result = new List(lists.Count); + foreach (IList list in lists) + { + result.Add(list[0]); + } + return result.ToArray(); + } + + private static string[] toTypes(ICollection> lists) + { + if (lists == null || lists.Count == 0) + { + return null; + } + List result = new List(lists.Count); + foreach (IList list in lists) + { + string type = null; + for (int i = 1; i < list.Count; i++) + { + string metadatum = list[i]; + int equals = metadatum.IndexOf('='); + if (equals < 0) + { + // take the whole thing as a usable label + type = metadatum; + break; + } + if ("TYPE" == (metadatum.Substring(0, equals)).ToUpper()) + { + type = metadatum.Substring(equals + 1); + break; + } + } + result.Add(type); + } + return result.ToArray(); + } + + private static bool isLikeVCardDate(string value) + { + //return value == null || VCARD_LIKE_DATE.matcher(value).matches(); + return value == null || new Regex(VCARD_LIKE_DATE).IsMatch(value); + } + + /// + /// Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like + /// "Reverend John Q. Public III". + /// + /// name values to format, in place + private static void formatNames(IEnumerable> names) + { + if (names != null) + { + foreach (IList list in names) + { + string name = list[0]; + string[] components = new string[5]; + int start = 0; + int end; + int componentIndex = 0; + while (componentIndex < components.Length - 1 && (end = name.IndexOf(';', start)) > 0) + { + components[componentIndex] = name.Substring(start, end - start); + componentIndex++; + start = end + 1; + } + components[componentIndex] = name.Substring(start); + StringBuilder newName = new StringBuilder(100); + maybeAppendComponent(components, 3, newName); + maybeAppendComponent(components, 1, newName); + maybeAppendComponent(components, 2, newName); + maybeAppendComponent(components, 0, newName); + maybeAppendComponent(components, 4, newName); + list[0] = newName.ToString().Trim(); + } + } + } + + private static void maybeAppendComponent(string[] components, int i, StringBuilder newName) + { + if (components[i] != null) + { + newName.Append(' '); + newName.Append(components[i]); + } + } + } + } \ No newline at end of file diff --git a/csharp/client/result/VEventResultParser.cs b/csharp/client/result/VEventResultParser.cs index 2b331dd9d..4d9756d91 100755 --- a/csharp/client/result/VEventResultParser.cs +++ b/csharp/client/result/VEventResultParser.cs @@ -1,67 +1,129 @@ -/* -* 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. -*/ using System; -using Result = com.google.zxing.Result; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.client.result { - - /// Partially implements the iCalendar format's "VEVENT" format for specifying a - /// calendar event. See RFC 2445. This supports SUMMARY, DTSTART and DTEND fields. + + using Result = com.google.zxing.Result; + + + /// + /// Partially implements the iCalendar format's "VEVENT" format for specifying a + /// calendar event. See RFC 2445. This supports SUMMARY, LOCATION, GEO, DTSTART and DTEND fields. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class VEventResultParser:ResultParser + public sealed class VEventResultParser : ResultParser { - - private VEventResultParser() + + public override ParsedResult parse(Result result) + { + string rawText = getMassagedText(result); + int vEventStart = rawText.IndexOf("BEGIN:VEVENT"); + if (vEventStart < 0) { + return null; } - - public static CalendarParsedResult parse(Result result) + + string summary = matchSingleVCardPrefixedField("SUMMARY", rawText, true); + string start = matchSingleVCardPrefixedField("DTSTART", rawText, true); + if (start == null) { - System.String rawText = result.Text; - if (rawText == null) - { - return null; - } - int vEventStart = rawText.IndexOf("BEGIN:VEVENT"); - if (vEventStart < 0) - { - return null; - } - int vEventEnd = rawText.IndexOf("END:VEVENT"); - if (vEventEnd < 0) - { - return null; - } - - System.String summary = VCardResultParser.matchSingleVCardPrefixedField("SUMMARY", rawText, true); - System.String start = VCardResultParser.matchSingleVCardPrefixedField("DTSTART", rawText, true); - System.String end = VCardResultParser.matchSingleVCardPrefixedField("DTEND", rawText, true); - try - { - return new CalendarParsedResult(summary, start, end, null, null, null); - } - catch (System.ArgumentException) - { - return null; - } + return null; } + string end = matchSingleVCardPrefixedField("DTEND", rawText, true); + string duration = matchSingleVCardPrefixedField("DURATION", rawText, true); + string location = matchSingleVCardPrefixedField("LOCATION", rawText, true); + string organizer = stripMailto(matchSingleVCardPrefixedField("ORGANIZER", rawText, true)); + + string[] attendees = matchVCardPrefixedField("ATTENDEE", rawText, true); + if (attendees != null) + { + for (int i = 0; i < attendees.Length; i++) + { + attendees[i] = stripMailto(attendees[i]); + } + } + string description = matchSingleVCardPrefixedField("DESCRIPTION", rawText, true); + + string geoString = matchSingleVCardPrefixedField("GEO", rawText, true); + double latitude; + double longitude; + if (geoString == null) + { + latitude = double.NaN; + longitude = double.NaN; + } + else + { + int semicolon = geoString.IndexOf(';'); + try + { + latitude = Convert.ToDouble(geoString.Substring(0, semicolon)); + longitude = Convert.ToDouble(geoString.Substring(semicolon + 1)); + } + catch (FormatException nfe) + { + return null; + } + } + + try + { + return new CalendarParsedResult(summary, start, end, duration, location, organizer, attendees, description, latitude, longitude); + } + catch (System.ArgumentException iae) + { + return null; + } + } + + private static string matchSingleVCardPrefixedField(string prefix, string rawText, bool trim) + { + IList values = VCardResultParser.matchSingleVCardPrefixedField(prefix, rawText, trim, false); + return values == null || values.Count == 0 ? null : values[0]; + } + + private static string[] matchVCardPrefixedField(string prefix, string rawText, bool trim) + { + IList> values = VCardResultParser.matchVCardPrefixedField(prefix, rawText, trim, false); + if (values == null || values.Count == 0) + { + return null; + } + int size = values.Count; + string[] result = new string[size]; + for (int i = 0; i < size; i++) + { + result[i] = values[i][0]; + } + return result; + } + + private static string stripMailto(string s) + { + if (s != null && (s.StartsWith("mailto:") || s.StartsWith("MAILTO:"))) + { + s = s.Substring(7); + } + return s; + } + } -} +} \ No newline at end of file diff --git a/csharp/common/BitArray.cs b/csharp/common/BitArray.cs index 51f277690..81708c066 100755 --- a/csharp/common/BitArray.cs +++ b/csharp/common/BitArray.cs @@ -1,208 +1,382 @@ -/* -* 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. -*/ using System; +using System.Collections; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.common { - - ///

A simple, fast array of bits, represented compactly by an array of ints internally.

+ + /// + ///

A simple, fast array of bits, represented compactly by an array of ints internally.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class BitArray { - public int Size + + private int[] bits; + private int size; + + public BitArray() + { + this.size = 0; + this.bits = new int[1]; + } + + public BitArray(int size) + { + this.size = size; + this.bits = makeArray(size); + } + + public int Size + { + get + { + return size; + } + } + + public int SizeInBytes + { + get + { + return (size + 7) >> 3; + } + } + + private void ensureCapacity(int size) + { + if (size > bits.Length << 5) { - get + int[] newBits = makeArray(size); + Array.Copy(bits, 0, newBits, 0, bits.Length); + this.bits = newBits; + } + } + + /// bit to get + /// true iff bit i is set + public bool get(int i) + { + return (bits[i >> 5] & (1 << (i & 0x1F))) != 0; + } + + /// + /// Sets bit i. + /// + /// bit to set + public void set(int i) + { + bits[i >> 5] |= 1 << (i & 0x1F); + } + + /// + /// Flips bit i. + /// + /// bit to set + public void flip(int i) + { + bits[i >> 5] ^= 1 << (i & 0x1F); + } + + /// first bit to check + /// index of first bit that is set, starting from the given index, or size if none are set + /// at or beyond this given index + /// + public int getNextSet(int from) + { + if (from >= size) + { + return size; + } + int bitsOffset = from >> 5; + int currentBits = bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) + { + if (++bitsOffset == bits.Length) + { + return size; + } + currentBits = bits[bitsOffset]; + } + //int result = (bitsOffset << 5) + int.numberOfTrailingZeros(currentBits); + int result = (bitsOffset << 5) + currentBits.NumberOfTrailingZeros(); + return result > size ? size : result; + } + + /// + public int getNextUnset(int from) + { + if (from >= size) + { + return size; + } + int bitsOffset = from >> 5; + int currentBits = ~bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) + { + if (++bitsOffset == bits.Length) + { + return size; + } + currentBits = ~bits[bitsOffset]; + } + //int result = (bitsOffset << 5) + int.numberOfTrailingZeros(currentBits); + int result = (bitsOffset << 5) + currentBits.NumberOfTrailingZeros(); + return result > size ? size : result; + } + + /// + /// Sets a block of 32 bits, starting at bit i. + /// + /// first bit to set + /// 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 void setBulk(int i, int newBits) + { + bits[i >> 5] = newBits; + } + + /// + /// Sets a range of bits. + /// + /// start of range, inclusive. + /// end of range, exclusive + public void setRange(int start, int end) + { + if (end < start) + { + throw new System.ArgumentException(); + } + if (end == start) + { + return; + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start >> 5; + int lastInt = end >> 5; + for (int i = firstInt; i <= lastInt; i++) + { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) + { + mask = -1; + } + else + { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { - return size; + mask |= 1 << j; } - + } + bits[i] |= mask; } - - // 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 int[] bits; - //UPGRADE_NOTE: Final was removed from the declaration of 'size '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public int size; - - public BitArray(int size) + } + + /// + /// Clears all bits (sets to false). + /// + public void clear() + { + int max = bits.Length; + for (int i = 0; i < max; i++) { - if (size < 1) + bits[i] = 0; + } + } + + /// + /// Efficient method to check if a range of bits is set, or not set. + /// + /// start of range, inclusive. + /// end of range, exclusive + /// if true, checks that bits in range are set, otherwise checks that they are not set + /// true iff all bits are set or not set in range, according to value argument + /// if end is less than or equal to start + public bool isRange(int start, int end, bool value) + { + if (end < start) + { + throw new System.ArgumentException(); + } + if (end == start) + { + return true; // empty range matches + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start >> 5; + int lastInt = end >> 5; + for (int i = firstInt; i <= lastInt; i++) + { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int mask; + if (firstBit == 0 && lastBit == 31) + { + mask = -1; + } + else + { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { - throw new System.ArgumentException("size must be at least 1"); + mask |= 1 << j; } - this.size = size; - this.bits = makeArray(size); + } + + // 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; + } } - - /// bit to get - /// - /// true iff bit i is set - /// - public bool get_Renamed(int i) + return true; + } + + public void appendBit(bool bit) + { + ensureCapacity(size + 1); + if (bit) { - return (bits[i >> 5] & (1 << (i & 0x1F))) != 0; + bits[size >> 5] |= 1 << (size & 0x1F); } - - /// Sets bit i. - /// - /// - /// bit to set - /// - public void set_Renamed(int i) + size++; + } + + /// + /// Appends the least-significant bits, from value, in order from most-significant to + /// least-significant. For example, appending 6 bits from 0x000001E will append the bits + /// 0, 1, 1, 1, 1, 0 in that order. + /// + public void appendBits(int value, int numBits) + { + if (numBits < 0 || numBits > 32) { - bits[i >> 5] |= 1 << (i & 0x1F); + throw new System.ArgumentException("Num bits must be between 0 and 32"); } - - /// Flips bit i. - /// - /// - /// bit to set - /// - public void flip(int i) + ensureCapacity(size + numBits); + for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { - bits[i >> 5] ^= 1 << (i & 0x1F); + appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1); } - - /// Sets a block of 32 bits, starting at bit i. - /// - /// - /// first bit to set - /// - /// 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 void setBulk(int i, int newBits) + } + + public void appendBitArray(BitArray other) + { + int otherSize = other.size; + ensureCapacity(size + otherSize); + for (int i = 0; i < otherSize; i++) { - bits[i >> 5] = newBits; + appendBit(other.get(i)); } - - /// Clears all bits (sets to false). - public void clear() + } + + public void xor(BitArray other) + { + if (bits.Length != other.bits.Length) { - int max = bits.Length; - for (int i = 0; i < max; i++) + throw new System.ArgumentException("Sizes don't match"); + } + for (int i = 0; i < bits.Length; i++) + { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + bits[i] ^= other.bits[i]; + } + } + + /// + /// first bit to start writing + /// array to write into. Bytes are written most-significant byte first. This is the opposite + /// of the internal representation, which is exposed by + /// position in array to start writing + /// how many bytes to write + public void toBytes(int bitOffset, sbyte[] array, int offset, int numBytes) + { + for (int i = 0; i < numBytes; i++) + { + int theByte = 0; + for (int j = 0; j < 8; j++) + { + if (get(bitOffset)) { - bits[i] = 0; + theByte |= 1 << (7 - j); } + bitOffset++; + } + array[offset + i] = (sbyte) theByte; } - - /// Efficient method to check if a range of bits is set, or not set. - /// - /// - /// start of range, inclusive. - /// - /// end of range, exclusive - /// - /// if true, checks that bits in range are set, otherwise checks that they are not set - /// - /// true iff all bits are set or not set in range, according to value argument - /// - /// IllegalArgumentException if end is less than or equal to start - public bool isRange(int start, int end, bool value_Renamed) - { - if (end < start) - { - throw new System.ArgumentException(); - } - if (end == start) - { - return true; // empty range matches - } - end--; // will be easier to treat this as the last actually set bit -- inclusive - int firstInt = start >> 5; - int lastInt = end >> 5; - for (int i = firstInt; i <= lastInt; i++) - { - int firstBit = i > firstInt?0:start & 0x1F; - int lastBit = i < lastInt?31:end & 0x1F; - int mask; - if (firstBit == 0 && lastBit == 31) - { - mask = - 1; - } - else - { - mask = 0; - for (int j = 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_Renamed?mask:0)) - { - return false; - } - } - return true; - } - - /// underlying array of ints. The first element holds the first 32 bits, and the least - /// significant bit is bit 0. - /// - public int[] getBitArray() - { + } + + /// underlying array of ints. The first element holds the first 32 bits, and the least + /// significant bit is bit 0. + public int[] BitArrayBits + { + get + { return bits; - } - - /// Reverses all bits in the array. - public void reverse() + } + } + + /// + /// Reverses all bits in the array. + /// + public void reverse() + { + int[] newBits = new int[bits.Length]; + int size = this.size; + for (int i = 0; i < size; i++) { - int[] newBits = new int[bits.Length]; - int size = this.size; - for (int i = 0; i < size; i++) - { - if (get_Renamed(size - i - 1)) - { - newBits[i >> 5] |= 1 << (i & 0x1F); - } - } - bits = newBits; + if (get(size - i - 1)) + { + newBits[i >> 5] |= 1 << (i & 0x1F); + } } - - private static int[] makeArray(int size) + bits = newBits; + } + + private static int[] makeArray(int size) + { + return new int[(size + 31) >> 5]; + } + + public override string ToString() + { + StringBuilder result = new StringBuilder(size); + for (int i = 0; i < size; i++) { - int arraySize = size >> 5; - if ((size & 0x1F) != 0) - { - arraySize++; - } - return new int[arraySize]; - } - - public override System.String ToString() - { - System.Text.StringBuilder result = new System.Text.StringBuilder(size); - for (int i = 0; i < size; i++) - { - if ((i & 0x07) == 0) - { - result.Append(' '); - } - result.Append(get_Renamed(i)?'X':'.'); - } - return result.ToString(); + if ((i & 0x07) == 0) + { + result.Append(' '); + } + result.Append(get(i) ? 'X' : '.'); } + return result.ToString(); + } + } } \ No newline at end of file diff --git a/csharp/common/BitMatrix.cs b/csharp/common/BitMatrix.cs index 6612ff443..f999943f0 100755 --- a/csharp/common/BitMatrix.cs +++ b/csharp/common/BitMatrix.cs @@ -1,23 +1,28 @@ -/* -* 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. -*/ using System; +using System.Collections; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.common { - - ///

Represents a 2D matrix of bits. In function arguments below, and throughout the common + + ///

+ ///

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.

/// @@ -28,210 +33,335 @@ namespace com.google.zxing.common ///

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.

/// + /// @author Sean Owen + /// @author dswitkin@google.com (Daniel Switkin) ///
- /// Sean Owen - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class BitMatrix { - /// The width of the matrix - /// - public int Width + + private readonly int width; + private readonly int height; + private readonly int rowSize; + private readonly int[] bits; + + // A helper to construct a square matrix. + public BitMatrix(int dimension) : this(dimension, dimension) + { + } + + public BitMatrix(int width, int height) + { + if (width < 1 || height < 1) { - get - { - return width; - } - + throw new System.ArgumentException("Both dimensions must be greater than 0"); } - /// The height of the matrix - /// - public int Height + this.width = width; + this.height = height; + this.rowSize = (width + 31) >> 5; + bits = new int[rowSize * height]; + } + + /// + ///

Gets the requested bit, where true means black.

+ ///
+ /// The horizontal component (i.e. which column) + /// The vertical component (i.e. which row) + /// value of given bit in matrix + public bool get(int x, int y) + { + int offset = y * rowSize + (x >> 5); + return (((int)((uint)bits[offset] >> (x & 0x1f))) & 1) != 0; + } + + /// + ///

Sets the given bit to true.

+ ///
+ /// The horizontal component (i.e. which column) + /// The vertical component (i.e. which row) + public void set(int x, int y) + { + int offset = y * rowSize + (x >> 5); + bits[offset] |= 1 << (x & 0x1f); + } + + /// + ///

Flips the given bit.

+ ///
+ /// The horizontal component (i.e. which column) + /// The vertical component (i.e. which row) + public void flip(int x, int y) + { + int offset = y * rowSize + (x >> 5); + bits[offset] ^= 1 << (x & 0x1f); + } + + /// + /// Clears all bits (sets to false). + /// + public void clear() + { + int max = bits.Length; + for (int i = 0; i < max; i++) { - get - { - return height; - } - + bits[i] = 0; } - /// 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. - /// - /// - /// row/column dimension of this matrix - /// - public int Dimension + } + + /// + ///

Sets a square region of the bit matrix to true.

+ ///
+ /// The horizontal position to begin at (inclusive) + /// The vertical position to begin at (inclusive) + /// The width of the region + /// The height of the region + public void setRegion(int left, int top, int width, int height) + { + if (top < 0 || left < 0) { - get + throw new System.ArgumentException("Left and top must be nonnegative"); + } + if (height < 1 || width < 1) + { + throw new System.ArgumentException("Height and width must be at least 1"); + } + int right = left + width; + int bottom = top + height; + if (bottom > this.height || right > this.width) + { + throw new System.ArgumentException("The region must fit inside the matrix"); + } + for (int y = top; y < bottom; y++) + { + int offset = y * rowSize; + for (int x = 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. + /// + /// The row to retrieve + /// An optional caller-allocated BitArray, will be allocated if null or too small + /// The resulting BitArray - this reference should always be used even when passing + /// your own row + public BitArray getRow(int y, BitArray row) + { + if (row == null || row.Size < width) + { + row = new BitArray(width); + } + int offset = y * rowSize; + for (int x = 0; x < rowSize; x++) + { + row.setBulk(x << 5, bits[offset + x]); + } + return row; + } + + /// row to set + /// to copy from + public void setRow(int y, BitArray row) + { + Array.Copy(row.BitArrayBits, 0, bits, y * rowSize, rowSize); + } + + /// + /// This is useful in detecting the enclosing rectangle of a 'pure' barcode. + /// + /// {left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white + public int[] EnclosingRectangle + { + get + { + int left = this.width; + int top = this.height; + int right = -1; + int bottom = -1; + + for (int y = 0; y < this.height; y++) { - if (width != height) + for (int x32 = 0; x32 < rowSize; x32++) + { + int theBits = bits[y * rowSize + x32]; + if (theBits != 0) { - throw new System.SystemException("Can't call getDimension() on a non-square matrix"); + if (y < top) + { + top = y; + } + if (y > bottom) + { + bottom = y; + } + if (x32 * 32 < left) + { + int bit = 0; + while ((theBits << (31 - bit)) == 0) + { + bit++; + } + if ((x32 * 32 + bit) < left) + { + left = x32 * 32 + bit; + } + } + if (x32 * 32 + 31 > right) + { + int bit = 31; + while (((int)((uint)theBits >> bit)) == 0) + { + bit--; + } + if ((x32 * 32 + bit) > right) + { + right = x32 * 32 + bit; + } + } } - return width; + } } - - } - - // TODO: Just like BitArray, these need to be public so ProGuard can inline them. - //UPGRADE_NOTE: Final was removed from the declaration of 'width '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public int width; - //UPGRADE_NOTE: Final was removed from the declaration of 'height '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public int height; - //UPGRADE_NOTE: Final was removed from the declaration of 'rowSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public int rowSize; - //UPGRADE_NOTE: Final was removed from the declaration of 'bits '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public int[] bits; - - // A helper to construct a square matrix. - public BitMatrix(int dimension):this(dimension, dimension) + + int width = right - left; + int height = bottom - top; + + if (width < 0 || height < 0) + { + return null; + } + + return new int[] {left, top, width, height}; + } + } + + /// + /// This is useful in detecting a corner of a 'pure' barcode. + /// + /// {x,y} coordinate of top-left-most 1 bit, or null if it is all white + public int[] TopLeftOnBit + { + get + { + int bitsOffset = 0; + while (bitsOffset < bits.Length && bits[bitsOffset] == 0) + { + bitsOffset++; + } + if (bitsOffset == bits.Length) + { + return null; + } + int y = bitsOffset / rowSize; + int x = (bitsOffset % rowSize) << 5; + + int theBits = bits[bitsOffset]; + int bit = 0; + while ((theBits << (31 - bit)) == 0) + { + bit++; + } + x += bit; + return new int[] {x, y}; + } + } + + public int[] BottomRightOnBit + { + get + { + int bitsOffset = bits.Length - 1; + while (bitsOffset >= 0 && bits[bitsOffset] == 0) + { + bitsOffset--; + } + if (bitsOffset < 0) + { + return null; + } + + int y = bitsOffset / rowSize; + int x = (bitsOffset % rowSize) << 5; + + int theBits = bits[bitsOffset]; + int bit = 31; + while (((int)((uint)theBits >> bit)) == 0) + { + bit--; + } + x += bit; + + return new int[] {x, y}; + } + } + + /// The width of the matrix + public int Width + { + get + { + return width; + } + } + + /// The height of the matrix + public int Height + { + get + { + return height; + } + } + + public override bool Equals(object o) + { + if (!(o is BitMatrix)) { + return false; } - - public BitMatrix(int width, int height) + BitMatrix other = (BitMatrix) o; + if (width != other.width || height != other.height || rowSize != other.rowSize || bits.Length != other.bits.Length) { - if (width < 1 || height < 1) - { - throw new System.ArgumentException("Both dimensions must be greater than 0"); - } - this.width = width; - this.height = height; - int rowSize = width >> 5; - if ((width & 0x1f) != 0) - { - rowSize++; - } - this.rowSize = rowSize; - bits = new int[rowSize * height]; + return false; } - - ///

Gets the requested bit, where true means black.

- /// - ///
- /// The horizontal component (i.e. which column) - /// - /// The vertical component (i.e. which row) - /// - /// value of given bit in matrix - /// - public bool get_Renamed(int x, int y) + for (int i = 0; i < bits.Length; i++) { - int offset = y * rowSize + (x >> 5); - return ((SupportClass.URShift(bits[offset], (x & 0x1f))) & 1) != 0; + if (bits[i] != other.bits[i]) + { + return false; + } } - - ///

Sets the given bit to true.

- /// - ///
- /// The horizontal component (i.e. which column) - /// - /// The vertical component (i.e. which row) - /// - public void set_Renamed(int x, int y) + return true; + } + + public override int GetHashCode() + { + int hash = width; + hash = 31 * hash + width; + hash = 31 * hash + height; + hash = 31 * hash + rowSize; + foreach (int bit in bits) { - int offset = y * rowSize + (x >> 5); - bits[offset] |= 1 << (x & 0x1f); + hash = 31 * hash + bit; } - - ///

Flips the given bit.

- /// - ///
- /// The horizontal component (i.e. which column) - /// - /// The vertical component (i.e. which row) - /// - public void flip(int x, int y) + return hash; + } + + public override string ToString() + { + StringBuilder result = new StringBuilder(height * (width + 1)); + for (int y = 0; y < height; y++) { - int offset = y * rowSize + (x >> 5); - bits[offset] ^= 1 << (x & 0x1f); - } - - /// Clears all bits (sets to false). - public void clear() - { - int max = bits.Length; - for (int i = 0; i < max; i++) - { - bits[i] = 0; - } - } - - ///

Sets a square region of the bit matrix to true.

- /// - ///
- /// The horizontal position to begin at (inclusive) - /// - /// The vertical position to begin at (inclusive) - /// - /// The width of the region - /// - /// The height of the region - /// - public void setRegion(int left, int top, int width, int height) - { - if (top < 0 || left < 0) - { - throw new System.ArgumentException("Left and top must be nonnegative"); - } - if (height < 1 || width < 1) - { - throw new System.ArgumentException("Height and width must be at least 1"); - } - int right = left + width; - int bottom = top + height; - if (bottom > this.height || right > this.width) - { - throw new System.ArgumentException("The region must fit inside the matrix"); - } - for (int y = top; y < bottom; y++) - { - int offset = y * rowSize; - for (int x = 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. - /// - /// - /// The row to retrieve - /// - /// An optional caller-allocated BitArray, will be allocated if null or too small - /// - /// The resulting BitArray - this reference should always be used even when passing - /// your own row - /// - public BitArray getRow(int y, BitArray row) - { - if (row == null || row.Size < width) - { - row = new BitArray(width); - } - int offset = y * rowSize; - for (int x = 0; x < rowSize; x++) - { - row.setBulk(x << 5, bits[offset + x]); - } - return row; - } - - public override System.String ToString() - { - System.Text.StringBuilder result = new System.Text.StringBuilder(height * (width + 1)); - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - result.Append(get_Renamed(x, y)?"X ":" "); - } - result.Append('\n'); - } - return result.ToString(); + for (int x = 0; x < width; x++) + { + result.Append(get(x, y) ? "X " : " "); + } + result.Append('\n'); } + return result.ToString(); + } + } + } \ No newline at end of file diff --git a/csharp/common/BitSource.cs b/csharp/common/BitSource.cs index 983caa753..d978785b3 100755 --- a/csharp/common/BitSource.cs +++ b/csharp/common/BitSource.cs @@ -1,109 +1,124 @@ -/* -* 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. -*/ using System; + +/* + * 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. + */ + namespace com.google.zxing.common { - - ///

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the + + ///

+ ///

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the /// number of bits read is not often a multiple of 8.

/// - ///

This class is thread-safe but not reentrant. Unless the caller modifies the bytes array + ///

This class is thread-safe but not reentrant -- unless the caller modifies the bytes array /// it passed in, in which case all bets are off.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class BitSource { - - //UPGRADE_NOTE: Final was removed from the declaration of 'bytes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte[] bytes; - private int byteOffset; - private int bitOffset; - - /// 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 BitSource(sbyte[] bytes) + + private readonly sbyte[] bytes; + private int byteOffset; + private int bitOffset; + + /// 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 BitSource(sbyte[] bytes) + { + this.bytes = bytes; + } + + /// index of next bit in current byte which would be read by the next call to . + public int BitOffset + { + get + { + return bitOffset; + } + } + + /// index of next byte in input byte array which would be read by the next call to . + public int ByteOffset + { + get + { + return byteOffset; + } + } + + /// number of bits to read + /// int representing the bits read. The bits will appear as the least-significant + /// bits of the int + /// if numBits isn't in [1,32] or more than is available + public int readBits(int numBits) + { + if (numBits < 1 || numBits > 32 || numBits > available()) { - this.bytes = bytes; + throw new System.ArgumentException(Convert.ToString(numBits)); } - - /// number of bits to read - /// - /// int representing the bits read. The bits will appear as the least-significant - /// bits of the int - /// - /// IllegalArgumentException if numBits isn't in [1,32] - public int readBits(int numBits) + + int result = 0; + + // First, read remainder from current byte + if (bitOffset > 0) { - if (numBits < 1 || numBits > 32) - { - throw new System.ArgumentException(); - } - - int result = 0; - - // First, read remainder from current byte - if (bitOffset > 0) - { - int bitsLeft = 8 - bitOffset; - int toRead = numBits < bitsLeft?numBits:bitsLeft; - int bitsToNotRead = bitsLeft - toRead; - int mask = (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) - { - int bitsToNotRead = 8 - numBits; - int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; - result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead); - bitOffset += numBits; - } - } - - return result; + int bitsLeft = 8 - bitOffset; + int toRead = numBits < bitsLeft ? numBits : bitsLeft; + int bitsToNotRead = bitsLeft - toRead; + int mask = (0xFF >> (8 - toRead)) << bitsToNotRead; + result = (bytes[byteOffset] & mask) >> bitsToNotRead; + numBits -= toRead; + bitOffset += toRead; + if (bitOffset == 8) + { + bitOffset = 0; + byteOffset++; + } } - - /// number of bits that can be read successfully - /// - public int available() + + // Next read whole bytes + if (numBits > 0) { - return 8 * (bytes.Length - byteOffset) - bitOffset; + while (numBits >= 8) + { + result = (result << 8) | (bytes[byteOffset] & 0xFF); + byteOffset++; + numBits -= 8; + } + + // Finally read a partial byte + if (numBits > 0) + { + int bitsToNotRead = 8 - numBits; + int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; + result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead); + bitOffset += numBits; + } } + + return result; + } + + /// number of bits that can be read successfully + public int available() + { + return 8 * (bytes.Length - byteOffset) - bitOffset; + } + } + } \ No newline at end of file diff --git a/csharp/common/CharacterSetECI.cs b/csharp/common/CharacterSetECI.cs index 54b8b98b1..517fa7f83 100755 --- a/csharp/common/CharacterSetECI.cs +++ b/csharp/common/CharacterSetECI.cs @@ -1,126 +1,224 @@ /* -* 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. -*/ + * 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. + */ + using System; +using System.Collections.Generic; + namespace com.google.zxing.common { - - /// Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 - /// of ISO 18004. - /// - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class CharacterSetECI:ECI - { - public System.String EncodingName - { - get - { - return encodingName; - } - - } - - private static System.Collections.Hashtable VALUE_TO_ECI; - private static System.Collections.Hashtable NAME_TO_ECI; - - private static void initialize() - { - VALUE_TO_ECI = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(29)); - NAME_TO_ECI = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(29)); - // TODO figure out if these values are even right! - addCharacterSet(0, "Cp437"); - addCharacterSet(1, new System.String[]{"ISO8859_1", "ISO-8859-1"}); - addCharacterSet(2, "Cp437"); - addCharacterSet(3, new System.String[]{"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, new System.String[]{"SJIS", "Shift_JIS"}); - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'encodingName '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String encodingName; - - private CharacterSetECI(int value_Renamed, System.String encodingName):base(value_Renamed) - { - this.encodingName = encodingName; - } - - private static void addCharacterSet(int value_Renamed, System.String encodingName) - { - CharacterSetECI eci = new CharacterSetECI(value_Renamed, encodingName); - VALUE_TO_ECI[(System.Int32) value_Renamed] = eci; // can't use valueOf - NAME_TO_ECI[encodingName] = eci; - } - - private static void addCharacterSet(int value_Renamed, System.String[] encodingNames) - { - CharacterSetECI eci = new CharacterSetECI(value_Renamed, encodingNames[0]); - VALUE_TO_ECI[(System.Int32) value_Renamed] = eci; // can't use valueOf - for (int i = 0; i < encodingNames.Length; i++) - { - NAME_TO_ECI[encodingNames[i]] = eci; - } - } - - /// character set ECI value - /// - /// {@link CharacterSetECI} representing ECI of given value, or null if it is legal but - /// unsupported - /// - /// IllegalArgumentException if ECI value is invalid - public static CharacterSetECI getCharacterSetECIByValue(int value_Renamed) - { - if (VALUE_TO_ECI == null) - { - initialize(); - } - if (value_Renamed < 0 || value_Renamed >= 900) - { - throw new System.ArgumentException("Bad ECI value: " + value_Renamed); - } - return (CharacterSetECI) VALUE_TO_ECI[(System.Int32) value_Renamed]; - } - - /// character set ECI encoding name - /// - /// {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal - /// but unsupported - /// - public static CharacterSetECI getCharacterSetECIByName(System.String name) - { - if (NAME_TO_ECI == null) - { - initialize(); - } - return (CharacterSetECI) NAME_TO_ECI[name]; - } - } + + using FormatException = com.google.zxing.FormatException; + + + /// + /// Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 + /// of ISO 18004. + /// + /// @author Sean Owen + /// + public abstract class CharacterSetECI + { + private CharacterSetECI() + { + + } + + private static object _syncLock; + + static CharacterSetECI() + { + lock (_syncLock) + { + addSet((innerCharacterSetECI)Cp437); + addSet((innerCharacterSetECI)ISO8859_1); + addSet((innerCharacterSetECI)ISO8859_2); + addSet((innerCharacterSetECI)ISO8859_3); + addSet((innerCharacterSetECI)ISO8859_4); + addSet((innerCharacterSetECI)ISO8859_5); + addSet((innerCharacterSetECI)ISO8859_6); + addSet((innerCharacterSetECI)ISO8859_7); + addSet((innerCharacterSetECI)ISO8859_8); + addSet((innerCharacterSetECI)ISO8859_9); + addSet((innerCharacterSetECI)ISO8859_10); + addSet((innerCharacterSetECI)ISO8859_11); + addSet((innerCharacterSetECI)ISO8859_13); + addSet((innerCharacterSetECI)ISO8859_14); + addSet((innerCharacterSetECI)ISO8859_15); + addSet((innerCharacterSetECI)ISO8859_16); + addSet((innerCharacterSetECI)SJIS); + addSet((innerCharacterSetECI)Cp1250); + addSet((innerCharacterSetECI)Cp1251); + addSet((innerCharacterSetECI)Cp1252); + addSet((innerCharacterSetECI)Cp1256); + addSet((innerCharacterSetECI)UnicodeBigUnmarked); + addSet((innerCharacterSetECI)UTF8); + addSet((innerCharacterSetECI)ASCII); + addSet((innerCharacterSetECI)Big5); + addSet((innerCharacterSetECI)GB18030); + addSet((innerCharacterSetECI)EUC_KR); + } + } + + private static void addSet(innerCharacterSetECI set) + { + foreach (int value in set.Values) + { + VALUE_TO_ECI[value] = set; + } + + foreach (string name in set.OtherEncodingNames) + { + NAME_TO_ECI[name] = set; + } + } + + private class innerCharacterSetECI : CharacterSetECI + { + private int[] values; + private string[] otherEncodingNames; + + + + //internal Thing(int value) + //{ + // setup(value); + //} + + internal innerCharacterSetECI(int value, params string[] otherEncodingNames) + { + setup(value, otherEncodingNames); + } + + internal innerCharacterSetECI(int[] values, params string[] otherEncodingNames) + { + setup(values, otherEncodingNames); + } + + //void setup(int value) + //{ + // setup(new int[] { value }); + //} + + void setup(int value, params string[] otherEncodingNames) + { + this.values = new int[] { value }; + this.otherEncodingNames = otherEncodingNames; + } + + void setup(int[] values, params string[] otherEncodingNames) + { + this.values = values; + this.otherEncodingNames = otherEncodingNames; + } + + public override int Value + { + get { return values[0]; } + } + + public override string name() + { + return otherEncodingNames[0]; + } + + public int[] Values + { + get { return values; } + } + + public string[] OtherEncodingNames + { + get { return otherEncodingNames; } + } + } + + public abstract string name(); + + + // Enum name is a Java encoding valid for java.lang and java.io + public static readonly CharacterSetECI Cp437 = new innerCharacterSetECI(new int[] { 0, 2 },"Cp437",""); + public static readonly CharacterSetECI ISO8859_1 = new innerCharacterSetECI(new int[] { 1, 3 }, "ISO-8859-1",""); + + public static readonly CharacterSetECI ISO8859_2 = new innerCharacterSetECI(4, "ISO-8859-2","ISO8859_2"); + public static readonly CharacterSetECI ISO8859_3 = new innerCharacterSetECI(5, "ISO-8859-3","ISO8859_3"); + public static readonly CharacterSetECI ISO8859_4 = new innerCharacterSetECI(6, "ISO-8859-4","ISO8859_4"); + public static readonly CharacterSetECI ISO8859_5 = new innerCharacterSetECI(7, "ISO-8859-5","ISO8859_5"); + public static readonly CharacterSetECI ISO8859_6 = new innerCharacterSetECI(8, "ISO-8859-6","ISO8859_6"); + public static readonly CharacterSetECI ISO8859_7 = new innerCharacterSetECI(9, "ISO-8859-7","ISO8859_7"); + public static readonly CharacterSetECI ISO8859_8 = new innerCharacterSetECI(10, "ISO-8859-8","ISO8859_8"); + public static readonly CharacterSetECI ISO8859_9 = new innerCharacterSetECI(11, "ISO-8859-9","ISO8859_9"); + public static readonly CharacterSetECI ISO8859_10 = new innerCharacterSetECI(12, "ISO-8859-10","ISO8859_10"); + public static readonly CharacterSetECI ISO8859_11 = new innerCharacterSetECI(13, "ISO-8859-11","ISO8859_11"); + public static readonly CharacterSetECI ISO8859_13 = new innerCharacterSetECI(15, "ISO-8859-13","ISO8859_13"); + public static readonly CharacterSetECI ISO8859_14 = new innerCharacterSetECI(16, "ISO-8859-14","ISO8859_14"); + public static readonly CharacterSetECI ISO8859_15 = new innerCharacterSetECI(17, "ISO-8859-15","ISO8859_15"); + public static readonly CharacterSetECI ISO8859_16 = new innerCharacterSetECI(18, "ISO-8859-16","ISO8859_16"); + public static readonly CharacterSetECI SJIS = new innerCharacterSetECI(20, "Shift_JIS","SJIS"); + public static readonly CharacterSetECI Cp1250 = new innerCharacterSetECI(21, "windows-1250","Cp1250"); + public static readonly CharacterSetECI Cp1251 = new innerCharacterSetECI(22, "windows-1251","Cp1251"); + public static readonly CharacterSetECI Cp1252 = new innerCharacterSetECI(23, "windows-1252","Cp1252"); + public static readonly CharacterSetECI Cp1256 = new innerCharacterSetECI(24, "windows-1256","Cp1256"); + public static readonly CharacterSetECI UnicodeBigUnmarked = new innerCharacterSetECI(25, "UTF-16BE", "UnicodeBig","UnicodeBigUnmarked"); + public static readonly CharacterSetECI UTF8 = new innerCharacterSetECI(26, "UTF-8",""); + public static readonly CharacterSetECI ASCII = new innerCharacterSetECI(new int[] { 27, 170 }, "US-ASCII","ASCII"); + public static readonly CharacterSetECI Big5 = new innerCharacterSetECI(28,"Big5","Big5"); + public static readonly CharacterSetECI GB18030 = new innerCharacterSetECI(29, "GB2312", "EUC_CN", "GBK","GB18030"); + public static readonly CharacterSetECI EUC_KR = new innerCharacterSetECI(30, "EUC-KR","EUC_KR"); + + private static readonly Dictionary VALUE_TO_ECI = new Dictionary(); + private static readonly Dictionary NAME_TO_ECI = new Dictionary(); + + /// character set ECI value + /// CharacterSetECI representing ECI of given value, or null if it is legal but + /// unsupported + /// if ECI value is invalid + public static CharacterSetECI getCharacterSetECIByValue(int value) + { + if (value < 0 || value >= 900) + { + throw FormatException.FormatInstance; + } + if (VALUE_TO_ECI.ContainsKey(value)) + { + return VALUE_TO_ECI[value]; + } + return null; + + } + + /// character set ECI encoding name + /// CharacterSetECI representing ECI for character encoding, or null if it is legal + /// but unsupported + public static CharacterSetECI getCharacterSetECIByName(string name) + { + if (NAME_TO_ECI.ContainsKey(name)) + { + return NAME_TO_ECI[name]; + } + return null; + } + + public virtual int Value { get { throw new NotImplementedException(); } } + } + //public static partial class EnumExtensionMethods + //{ + // public static int getValue(this CharacterSetECI instanceJavaToDotNetTempPropertyGetValue) + // { + // return values[0]; + // } + //} + } \ No newline at end of file diff --git a/csharp/common/DecoderResult.cs b/csharp/common/DecoderResult.cs index 8cbf31aff..6a4999152 100755 --- a/csharp/common/DecoderResult.cs +++ b/csharp/common/DecoderResult.cs @@ -1,86 +1,79 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + * 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. + */ + namespace com.google.zxing.common { - - ///

Encapsulates the result of decoding a matrix of bits. This typically + + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class DecoderResult { - public sbyte[] RawBytes - { - get - { - return rawBytes; - } - - } - public System.String Text - { - get - { - return text; - } - - } - public System.Collections.ArrayList ByteSegments - { - get - { - return byteSegments; - } - - } - public ErrorCorrectionLevel ECLevel - { - get - { - return ecLevel; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'rawBytes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte[] rawBytes; - //UPGRADE_NOTE: Final was removed from the declaration of 'text '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String text; - //UPGRADE_NOTE: Final was removed from the declaration of 'byteSegments '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList byteSegments; - //UPGRADE_NOTE: Final was removed from the declaration of 'ecLevel '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ErrorCorrectionLevel ecLevel; - - public DecoderResult(sbyte[] rawBytes, System.String text, System.Collections.ArrayList byteSegments, ErrorCorrectionLevel ecLevel) - { - if (rawBytes == null && text == null) - { - throw new System.ArgumentException(); - } - this.rawBytes = rawBytes; - this.text = text; - this.byteSegments = byteSegments; - this.ecLevel = ecLevel; - } + + private readonly sbyte[] rawBytes; + private readonly string text; + private readonly IList byteSegments; + private readonly string ecLevel; + + public DecoderResult(sbyte[] rawBytes, string text, IList byteSegments, string ecLevel) + { + this.rawBytes = rawBytes; + this.text = text; + this.byteSegments = byteSegments; + this.ecLevel = ecLevel; + } + + public sbyte[] RawBytes + { + get + { + return rawBytes; + } + } + + public string Text + { + get + { + return text; + } + } + + public IList ByteSegments + { + get + { + return byteSegments; + } + } + + public string ECLevel + { + get + { + return ecLevel; + } + } + } } \ No newline at end of file diff --git a/csharp/common/DefaultGridSampler.cs b/csharp/common/DefaultGridSampler.cs index 1a789cb02..f8e860650 100755 --- a/csharp/common/DefaultGridSampler.cs +++ b/csharp/common/DefaultGridSampler.cs @@ -1,82 +1,89 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; + * 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. + */ + namespace com.google.zxing.common { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class DefaultGridSampler:GridSampler + + using NotFoundException = com.google.zxing.NotFoundException; + + /// + /// @author Sean Owen + /// + public sealed class DefaultGridSampler : GridSampler { - - public override BitMatrix sampleGrid(BitMatrix image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) throws com.google.zxing.NotFoundException + public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) + { + + PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); + + return sampleGrid(image, dimensionX, dimensionY, transform); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) throws com.google.zxing.NotFoundException + public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) + { + if (dimensionX <= 0 || dimensionY <= 0) { - - PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); - - return sampleGrid(image, dimension, transform); + throw NotFoundException.NotFoundInstance; } - - public override BitMatrix sampleGrid(BitMatrix image, int dimension, PerspectiveTransform transform) + BitMatrix bits = new BitMatrix(dimensionX, dimensionY); + float[] points = new float[dimensionX << 1]; + for (int y = 0; y < dimensionY; y++) { - BitMatrix bits = new BitMatrix(dimension); - float[] points = new float[dimension << 1]; - for (int y = 0; y < dimension; y++) + int max = points.Length; + float iValue = (float) y + 0.5f; + for (int x = 0; x < max; x += 2) + { + points[x] = (float)(x >> 1) + 0.5f; + points[x + 1] = iValue; + } + transform.transformPoints(points); + // Quick check to see if points transformed to something inside the image; + // sufficient to check the endpoints + checkAndNudgePoints(image, points); + try + { + for (int x = 0; x < max; x += 2) { - int max = points.Length; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float iValue = (float) y + 0.5f; - for (int x = 0; x < max; x += 2) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - points[x] = (float) (x >> 1) + 0.5f; - points[x + 1] = iValue; - } - transform.transformPoints(points); - // Quick check to see if points transformed to something inside the image; - // sufficient to check the endpoints - checkAndNudgePoints(image, points); - try - { - for (int x = 0; x < max; x += 2) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - if (image.get_Renamed((int) points[x], (int) points[x + 1])) - { - // Black(-ish) pixel - bits.set_Renamed(x >> 1, y); - } - } - } - catch (System.IndexOutOfRangeException) - { - // 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 ReaderException.Instance; - } + if (image.get((int) points[x], (int) points[x + 1])) + { + // Black(-ish) pixel + bits.set(x >> 1, y); + } } - return bits; + } + catch (System.IndexOutOfRangeException aioobe) + { + // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting + // transform gets "twisted" such that it maps a straight line of points to a set of points + // whose endpoints are in bounds, but others are not. There is probably some mathematical + // way to detect this about the transformation that I don't know yet. + // This results in an ugly runtime exception despite our clever checks above -- can't have + // that. We could check each point's coordinates but that feels duplicative. We settle for + // catching and wrapping ArrayIndexOutOfBoundsException. + throw NotFoundException.NotFoundInstance; + } } + return bits; + } + } -} + +} \ No newline at end of file diff --git a/csharp/common/DetectorResult.cs b/csharp/common/DetectorResult.cs index 9a327a467..637a89c89 100755 --- a/csharp/common/DetectorResult.cs +++ b/csharp/common/DetectorResult.cs @@ -1,60 +1,58 @@ /* -* 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. -*/ -using System; -using ResultPoint = com.google.zxing.ResultPoint; + * 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. + */ + namespace com.google.zxing.common { - - ///

Encapsulates the result of detecting a barcode in an image. This includes the raw + + using ResultPoint = com.google.zxing.ResultPoint; + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class DetectorResult + public class DetectorResult { - public BitMatrix Bits - { - get - { - return bits; - } - - } - public ResultPoint[] Points - { - get - { - return points; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'bits '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix bits; - //UPGRADE_NOTE: Final was removed from the declaration of 'points '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPoint[] points; - - public DetectorResult(BitMatrix bits, ResultPoint[] points) - { - this.bits = bits; - this.points = points; - } + + private readonly BitMatrix bits; + private readonly ResultPoint[] points; + + public DetectorResult(BitMatrix bits, ResultPoint[] points) + { + this.bits = bits; + this.points = points; + } + + public BitMatrix Bits + { + get + { + return bits; + } + } + + public ResultPoint[] Points + { + get + { + return points; + } + } + } } \ No newline at end of file diff --git a/csharp/common/GlobalHistogramBinarizer.cs b/csharp/common/GlobalHistogramBinarizer.cs index f6d0ae276..58d16b3b4 100755 --- a/csharp/common/GlobalHistogramBinarizer.cs +++ b/csharp/common/GlobalHistogramBinarizer.cs @@ -1,250 +1,237 @@ +using System.Collections; + /* -* 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. -*/ -using System; -using Binarizer = com.google.zxing.Binarizer; -using LuminanceSource = com.google.zxing.LuminanceSource; -using ReaderException = com.google.zxing.ReaderException; + * 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. + */ + namespace com.google.zxing.common { - - /// This Binarizer implementation uses the old ZXing global histogram approach. It is suitable + + using Binarizer = com.google.zxing.Binarizer; + using LuminanceSource = com.google.zxing.LuminanceSource; + using NotFoundException = com.google.zxing.NotFoundException; + + /// + /// 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. /// /// Faster mobile devices and all desktop applications should probably use HybridBinarizer instead. /// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public class GlobalHistogramBinarizer:Binarizer + public class GlobalHistogramBinarizer : com.google.zxing.Binarizer { - override public BitMatrix BlackMatrix - { - // Does not sharpen the data, as this call is intended to only be used by 2D Readers. - - get - { - LuminanceSource source = LuminanceSource; - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Added - // START - sbyte[] localLuminances; - //END - - int width = source.Width; - int height = source.Height; - BitMatrix matrix = 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); - int[] localBuckets = buckets; - for (int y = 1; y < 5; y++) - { - int row = height * y / 5; - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Commented & Added - // START - //sbyte[] localLuminances = source.getRow(row, luminances); - localLuminances = source.getRow(row, luminances); - // END - int right = (width << 2) / 5; - for (int x = width / 5; x < right; x++) - { - int pixel = localLuminances[x] & 0xff; - localBuckets[pixel >> LUMINANCE_SHIFT]++; - } - } - int blackPoint = 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.Matrix; // Govinda : Removed sbyte [] - for (int y = 0; y < height; y++) - { - int offset = y * width; - for (int x = 0; x < width; x++) - { - int pixel = localLuminances[offset + x] & 0xff; - if (pixel < blackPoint) - { - matrix.set_Renamed(x, y); - } - } - } - - return matrix; - } - - } - - private const int LUMINANCE_BITS = 5; - //UPGRADE_NOTE: Final was removed from the declaration of 'LUMINANCE_SHIFT '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; - //UPGRADE_NOTE: Final was removed from the declaration of 'LUMINANCE_BUCKETS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; - - private sbyte[] luminances = null; - private int[] buckets = null; - - public GlobalHistogramBinarizer(LuminanceSource source):base(source) + private const int LUMINANCE_BITS = 5; + private static readonly int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; + private static readonly int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; + private static readonly sbyte[] EMPTY = new sbyte[0]; + + private sbyte[] luminances; + private readonly int[] buckets; + + public GlobalHistogramBinarizer(LuminanceSource source) : base(source) + { + luminances = EMPTY; + buckets = new int[LUMINANCE_BUCKETS]; + } + + // Applies simple sharpening to the row data to improve performance of the 1D Readers. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public BitArray getBlackRow(int y, BitArray row) throws com.google.zxing.NotFoundException + public override BitArray getBlackRow(int y, BitArray row) + { + LuminanceSource source = LuminanceSource; + int width = source.Width; + if (row == null || row.Size < width) { + row = new BitArray(width); } - - // Applies simple sharpening to the row data to improve performance of the 1D Readers. - public override BitArray getBlackRow(int y, BitArray row) + else { + //row.SetAll(false); + row.clear(); + } + + initArrays(width); + sbyte[] localLuminances = source.getRow(y, luminances); + int[] localBuckets = buckets; + for (int x = 0; x < width; x++) + { + int pixel = localLuminances[x] & 0xff; + localBuckets[pixel >> LUMINANCE_SHIFT]++; + } + int blackPoint = estimateBlackPoint(localBuckets); + + int left = localLuminances[0] & 0xff; + int center = localLuminances[1] & 0xff; + for (int x = 1; x < width - 1; x++) + { + int right = localLuminances[x + 1] & 0xff; + // A simple -1 4 -1 box filter with a weight of 2. + int luminance = ((center << 2) - left - right) >> 1; + if (luminance < blackPoint) + { + //row.Set(x, true); + 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. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public BitMatrix getBlackMatrix() throws com.google.zxing.NotFoundException + public override BitMatrix BlackMatrix + { + get + { LuminanceSource source = LuminanceSource; int width = source.Width; - if (row == null || row.Size < width) - { - row = new BitArray(width); - } - else - { - row.clear(); - } - + int height = source.Height; + BitMatrix matrix = 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); - sbyte[] localLuminances = source.getRow(y, luminances); int[] localBuckets = buckets; - for (int x = 0; x < width; x++) + for (int y = 1; y < 5; y++) { - int pixel = localLuminances[x] & 0xff; + int row = height * y / 5; + sbyte[] localLuminances1 = source.getRow(row, luminances); + int right = (width << 2) / 5; + for (int x = width / 5; x < right; x++) + { + int pixel = localLuminances1[x] & 0xff; localBuckets[pixel >> LUMINANCE_SHIFT]++; + } } int blackPoint = estimateBlackPoint(localBuckets); - - int left = localLuminances[0] & 0xff; - int center = localLuminances[1] & 0xff; - for (int x = 1; x < width - 1; x++) + + // 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. + sbyte[] localLuminances = source.Matrix; + for (int y = 0; y < height; y++) { - int right = localLuminances[x + 1] & 0xff; - // A simple -1 4 -1 box filter with a weight of 2. - int luminance = ((center << 2) - left - right) >> 1; - if (luminance < blackPoint) + int offset = y * width; + for (int x = 0; x < width; x++) + { + int pixel = localLuminances[offset + x] & 0xff; + if (pixel < blackPoint) { - row.set_Renamed(x); + matrix.set(x, y); } - left = center; - center = right; + } } - return row; - } - - public override Binarizer createBinarizer(LuminanceSource source) + + return matrix; + } + } + + public override Binarizer createBinarizer(LuminanceSource source) + { + return new GlobalHistogramBinarizer(source); + } + + private void initArrays(int luminanceSize) + { + if (luminances.Length < luminanceSize) { - return new GlobalHistogramBinarizer(source); + luminances = new sbyte[luminanceSize]; } - - private void initArrays(int luminanceSize) + for (int x = 0; x < LUMINANCE_BUCKETS; x++) { - if (luminances == null || luminances.Length < luminanceSize) - { - luminances = new sbyte[luminanceSize]; - } - if (buckets == null) - { - buckets = new int[LUMINANCE_BUCKETS]; - } - else - { - for (int x = 0; x < LUMINANCE_BUCKETS; x++) - { - buckets[x] = 0; - } - } + buckets[x] = 0; } - - private static int estimateBlackPoint(int[] buckets) + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int estimateBlackPoint(int[] buckets) throws com.google.zxing.NotFoundException + private static int estimateBlackPoint(int[] buckets) + { + // Find the tallest peak in the histogram. + int numBuckets = buckets.Length; + int maxBucketCount = 0; + int firstPeak = 0; + int firstPeakSize = 0; + for (int x = 0; x < numBuckets; x++) { - // Find the tallest peak in the histogram. - int numBuckets = buckets.Length; - int maxBucketCount = 0; - int firstPeak = 0; - int firstPeakSize = 0; - for (int x = 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. - int secondPeak = 0; - int secondPeakScore = 0; - for (int x = 0; x < numBuckets; x++) - { - int distanceToBiggest = x - firstPeak; - // Encourage more distant second peaks by multiplying by square of distance. - int score = buckets[x] * distanceToBiggest * distanceToBiggest; - if (score > secondPeakScore) - { - secondPeak = x; - secondPeakScore = score; - } - } - - // Make sure firstPeak corresponds to the black peak. - if (firstPeak > secondPeak) - { - int temp = 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 ReaderException.Instance; - } - - // Find a valley between them that is low and closer to the white peak. - int bestValley = secondPeak - 1; - int bestValleyScore = - 1; - for (int x = secondPeak - 1; x > firstPeak; x--) - { - int fromFirst = x - firstPeak; - int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]); - if (score > bestValleyScore) - { - bestValley = x; - bestValleyScore = score; - } - } - - return bestValley << LUMINANCE_SHIFT; + 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. + int secondPeak = 0; + int secondPeakScore = 0; + for (int x = 0; x < numBuckets; x++) + { + int distanceToBiggest = x - firstPeak; + // Encourage more distant second peaks by multiplying by square of distance. + int score = buckets[x] * distanceToBiggest * distanceToBiggest; + if (score > secondPeakScore) + { + secondPeak = x; + secondPeakScore = score; + } + } + + // Make sure firstPeak corresponds to the black peak. + if (firstPeak > secondPeak) + { + int temp = 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. + if (secondPeak - firstPeak <= numBuckets >> 4) + { + throw NotFoundException.NotFoundInstance; + } + + // Find a valley between them that is low and closer to the white peak. + int bestValley = secondPeak - 1; + int bestValleyScore = -1; + for (int x = secondPeak - 1; x > firstPeak; x--) + { + int fromFirst = x - firstPeak; + int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]); + if (score > bestValleyScore) + { + bestValley = x; + bestValleyScore = score; + } + } + + return bestValley << LUMINANCE_SHIFT; + } + } + } \ No newline at end of file diff --git a/csharp/common/GridSampler.cs b/csharp/common/GridSampler.cs index bec46b73a..13e779eea 100755 --- a/csharp/common/GridSampler.cs +++ b/csharp/common/GridSampler.cs @@ -1,193 +1,170 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; + * 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. + */ + namespace com.google.zxing.common { - - /// Implementations of this class can, given locations of finder patterns for a QR code in an + + using NotFoundException = com.google.zxing.NotFoundException; + + /// + /// 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)} + /// The implementation used can be controlled by calling /// with an instance of a class which implements this interface. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public abstract class GridSampler { - /// the current implementation of {@link GridSampler} - /// - public static GridSampler Instance + + private static GridSampler gridSampler = new DefaultGridSampler(); + + /// + /// Sets the implementation of 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. + /// + /// The platform-specific object to install. + public static GridSampler GridSampler2 + { + set + { + gridSampler = value; + } + } + + /// the current implementation of GridSampler + public static GridSampler Instance + { + get + { + return gridSampler; + } + } + + /// + /// Samples an image for a rectangular matrix of bits of the given dimension. + /// image to sample + /// width of to sample from image + /// height of to sample from image + /// representing a grid of points sampled from the image within a region + /// defined by the "from" parameters + /// 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 +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) throws com.google.zxing.NotFoundException; + public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) throws com.google.zxing.NotFoundException; + public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform); + + /// + ///

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.

+ /// + ///

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.

+ /// + ///

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.

+ ///
+ /// image into which the points should map + /// actual points in x1,y1,...,xn,yn form + /// if an endpoint is lies outside the image boundaries +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected static void checkAndNudgePoints(BitMatrix image, float[] points) throws com.google.zxing.NotFoundException + protected internal static void checkAndNudgePoints(BitMatrix image, float[] points) + { + int width = image.Width; + int height = image.Height; + // Check and nudge points from start until we see some that are OK: + bool nudged = true; + for (int offset = 0; offset < points.Length && nudged; offset += 2) { - get - { - return gridSampler; - } - - } - - private static GridSampler gridSampler = new DefaultGridSampler(); - - /// 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. - /// - /// - /// The platform-specific object to install. - /// - public static void setGridSampler(GridSampler newGridSampler) - { - if (newGridSampler == null) - { - throw new System.ArgumentException(); - } - gridSampler = newGridSampler; - } - - ///

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.

- /// - ///

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.

- /// - ///

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.

- /// - ///

These 16 parameters define the transformation needed to sample the image.

- /// - ///
- /// image to sample - /// - /// width/height of {@link BitMatrix} to sample from image - /// - /// {@link BitMatrix} representing a grid of points sampled from the image within a region - /// defined by the "from" parameters - /// - /// 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 abstract BitMatrix sampleGrid(BitMatrix image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); - - public virtual BitMatrix sampleGrid(BitMatrix image, int dimension, PerspectiveTransform transform) - { - throw new System.NotSupportedException(); - } - - - ///

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.

- /// - ///

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.

- /// - ///

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.

- /// - ///
- /// image into which the points should map - /// - /// actual points in x1,y1,...,xn,yn form - /// - /// ReaderException if an endpoint is lies outside the image boundaries - protected internal static void checkAndNudgePoints(BitMatrix image, float[] points) - { - int width = image.Width; - int height = image.Height; - // Check and nudge points from start until we see some that are OK: - bool nudged = true; - for (int offset = 0; offset < points.Length && nudged; offset += 2) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int x = (int) points[offset]; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int y = (int) points[offset + 1]; - if (x < - 1 || x > width || y < - 1 || y > height) - { - throw ReaderException.Instance; - } - nudged = false; - if (x == - 1) - { - points[offset] = 0.0f; - nudged = true; - } - else if (x == width) - { - points[offset] = width - 1; - nudged = true; - } - if (y == - 1) - { - points[offset + 1] = 0.0f; - nudged = true; - } - else if (y == height) - { - points[offset + 1] = height - 1; - nudged = true; - } - } - // Check and nudge points from end: + int x = (int) points[offset]; + int y = (int) points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) + { + throw NotFoundException.NotFoundInstance; + } + nudged = false; + if (x == -1) + { + points[offset] = 0.0f; nudged = true; - for (int offset = points.Length - 2; offset >= 0 && nudged; offset -= 2) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int x = (int) points[offset]; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int y = (int) points[offset + 1]; - if (x < - 1 || x > width || y < - 1 || y > height) - { - throw ReaderException.Instance; - } - nudged = false; - if (x == - 1) - { - points[offset] = 0.0f; - nudged = true; - } - else if (x == width) - { - points[offset] = width - 1; - nudged = true; - } - if (y == - 1) - { - points[offset + 1] = 0.0f; - nudged = true; - } - else if (y == height) - { - points[offset + 1] = height - 1; - nudged = true; - } - } + } + else if (x == width) + { + points[offset] = width - 1; + nudged = true; + } + if (y == -1) + { + points[offset + 1] = 0.0f; + nudged = true; + } + else if (y == height) + { + points[offset + 1] = height - 1; + nudged = true; + } } + // Check and nudge points from end: + nudged = true; + for (int offset = points.Length - 2; offset >= 0 && nudged; offset -= 2) + { + int x = (int) points[offset]; + int y = (int) points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) + { + throw NotFoundException.NotFoundInstance; + } + nudged = false; + if (x == -1) + { + points[offset] = 0.0f; + nudged = true; + } + else if (x == width) + { + points[offset] = width - 1; + nudged = true; + } + if (y == -1) + { + points[offset + 1] = 0.0f; + nudged = true; + } + else if (y == height) + { + points[offset + 1] = height - 1; + nudged = true; + } + } + } + } + } \ No newline at end of file diff --git a/csharp/common/HybridBinarizer.cs b/csharp/common/HybridBinarizer.cs index 19d8fa371..d9a1698a2 100755 --- a/csharp/common/HybridBinarizer.cs +++ b/csharp/common/HybridBinarizer.cs @@ -1,26 +1,28 @@ /* -* 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. -*/ -using System; -using Binarizer = com.google.zxing.Binarizer; -using LuminanceSource = com.google.zxing.LuminanceSource; -using ReaderException = com.google.zxing.ReaderException; + * 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. + */ + namespace com.google.zxing.common { - - /// This class implements a local thresholding algorithm, which while slower than the + + using Binarizer = com.google.zxing.Binarizer; + using LuminanceSource = com.google.zxing.LuminanceSource; + using NotFoundException = com.google.zxing.NotFoundException; + + /// + /// 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. @@ -34,154 +36,229 @@ namespace com.google.zxing.common /// /// This Binarizer is the default for the unit tests and the recommended class for library users. /// + /// @author dswitkin@google.com (Daniel Switkin) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class HybridBinarizer:GlobalHistogramBinarizer + public sealed class HybridBinarizer : GlobalHistogramBinarizer { - override public BitMatrix BlackMatrix - { - get + + // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. + // So this is the smallest dimension in each axis we can accept. + private const int BLOCK_SIZE_POWER = 3; + private static readonly int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER; // ...0100...00 + private static readonly int BLOCK_SIZE_MASK = BLOCK_SIZE - 1; // ...0011...11 + private static readonly int MINIMUM_DIMENSION = BLOCK_SIZE * 5; + private const int MIN_DYNAMIC_RANGE = 24; + + private BitMatrix matrix; + + public HybridBinarizer(LuminanceSource source) : base(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. + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public BitMatrix getBlackMatrix() throws com.google.zxing.NotFoundException + public override BitMatrix BlackMatrix + { + get + { + if (matrix != null) { - binarizeEntireImage(); - return matrix; + return matrix; } - - } - - // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. - // So this is the smallest dimension in each axis we can accept. - private const int MINIMUM_DIMENSION = 40; - - private BitMatrix matrix = null; - - public HybridBinarizer(LuminanceSource source):base(source) - { - } - - public override Binarizer createBinarizer(LuminanceSource source) - { - return new HybridBinarizer(source); - } - - // Calculates the final BitMatrix once for all requests. This could be called once from the - // constructor instead, but there are some advantages to doing it lazily, such as making - // profiling easier, and not doing heavy lifting when callers don't expect it. - private void binarizeEntireImage() - { - if (matrix == null) + LuminanceSource source = LuminanceSource; + int width = source.Width; + int height = source.Height; + if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) { - LuminanceSource source = LuminanceSource; - if (source.Width >= MINIMUM_DIMENSION && source.Height >= MINIMUM_DIMENSION) + sbyte[] luminances = source.Matrix; + int subWidth = width >> BLOCK_SIZE_POWER; + if ((width & BLOCK_SIZE_MASK) != 0) + { + subWidth++; + } + int subHeight = height >> BLOCK_SIZE_POWER; + if ((height & BLOCK_SIZE_MASK) != 0) + { + subHeight++; + } + int[][] blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width, height); + + BitMatrix newMatrix = new BitMatrix(width, height); + calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix); + matrix = newMatrix; + } + else + { + // If the image is too small, fall back to the global histogram approach. + matrix = base.BlackMatrix; + } + return matrix; + } + } + + public override Binarizer createBinarizer(LuminanceSource source) + { + return new HybridBinarizer(source); + } + + /// + /// For each block in the image, calculate the average black point using a 5x5 grid + /// of the blocks around it. Also handles the corner cases (fractional blocks are computed based + /// on the last pixels in the row/column which are also used in the previous block). + /// + private static void calculateThresholdForBlock(sbyte[] luminances, int subWidth, int subHeight, int width, int height, int[][] blackPoints, BitMatrix matrix) + { + for (int y = 0; y < subHeight; y++) + { + int yoffset = y << BLOCK_SIZE_POWER; + int maxYOffset = height - BLOCK_SIZE; + if (yoffset > maxYOffset) + { + yoffset = maxYOffset; + } + for (int x = 0; x < subWidth; x++) + { + int xoffset = x << BLOCK_SIZE_POWER; + int maxXOffset = width - BLOCK_SIZE; + if (xoffset > maxXOffset) + { + xoffset = maxXOffset; + } + int left = cap(x, 2, subWidth - 3); + int top = cap(y, 2, subHeight - 3); + int sum = 0; + for (int z = -2; z <= 2; z++) + { + int[] blackRow = blackPoints[top + z]; + sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2]; + } + int average = sum / 25; + thresholdBlock(luminances, xoffset, yoffset, average, width, matrix); + } + } + } + + private static int cap(int value, int min, int max) + { + return value < min ? min : value > max ? max : value; + } + + /// + /// Applies a single threshold to a block of pixels. + /// + private static void thresholdBlock(sbyte[] luminances, int xoffset, int yoffset, int threshold, int stride, BitMatrix matrix) + { + for (int y = 0, offset = yoffset * stride + xoffset; y < BLOCK_SIZE; y++, offset += stride) + { + for (int x = 0; x < BLOCK_SIZE; x++) + { + // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0. + if ((luminances[offset + x] & 0xFF) <= threshold) + { + matrix.set(xoffset + x, yoffset + y); + } + } + } + } + + /// + /// Calculates a single black point for each block of pixels and saves it away. + /// See the following thread for a discussion of this algorithm: + /// http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 + /// + private static int[][] calculateBlackPoints(sbyte[] luminances, int subWidth, int subHeight, int width, int height) + { +//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: +//ORIGINAL LINE: int[][] blackPoints = new int[subHeight][subWidth]; + int[][] blackPoints = RectangularArrays.ReturnRectangularIntArray(subHeight, subWidth); + for (int y = 0; y < subHeight; y++) + { + int yoffset = y << BLOCK_SIZE_POWER; + int maxYOffset = height - BLOCK_SIZE; + if (yoffset > maxYOffset) + { + yoffset = maxYOffset; + } + for (int x = 0; x < subWidth; x++) + { + int xoffset = x << BLOCK_SIZE_POWER; + int maxXOffset = width - BLOCK_SIZE; + if (xoffset > maxXOffset) + { + xoffset = maxXOffset; + } + int sum = 0; + int min = 0xFF; + int max = 0; + for (int yy = 0, offset = yoffset * width + xoffset; yy < BLOCK_SIZE; yy++, offset += width) + { + for (int xx = 0; xx < BLOCK_SIZE; xx++) + { + int pixel = luminances[offset + xx] & 0xFF; + sum += pixel; + // still looking for good contrast + if (pixel < min) { - sbyte[] luminances = source.Matrix; - int width = source.Width; - int height = source.Height; - int subWidth = width >> 3; - int subHeight = height >> 3; - int[][] blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width); - - matrix = new BitMatrix(width, height); - calculateThresholdForBlock(luminances, subWidth, subHeight, width, blackPoints, matrix); + min = pixel; } - else + if (pixel > max) { - // If the image is too small, fall back to the global histogram approach. - matrix = base.BlackMatrix; + max = pixel; } - } - } - - // 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 dimensions are not - // multiples of eight. In practice, leaving those pixels white does not seem to be a problem. - private static void calculateThresholdForBlock(sbyte[] luminances, int subWidth, int subHeight, int stride, int[][] blackPoints, BitMatrix matrix) - { - for (int y = 0; y < subHeight; y++) - { - for (int x = 0; x < subWidth; x++) + } + // short-circuit min/max tests once dynamic range is met + if (max - min > MIN_DYNAMIC_RANGE) + { + // finish the rest of the rows quickly + for (yy++, offset += width; yy < BLOCK_SIZE; yy++, offset += width) { - int left = (x > 1)?x:2; - left = (left < subWidth - 2)?left:subWidth - 3; - int top = (y > 1)?y:2; - top = (top < subHeight - 2)?top:subHeight - 3; - int sum = 0; - for (int z = - 2; z <= 2; z++) - { - int[] blackRow = blackPoints[top + z]; - sum += blackRow[left - 2]; - sum += blackRow[left - 1]; - sum += blackRow[left]; - sum += blackRow[left + 1]; - sum += blackRow[left + 2]; - } - int average = sum / 25; - threshold8x8Block(luminances, x << 3, y << 3, average, stride, matrix); + for (int xx = 0; xx < BLOCK_SIZE; xx++) + { + sum += luminances[offset + xx] & 0xFF; + } } + } } - } - - // Applies a single threshold to an 8x8 block of pixels. - private static void threshold8x8Block(sbyte[] luminances, int xoffset, int yoffset, int threshold, int stride, BitMatrix matrix) - { - for (int y = 0; y < 8; y++) + + // The default estimate is the average of the values in the block. + int average = sum >> (BLOCK_SIZE_POWER * 2); + if (max - min <= MIN_DYNAMIC_RANGE) { - int offset = (yoffset + y) * stride + xoffset; - for (int x = 0; x < 8; x++) + // If variation within the block is low, assume this is a block with only light or only + // dark pixels. In that case we do not want to use the average, as it would divide this + // low contrast area into black and white pixels, essentially creating data out of noise. + // + // The default assumption is that the block is light/background. Since no estimate for + // the level of dark pixels exists locally, use half the min for the block. + average = min >> 1; + + if (y > 0 && x > 0) + { + // Correct the "white background" assumption for blocks that have neighbors by comparing + // the pixels in this block to the previously calculated black points. This is based on + // the fact that dark barcode symbology is always surrounded by some amount of light + // background for which reasonable black point estimates were made. The bp estimated at + // the boundaries is used for the interior. + + // The (min < bp) is arbitrary but works better than other heuristics that were tried. + int averageNeighborBlackPoint = (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) >> 2; + if (min < averageNeighborBlackPoint) { - int pixel = luminances[offset + x] & 0xff; - if (pixel < threshold) - { - matrix.set_Renamed(xoffset + x, yoffset + y); - } + average = averageNeighborBlackPoint; } + } } + blackPoints[y][x] = average; + } } - - // Calculates a single black point for each 8x8 block of pixels and saves it away. - private static int[][] calculateBlackPoints(sbyte[] luminances, int subWidth, int subHeight, int stride) - { - int[][] blackPoints = new int[subHeight][]; - for (int i = 0; i < subHeight; i++) - { - blackPoints[i] = new int[subWidth]; - } - for (int y = 0; y < subHeight; y++) - { - for (int x = 0; x < subWidth; x++) - { - int sum = 0; - int min = 255; - int max = 0; - for (int yy = 0; yy < 8; yy++) - { - int offset = ((y << 3) + yy) * stride + (x << 3); - for (int xx = 0; xx < 8; xx++) - { - int pixel = 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. - int average = (max - min > 24)?(sum >> 6):(min >> 1); - blackPoints[y][x] = average; - } - } - return blackPoints; - } + return blackPoints; + } + } + } \ No newline at end of file diff --git a/csharp/common/PerspectiveTransform.cs b/csharp/common/PerspectiveTransform.cs index b516ef735..7928d03a6 100755 --- a/csharp/common/PerspectiveTransform.cs +++ b/csharp/common/PerspectiveTransform.cs @@ -1,146 +1,140 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.common { - - ///

This class implements a perspective transform in two dimensions. Given four source and four + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class PerspectiveTransform { - - //UPGRADE_NOTE: Final was removed from the declaration of 'a11 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a12 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a13 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a21 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a22 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a23 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a31 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a32 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_NOTE: Final was removed from the declaration of 'a33 '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float a11; - private float a12; - private float a13; - private float a21; - private float a22; - private float a23; - private float a31; - private float a32; - private float a33; - - private PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, float a33) + + private readonly float a11; + private readonly float a12; + private readonly float a13; + private readonly float a21; + private readonly float a22; + private readonly float a23; + private readonly float a31; + private readonly float a32; + private readonly float a33; + + private PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, float a33) + { + 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 PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p) + { + + PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); + PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); + return sToQ.times(qToS); + } + + public void transformPoints(float[] points) + { + int max = points.Length; + float a11 = this.a11; + float a12 = this.a12; + float a13 = this.a13; + float a21 = this.a21; + float a22 = this.a22; + float a23 = this.a23; + float a31 = this.a31; + float a32 = this.a32; + float a33 = this.a33; + for (int i = 0; i < max; i += 2) { - 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; + float x = points[i]; + float y = points[i + 1]; + float denominator = a13 * x + a23 * y + a33; + points[i] = (a11 * x + a21 * y + a31) / denominator; + points[i + 1] = (a12 * x + a22 * y + a32) / denominator; } - - public static PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p) + } + + /// + /// Convenience method, not optimized for performance. + public void transformPoints(float[] xValues, float[] yValues) + { + int n = xValues.Length; + for (int i = 0; i < n; i++) { - - PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); - PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); - return sToQ.times(qToS); + float x = xValues[i]; + float y = yValues[i]; + float denominator = a13 * x + a23 * y + a33; + xValues[i] = (a11 * x + a21 * y + a31) / denominator; + yValues[i] = (a12 * x + a22 * y + a32) / denominator; } - - public void transformPoints(float[] points) + } + + public static PerspectiveTransform squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) + { + float dx3 = x0 - x1 + x2 - x3; + float dy3 = y0 - y1 + y2 - y3; + if (dx3 == 0.0f && dy3 == 0.0f) { - int max = points.Length; - float a11 = this.a11; - float a12 = this.a12; - float a13 = this.a13; - float a21 = this.a21; - float a22 = this.a22; - float a23 = this.a23; - float a31 = this.a31; - float a32 = this.a32; - float a33 = this.a33; - for (int i = 0; i < max; i += 2) - { - float x = points[i]; - float y = points[i + 1]; - float denominator = a13 * x + a23 * y + a33; - points[i] = (a11 * x + a21 * y + a31) / denominator; - points[i + 1] = (a12 * x + a22 * y + a32) / denominator; - } + // Affine + return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, 0.0f, 1.0f); } - - /// Convenience method, not optimized for performance. - public void transformPoints(float[] xValues, float[] yValues) + else { - int n = xValues.Length; - for (int i = 0; i < n; i++) - { - float x = xValues[i]; - float y = yValues[i]; - float denominator = a13 * x + a23 * y + a33; - xValues[i] = (a11 * x + a21 * y + a31) / denominator; - yValues[i] = (a12 * x + a22 * y + a32) / denominator; - } - } - - public static PerspectiveTransform squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) - { - float dy2 = y3 - y2; - float dy3 = y0 - y1 + y2 - y3; - if (dy2 == 0.0f && dy3 == 0.0f) - { - return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, 0.0f, 1.0f); - } - else - { - float dx1 = x1 - x2; - float dx2 = x3 - x2; - float dx3 = x0 - x1 + x2 - x3; - float dy1 = y1 - y2; - float denominator = dx1 * dy2 - dx2 * dy1; - float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; - float a23 = (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.0f); - } - } - - public static PerspectiveTransform quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) - { - // Here, the adjoint serves as the inverse: - return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); - } - - internal PerspectiveTransform buildAdjoint() - { - // 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); - } - - internal PerspectiveTransform times(PerspectiveTransform other) - { - 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); + float dx1 = x1 - x2; + float dx2 = x3 - x2; + float dy1 = y1 - y2; + float dy2 = y3 - y2; + float denominator = dx1 * dy2 - dx2 * dy1; + float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; + float a23 = (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.0f); } + } + + public static PerspectiveTransform quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) + { + // Here, the adjoint serves as the inverse: + return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); + } + + internal PerspectiveTransform buildAdjoint() + { + // 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); + } + + internal PerspectiveTransform times(PerspectiveTransform other) + { + 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); + + } + } + } \ No newline at end of file diff --git a/csharp/common/detector/MonochromeRectangleDetector.cs b/csharp/common/detector/MonochromeRectangleDetector.cs index eea5cb107..5f8b078a1 100755 --- a/csharp/common/detector/MonochromeRectangleDetector.cs +++ b/csharp/common/detector/MonochromeRectangleDetector.cs @@ -1,255 +1,237 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using BitMatrix = com.google.zxing.common.BitMatrix; + +/* + * 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. + */ + namespace com.google.zxing.common.detector { - - ///

A somewhat generic detector that looks for a barcode-like rectangular region within an image. + + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class MonochromeRectangleDetector { - - private const int MAX_MODULES = 32; - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix image; - - public MonochromeRectangleDetector(BitMatrix image) + + private const int MAX_MODULES = 32; + + private readonly BitMatrix image; + + public MonochromeRectangleDetector(BitMatrix image) + { + this.image = image; + } + + /// + ///

Detects a rectangular region of black and white -- mostly black -- with a region of mostly + /// white, in an image.

+ ///
+ /// [] 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 + /// if no Data Matrix Code can be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.ResultPoint[] detect() throws com.google.zxing.NotFoundException + public ResultPoint[] detect() + { + int height = image.Height; + int width = image.Width; + int halfHeight = height >> 1; + int halfWidth = width >> 1; + int deltaY = Math.Max(1, height / (MAX_MODULES << 3)); + int deltaX = Math.Max(1, width / (MAX_MODULES << 3)); + + int top = 0; + int bottom = height; + int left = 0; + int right = width; + ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, -deltaY, top, bottom, halfWidth >> 1); + top = (int) pointA.Y - 1; + ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1); + left = (int) pointB.X - 1; + ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1); + right = (int) pointC.X + 1; + ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, deltaY, top, bottom, halfWidth >> 1); + bottom = (int) pointD.Y + 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 new ResultPoint[] {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. + /// + /// center's x component (horizontal) + /// same as deltaY but change in x per step instead + /// minimum value of x + /// maximum value of x + /// center's y component (vertical) + /// change in y per step. If scanning up this is negative; down, positive; + /// left or right, 0 + /// minimum value of y to search through (meaningless when di == 0) + /// maximum value of y + /// maximum run of white pixels that can still be considered to be within + /// the barcode + /// a encapsulating the corner that was found + /// if such a point cannot be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private com.google.zxing.ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, int centerY, int deltaY, int top, int bottom, int maxWhiteRun) throws com.google.zxing.NotFoundException + private ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, int centerY, int deltaY, int top, int bottom, int maxWhiteRun) + { + int[] lastRange = null; + for (int y = centerY, x = centerX; y < bottom && y >= top && x < right && x >= left; y += deltaY, x += deltaX) { - this.image = image; - } - - ///

Detects a rectangular region of black and white -- mostly black -- with a region of mostly - /// white, in an image.

- /// - ///
- /// {@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 - /// - /// ReaderException if no Data Matrix Code can be found - public ResultPoint[] detect() - { - int height = image.Height; - int width = image.Width; - int halfHeight = height >> 1; - int halfWidth = width >> 1; - int deltaY = System.Math.Max(1, height / (MAX_MODULES << 3)); - int deltaX = System.Math.Max(1, width / (MAX_MODULES << 3)); - - int top = 0; - int bottom = height; - int left = 0; - int right = width; - ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, - deltaY, top, bottom, halfWidth >> 1); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - top = (int) pointA.Y - 1; - ResultPoint pointB = findCornerFromCenter(halfWidth, - deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - left = (int) pointB.X - 1; - ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - right = (int) pointC.X + 1; - ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, deltaY, top, bottom, halfWidth >> 1); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - bottom = (int) pointD.Y + 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 new ResultPoint[]{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. - /// - /// - /// center's x component (horizontal) - /// - /// same as deltaY but change in x per step instead - /// - /// minimum value of x - /// - /// maximum value of x - /// - /// center's y component (vertical) - /// - /// change in y per step. If scanning up this is negative; down, positive; - /// left or right, 0 - /// - /// minimum value of y to search through (meaningless when di == 0) - /// - /// maximum value of y - /// - /// maximum run of white pixels that can still be considered to be within - /// the barcode - /// - /// a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found - /// - /// com.google.zxing.ReaderException if such a point cannot be found - private ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, int centerY, int deltaY, int top, int bottom, int maxWhiteRun) - { - int[] lastRange = null; - for (int y = centerY, x = centerX; y < bottom && y >= top && x < right && x >= left; y += deltaY, x += deltaX) + int[] range; + 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) { - int[] range; - 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 ReaderException.Instance; - } - // lastRange was found - if (deltaX == 0) - { - int lastY = 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 - { - int lastX = 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 NotFoundException.NotFoundInstance; } - throw ReaderException.Instance; + // lastRange was found + if (deltaX == 0) + { + int lastY = 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 + { + int lastX = 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; } - - /// Computes the start and end of a region of pixels, either horizontally or vertically, that could - /// be part of a Data Matrix barcode. - /// - /// - /// if scanning horizontally, this is the row (the fixed vertical location) - /// where we are scanning. If scanning vertically it's the column, the fixed horizontal location - /// - /// largest run of white pixels that can still be considered part of the - /// barcode region - /// - /// minimum pixel location, horizontally or vertically, to consider - /// - /// maximum pixel location, horizontally or vertically, to consider - /// - /// if true, we're scanning left-right, instead of up-down - /// - /// int[] with start and end of found range, or null if no such range is found - /// (e.g. only white was found) - /// - private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, bool horizontal) + throw NotFoundException.NotFoundInstance; + } + + /// + /// Computes the start and end of a region of pixels, either horizontally or vertically, that could + /// be part of a Data Matrix barcode. + /// + /// if scanning horizontally, this is the row (the fixed vertical location) + /// where we are scanning. If scanning vertically it's the column, the fixed horizontal location + /// largest run of white pixels that can still be considered part of the + /// barcode region + /// minimum pixel location, horizontally or vertically, to consider + /// maximum pixel location, horizontally or vertically, to consider + /// if true, we're scanning left-right, instead of up-down + /// int[] with start and end of found range, or null if no such range is found + /// (e.g. only white was found) + private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, bool horizontal) + { + + int center = (minDim + maxDim) >> 1; + + // Scan left/up first + int start = center; + while (start >= minDim) { - - int center = (minDim + maxDim) >> 1; - - // Scan left/up first - int start = center; - while (start >= minDim) + if (horizontal ? image.get(start, fixedDimension) : image.get(fixedDimension, start)) + { + start--; + } + else + { + int whiteRunStart = start; + do { - if (horizontal?image.get_Renamed(start, fixedDimension):image.get_Renamed(fixedDimension, start)) - { - start--; - } - else - { - int whiteRunStart = start; - do - { - start--; - } - while (start >= minDim && !(horizontal?image.get_Renamed(start, fixedDimension):image.get_Renamed(fixedDimension, start))); - int whiteRunSize = whiteRunStart - start; - if (start < minDim || whiteRunSize > maxWhiteRun) - { - start = whiteRunStart; - break; - } - } - } - start++; - - // Then try right/down - int end = center; - while (end < maxDim) + start--; + } while (start >= minDim && !(horizontal ? image.get(start, fixedDimension) : image.get(fixedDimension, start))); + int whiteRunSize = whiteRunStart - start; + if (start < minDim || whiteRunSize > maxWhiteRun) { - if (horizontal?image.get_Renamed(end, fixedDimension):image.get_Renamed(fixedDimension, end)) - { - end++; - } - else - { - int whiteRunStart = end; - do - { - end++; - } - while (end < maxDim && !(horizontal?image.get_Renamed(end, fixedDimension):image.get_Renamed(fixedDimension, end))); - int whiteRunSize = end - whiteRunStart; - if (end >= maxDim || whiteRunSize > maxWhiteRun) - { - end = whiteRunStart; - break; - } - } + start = whiteRunStart; + break; } - end--; - - return end > start?new int[]{start, end}:null; + } } + start++; + + // Then try right/down + int end = center; + while (end < maxDim) + { + if (horizontal ? image.get(end, fixedDimension) : image.get(fixedDimension, end)) + { + end++; + } + else + { + int whiteRunStart = end; + do + { + end++; + } while (end < maxDim && !(horizontal ? image.get(end, fixedDimension) : image.get(fixedDimension, end))); + int whiteRunSize = end - whiteRunStart; + if (end >= maxDim || whiteRunSize > maxWhiteRun) + { + end = whiteRunStart; + break; + } + } + } + end--; + + return end > start ? new int[]{start, end} : null; + } + } } \ No newline at end of file diff --git a/csharp/common/reedsolomon/ReedSolomonDecoder.cs b/csharp/common/reedsolomon/ReedSolomonDecoder.cs index 18123116e..8aaa3625d 100755 --- a/csharp/common/reedsolomon/ReedSolomonDecoder.cs +++ b/csharp/common/reedsolomon/ReedSolomonDecoder.cs @@ -1,23 +1,24 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.common.reedsolomon { - - ///

Implements Reed-Solomon decoding, as the name implies.

+ + /// + ///

Implements Reed-Solomon decoding, as the name implies.

/// ///

The algorithm will not be explained here, but the following references were helpful /// in creating this implementation:

@@ -34,184 +35,184 @@ namespace com.google.zxing.common.reedsolomon ///

Much credit is due to William Rucklidge since portions of this code are an indirect /// port of his C++ Reed-Solomon implementation.

/// + /// @author Sean Owen + /// @author William Rucklidge + /// @author sanfordsquires ///
- /// Sean Owen - /// - /// William Rucklidge - /// - /// sanfordsquires - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class ReedSolomonDecoder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'field '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private GF256 field; - - public ReedSolomonDecoder(GF256 field) + + private readonly GenericGF field; + + public ReedSolomonDecoder(GenericGF field) + { + this.field = field; + } + + /// + ///

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.

+ ///
+ /// data and error-correction codewords + /// number of error-correction codewords available + /// if decoding fails for any reason +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public void decode(int[] received, int twoS) throws ReedSolomonException + public void decode(int[] received, int twoS) + { + GenericGFPoly poly = new GenericGFPoly(field, received); + int[] syndromeCoefficients = new int[twoS]; + bool dataMatrix = field.Equals(GenericGF.DATA_MATRIX_FIELD_256); + bool noError = true; + for (int i = 0; i < twoS; i++) { - this.field = field; + // Thanks to sanfordsquires for this fix: + int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i)); + syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; + if (eval != 0) + { + noError = false; + } } - - ///

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.

- /// - ///
- /// data and error-correction codewords - /// - /// number of error-correction codewords available - /// - /// ReedSolomonException if decoding fails for any reason - public void decode(int[] received, int twoS) + if (noError) { - GF256Poly poly = new GF256Poly(field, received); - int[] syndromeCoefficients = new int[twoS]; - bool dataMatrix = field.Equals(GF256.DATA_MATRIX_FIELD); - bool noError = true; - for (int i = 0; i < twoS; i++) - { - // Thanks to sanfordsquires for this fix: - int eval = poly.evaluateAt(field.exp(dataMatrix?i + 1:i)); - syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval; - if (eval != 0) - { - noError = false; - } - } - if (noError) - { - return ; - } - GF256Poly syndrome = new GF256Poly(field, syndromeCoefficients); - GF256Poly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); - GF256Poly sigma = sigmaOmega[0]; - GF256Poly omega = sigmaOmega[1]; - int[] errorLocations = findErrorLocations(sigma); - int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); - for (int i = 0; i < errorLocations.Length; i++) - { - int position = received.Length - 1 - field.log(errorLocations[i]); - if (position < 0) - { - throw new ReedSolomonException("Bad error location"); - } - received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]); - } + return; } - - private GF256Poly[] runEuclideanAlgorithm(GF256Poly a, GF256Poly b, int R) + GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients); + GenericGFPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS); + GenericGFPoly sigma = sigmaOmega[0]; + GenericGFPoly omega = sigmaOmega[1]; + int[] errorLocations = findErrorLocations(sigma); + int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); + for (int i = 0; i < errorLocations.Length; i++) { - // Assume a's degree is >= b's - if (a.Degree < b.Degree) - { - GF256Poly temp = a; - a = b; - b = temp; - } - - GF256Poly rLast = a; - GF256Poly r = b; - GF256Poly sLast = field.One; - GF256Poly s = field.Zero; - GF256Poly tLast = field.Zero; - GF256Poly t = field.One; - - // Run Euclidean algorithm until r's degree is less than R/2 - while (r.Degree >= R / 2) - { - GF256Poly rLastLast = rLast; - GF256Poly sLastLast = sLast; - GF256Poly tLastLast = tLast; - rLast = r; - sLast = s; - tLast = t; - - // Divide rLastLast by rLast, with quotient in q and remainder in r - if (rLast.Zero) - { - // Oops, Euclidean algorithm already terminated? - throw new ReedSolomonException("r_{i-1} was zero"); - } - r = rLastLast; - GF256Poly q = field.Zero; - int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); - int dltInverse = field.inverse(denominatorLeadingTerm); - while (r.Degree >= rLast.Degree && !r.Zero) - { - int degreeDiff = r.Degree - rLast.Degree; - int scale = field.multiply(r.getCoefficient(r.Degree), 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); - } - - int sigmaTildeAtZero = t.getCoefficient(0); - if (sigmaTildeAtZero == 0) - { - throw new ReedSolomonException("sigmaTilde(0) was zero"); - } - - int inverse = field.inverse(sigmaTildeAtZero); - GF256Poly sigma = t.multiply(inverse); - GF256Poly omega = r.multiply(inverse); - return new GF256Poly[]{sigma, omega}; + int position = received.Length - 1 - field.log(errorLocations[i]); + if (position < 0) + { + throw new ReedSolomonException("Bad error location"); + } + received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]); } - - private int[] findErrorLocations(GF256Poly errorLocator) + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) throws ReedSolomonException + private GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R) + { + // Assume a's degree is >= b's + if (a.Degree < b.Degree) { - // This is a direct application of Chien's search - int numErrors = errorLocator.Degree; - if (numErrors == 1) - { - // shortcut - return new int[]{errorLocator.getCoefficient(1)}; - } - int[] result = new int[numErrors]; - int e = 0; - for (int i = 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; + GenericGFPoly temp = a; + a = b; + b = temp; } - - private int[] findErrorMagnitudes(GF256Poly errorEvaluator, int[] errorLocations, bool dataMatrix) + + GenericGFPoly rLast = a; + GenericGFPoly r = b; + GenericGFPoly tLast = field.Zero; + GenericGFPoly t = field.One; + + // Run Euclidean algorithm until r's degree is less than R/2 + while (r.Degree >= R / 2) { - // This is directly applying Forney's Formula - int s = errorLocations.Length; - int[] result = new int[s]; - for (int i = 0; i < s; i++) - { - int xiInverse = field.inverse(errorLocations[i]); - int denominator = 1; - for (int j = 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; + GenericGFPoly rLastLast = rLast; + GenericGFPoly tLastLast = tLast; + rLast = r; + tLast = t; + + // Divide rLastLast by rLast, with quotient in q and remainder in r + if (rLast.Zero) + { + // Oops, Euclidean algorithm already terminated? + throw new ReedSolomonException("r_{i-1} was zero"); + } + r = rLastLast; + GenericGFPoly q = field.Zero; + int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); + int dltInverse = field.inverse(denominatorLeadingTerm); + while (r.Degree >= rLast.Degree && !r.Zero) + { + int degreeDiff = r.Degree - rLast.Degree; + int scale = field.multiply(r.getCoefficient(r.Degree), dltInverse); + q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale)); + r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); + } + + t = q.multiply(tLast).addOrSubtract(tLastLast); } + + int sigmaTildeAtZero = t.getCoefficient(0); + if (sigmaTildeAtZero == 0) + { + throw new ReedSolomonException("sigmaTilde(0) was zero"); + } + + int inverse = field.inverse(sigmaTildeAtZero); + GenericGFPoly sigma = t.multiply(inverse); + GenericGFPoly omega = r.multiply(inverse); + return new GenericGFPoly[]{sigma, omega}; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private int[] findErrorLocations(GenericGFPoly errorLocator) throws ReedSolomonException + private int[] findErrorLocations(GenericGFPoly errorLocator) + { + // This is a direct application of Chien's search + int numErrors = errorLocator.Degree; + if (numErrors == 1) // shortcut + { + return new int[] {errorLocator.getCoefficient(1)}; + } + int[] result = new int[numErrors]; + int e = 0; + for (int i = 1; i < field.Size && 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 int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations, bool dataMatrix) + { + // This is directly applying Forney's Formula + int s = errorLocations.Length; + int[] result = new int[s]; + for (int i = 0; i < s; i++) + { + int xiInverse = field.inverse(errorLocations[i]); + int denominator = 1; + for (int j = 0; j < s; j++) + { + if (i != j) + { + //denominator = field.multiply(denominator, + // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); + // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. + // Below is a funny-looking workaround from Steven Parkes + int term = field.multiply(errorLocations[j], xiInverse); + int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; + denominator = field.multiply(denominator, termPlus1); + } + } + 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; + } + } + } \ No newline at end of file diff --git a/csharp/common/reedsolomon/ReedSolomonEncoder.cs b/csharp/common/reedsolomon/ReedSolomonEncoder.cs index 162f80ebc..330e8757b 100755 --- a/csharp/common/reedsolomon/ReedSolomonEncoder.cs +++ b/csharp/common/reedsolomon/ReedSolomonEncoder.cs @@ -1,89 +1,90 @@ -/* -* 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. -*/ using System; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.common.reedsolomon { - - ///

Implements Reed-Solomon enbcoding, as the name implies.

+ + + /// + ///

Implements Reed-Solomon enbcoding, as the name implies.

/// + /// @author Sean Owen + /// @author William Rucklidge ///
- /// Sean Owen - /// - /// William Rucklidge - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class ReedSolomonEncoder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'field '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private GF256 field; - //UPGRADE_NOTE: Final was removed from the declaration of 'cachedGenerators '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList cachedGenerators; - - public ReedSolomonEncoder(GF256 field) + + private readonly GenericGF field; + private readonly IList cachedGenerators; + + public ReedSolomonEncoder(GenericGF field) + { + if (!GenericGF.QR_CODE_FIELD_256.Equals(field)) { - if (!GF256.QR_CODE_FIELD.Equals(field)) - { - throw new System.ArgumentException("Only QR Code is supported at this time"); - } - this.field = field; - this.cachedGenerators = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - cachedGenerators.Add(new GF256Poly(field, new int[]{1})); + throw new System.ArgumentException("Only QR Code is supported at this time"); } - - private GF256Poly buildGenerator(int degree) + this.field = field; + this.cachedGenerators = new List(); + cachedGenerators.Add(new GenericGFPoly(field, new int[]{1})); + } + + private GenericGFPoly buildGenerator(int degree) + { + if (degree >= cachedGenerators.Count) { - if (degree >= cachedGenerators.Count) - { - GF256Poly lastGenerator = (GF256Poly) cachedGenerators[cachedGenerators.Count - 1]; - for (int d = cachedGenerators.Count; d <= degree; d++) - { - GF256Poly nextGenerator = lastGenerator.multiply(new GF256Poly(field, new int[]{1, field.exp(d - 1)})); - cachedGenerators.Add(nextGenerator); - lastGenerator = nextGenerator; - } - } - return (GF256Poly) cachedGenerators[degree]; + GenericGFPoly lastGenerator = cachedGenerators[cachedGenerators.Count - 1]; + for (int d = cachedGenerators.Count; d <= degree; d++) + { + GenericGFPoly nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] {1, field.exp(d - 1)})); + cachedGenerators.Add(nextGenerator); + lastGenerator = nextGenerator; + } } - - public void encode(int[] toEncode, int ecBytes) + return cachedGenerators[degree]; + } + + public void encode(int[] toEncode, int ecBytes) + { + if (ecBytes == 0) { - if (ecBytes == 0) - { - throw new System.ArgumentException("No error correction bytes"); - } - int dataBytes = toEncode.Length - ecBytes; - if (dataBytes <= 0) - { - throw new System.ArgumentException("No data bytes provided"); - } - GF256Poly generator = buildGenerator(ecBytes); - int[] infoCoefficients = new int[dataBytes]; - Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); - GF256Poly info = new GF256Poly(field, infoCoefficients); - info = info.multiplyByMonomial(ecBytes, 1); - GF256Poly remainder = info.divide(generator)[1]; - int[] coefficients = remainder.Coefficients; - int numZeroCoefficients = ecBytes - coefficients.Length; - for (int i = 0; i < numZeroCoefficients; i++) - { - toEncode[dataBytes + i] = 0; - } - Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); + throw new System.ArgumentException("No error correction bytes"); } + int dataBytes = toEncode.Length - ecBytes; + if (dataBytes <= 0) + { + throw new System.ArgumentException("No data bytes provided"); + } + GenericGFPoly generator = buildGenerator(ecBytes); + int[] infoCoefficients = new int[dataBytes]; + Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes); + GenericGFPoly info = new GenericGFPoly(field, infoCoefficients); + info = info.multiplyByMonomial(ecBytes, 1); + GenericGFPoly remainder = info.divide(generator)[1]; + int[] coefficients = remainder.Coefficients; + int numZeroCoefficients = ecBytes - coefficients.Length; + for (int i = 0; i < numZeroCoefficients; i++) + { + toEncode[dataBytes + i] = 0; + } + Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length); + } + } + } \ No newline at end of file diff --git a/csharp/common/reedsolomon/ReedSolomonException.cs b/csharp/common/reedsolomon/ReedSolomonException.cs index 964d0e6f5..a6c1e79f3 100755 --- a/csharp/common/reedsolomon/ReedSolomonException.cs +++ b/csharp/common/reedsolomon/ReedSolomonException.cs @@ -1,36 +1,36 @@ -/* -* 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. -*/ using System; + +/* + * 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. + */ + namespace com.google.zxing.common.reedsolomon { - - ///

Thrown when an exception occurs during Reed-Solomon decoding, such as when + + ///

+ ///

Thrown when an exception occurs during Reed-Solomon decoding, such as when /// there are too many errors to correct.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - [Serializable] - public sealed class ReedSolomonException:System.Exception + public sealed class ReedSolomonException : Exception { - - public ReedSolomonException(System.String message):base(message) - { - } + + public ReedSolomonException(string message) : base(message) + { + } + } } \ No newline at end of file diff --git a/csharp/datamatrix/DataMatrixReader.cs b/csharp/datamatrix/DataMatrixReader.cs index 25f2dbb99..5473c7889 100755 --- a/csharp/datamatrix/DataMatrixReader.cs +++ b/csharp/datamatrix/DataMatrixReader.cs @@ -1,171 +1,184 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using DecodeHintType = com.google.zxing.DecodeHintType; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using Reader = com.google.zxing.Reader; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultMetadataType = com.google.zxing.ResultMetadataType; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; -using DetectorResult = com.google.zxing.common.DetectorResult; -using Decoder = com.google.zxing.datamatrix.decoder.Decoder; -using Detector = com.google.zxing.datamatrix.detector.Detector; + * 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. + */ + namespace com.google.zxing.datamatrix { - - /// This implementation can detect and decode Data Matrix codes in an image. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using Result = com.google.zxing.Result; + using ResultMetadataType = com.google.zxing.ResultMetadataType; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using DetectorResult = com.google.zxing.common.DetectorResult; + using Decoder = com.google.zxing.datamatrix.decoder.Decoder; + using Detector = com.google.zxing.datamatrix.detector.Detector; + + + /// + /// This implementation can detect and decode Data Matrix codes in an image. /// + /// @author bbrown@google.com (Brian Brown) /// - /// bbrown@google.com (Brian Brown) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class DataMatrixReader : Reader + public sealed class DataMatrixReader : com.google.zxing.Reader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'NO_POINTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Decoder decoder = new Decoder(); - - /// Locates and decodes a Data Matrix code in an image. - /// - /// - /// a String representing the content encoded by the Data Matrix code - /// - /// ReaderException if a Data Matrix code cannot be found, or cannot be decoded - public Result decode(BinaryBitmap image) + + private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; + + private readonly Decoder decoder = new Decoder(); + + /// + /// Locates and decodes a Data Matrix code in an image. + /// + /// a String representing the content encoded by the Data Matrix code + /// if a Data Matrix code cannot be found + /// if a Data Matrix code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image) + { + return decode(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image, IDictionary hints) + { + DecoderResult decoderResult; + ResultPoint[] points; + if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) { - return decode(image, null); + BitMatrix bits = extractPureBits(image.BlackMatrix); + decoderResult = decoder.decode(bits); + points = NO_POINTS; } - - public Result decode(BinaryBitmap image, System.Collections.Hashtable hints) + else { - DecoderResult decoderResult; - ResultPoint[] points; - if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) - { - BitMatrix bits = extractPureBits(image.BlackMatrix); - decoderResult = decoder.decode(bits); - points = NO_POINTS; - } - else - { - DetectorResult detectorResult = new Detector(image.BlackMatrix).detect(); - decoderResult = decoder.decode(detectorResult.Bits); - points = detectorResult.Points; - } - Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.DATAMATRIX); - if (decoderResult.ByteSegments != null) - { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.ByteSegments); - } - if (decoderResult.ECLevel != null) - { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel.ToString()); - } - return result; + DetectorResult detectorResult = (new Detector(image.BlackMatrix)).detect(); + decoderResult = decoder.decode(detectorResult.Bits); + points = detectorResult.Points; } - - /// 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 BitMatrix extractPureBits(BitMatrix image) + Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.DATA_MATRIX); + IList byteSegments = decoderResult.ByteSegments; + if (byteSegments != null) { - // Now need to determine module size in pixels - - int height = image.Height; - int width = image.Width; - int minDimension = System.Math.Min(height, width); - - // First, skip white border by tracking diagonally from the top left down and to the right: - int borderWidth = 0; - while (borderWidth < minDimension && !image.get_Renamed(borderWidth, borderWidth)) - { - borderWidth++; - } - if (borderWidth == minDimension) - { - throw ReaderException.Instance; - } - - // And then keep tracking across the top-left black module to determine module size - int moduleEnd = borderWidth + 1; - while (moduleEnd < width && image.get_Renamed(moduleEnd, borderWidth)) - { - moduleEnd++; - } - if (moduleEnd == width) - { - throw ReaderException.Instance; - } - - int moduleSize = moduleEnd - borderWidth; - - // And now find where the bottommost black module on the first column ends - int columnEndOfSymbol = height - 1; - while (columnEndOfSymbol >= 0 && !image.get_Renamed(borderWidth, columnEndOfSymbol)) - { - columnEndOfSymbol--; - } - if (columnEndOfSymbol < 0) - { - throw ReaderException.Instance; - } - columnEndOfSymbol++; - - // Make sure width of barcode is a multiple of module size - if ((columnEndOfSymbol - borderWidth) % moduleSize != 0) - { - throw ReaderException.Instance; - } - int dimension = (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); - - int sampleDimension = borderWidth + (dimension - 1) * moduleSize; - if (sampleDimension >= width || sampleDimension >= height) - { - throw ReaderException.Instance; - } - - // Now just read off the bits - BitMatrix bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - int iOffset = borderWidth + i * moduleSize; - for (int j = 0; j < dimension; j++) - { - if (image.get_Renamed(borderWidth + j * moduleSize, iOffset)) - { - bits.set_Renamed(j, i); - } - } - } - return bits; + result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); } + string ecLevel = decoderResult.ECLevel; + if (ecLevel != null) + { + result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); + } + return result; + } + + public void reset() + { + // do nothing + } + + /// + /// This method detects a code in a "pure" image -- that is, pure monochrome image + /// which contains only an unrotated, unskewed, image of a code, with some white border + /// around it. This is a specialized method that works exceptionally fast in this special + /// case. + /// + /// + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix extractPureBits(com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static BitMatrix extractPureBits(BitMatrix image) + { + + int[] leftTopBlack = image.TopLeftOnBit; + int[] rightBottomBlack = image.BottomRightOnBit; + if (leftTopBlack == null || rightBottomBlack == null) + { + throw NotFoundException.NotFoundInstance; + } + + int moduleSize = getModuleSize(leftTopBlack, image); + + int top = leftTopBlack[1]; + int bottom = rightBottomBlack[1]; + int left = leftTopBlack[0]; + int right = rightBottomBlack[0]; + + int matrixWidth = (right - left + 1) / moduleSize; + int matrixHeight = (bottom - top + 1) / moduleSize; + if (matrixWidth <= 0 || matrixHeight <= 0) + { + throw NotFoundException.NotFoundInstance; + } + + // 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. + int nudge = moduleSize >> 1; + top += nudge; + left += nudge; + + // Now just read off the bits + BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight); + for (int y = 0; y < matrixHeight; y++) + { + int iOffset = top + y * moduleSize; + for (int x = 0; x < matrixWidth; x++) + { + if (image.get(left + x * moduleSize, iOffset)) + { + bits.set(x, y); + } + } + } + return bits; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int moduleSize(int[] leftTopBlack, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static int getModuleSize(int[] leftTopBlack, BitMatrix image) + { + int width = image.Width; + int x = leftTopBlack[0]; + int y = leftTopBlack[1]; + while (x < width && image.get(x, y)) + { + x++; + } + if (x == width) + { + throw NotFoundException.NotFoundInstance; + } + + int moduleSize = x - leftTopBlack[0]; + if (moduleSize == 0) + { + throw NotFoundException.NotFoundInstance; + } + return moduleSize; + } + } } \ No newline at end of file diff --git a/csharp/datamatrix/decoder/BitMatrixParser.cs b/csharp/datamatrix/decoder/BitMatrixParser.cs index b94a682f1..2158e61db 100755 --- a/csharp/datamatrix/decoder/BitMatrixParser.cs +++ b/csharp/datamatrix/decoder/BitMatrixParser.cs @@ -1,547 +1,516 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; + * 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. + */ + namespace com.google.zxing.datamatrix.decoder { - - /// bbrown@google.com (Brian Brown) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class BitMatrixParser + + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + /// + /// @author bbrown@google.com (Brian Brown) + /// + internal sealed class BitMatrixParser { - - //UPGRADE_NOTE: Final was removed from the declaration of 'mappingBitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix mappingBitMatrix; - //UPGRADE_NOTE: Final was removed from the declaration of 'readMappingMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix readMappingMatrix; - //UPGRADE_NOTE: Final was removed from the declaration of 'version '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Version version; - - /// {@link BitMatrix} to parse - /// - /// ReaderException if dimension is < 10 or > 144 or not 0 mod 2 - internal BitMatrixParser(BitMatrix bitMatrix) + + private readonly BitMatrix mappingBitMatrix; + private readonly BitMatrix readMappingMatrix; + private readonly Version version; + + /// to parse + /// if dimension is < 8 or > 144 or not 0 mod 2 +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: BitMatrixParser(com.google.zxing.common.BitMatrix bitMatrix) throws com.google.zxing.FormatException + internal BitMatrixParser(BitMatrix bitMatrix) + { + int dimension = bitMatrix.Height; + if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) { - int dimension = bitMatrix.Dimension; - if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) - { - throw ReaderException.Instance; - } - - version = readVersion(bitMatrix); - this.mappingBitMatrix = extractDataRegion(bitMatrix); - // TODO(bbrown): Make this work for rectangular symbols - this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Dimension); + throw FormatException.FormatInstance; } - - ///

Creates the version object based on the dimension of the original bit matrix from - /// the datamatrix code.

- /// - ///

See ISO 16022:2006 Table 7 - ECC 200 symbol attributes

- /// - ///
- /// Original {@link BitMatrix} including alignment patterns - /// - /// {@link Version} encapsulating the Data Matrix Code's "version" - /// - /// ReaderException if the dimensions of the mapping matrix are not valid - /// Data Matrix dimensions. - /// - internal Version readVersion(BitMatrix bitMatrix) + + version = readVersion(bitMatrix); + this.mappingBitMatrix = extractDataRegion(bitMatrix); + this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Width, this.mappingBitMatrix.Height); + } + + internal Version Version + { + get + { + return version; + } + } + + /// + ///

Creates the version object based on the dimension of the original bit matrix from + /// the datamatrix code.

+ /// + ///

See ISO 16022:2006 Table 7 - ECC 200 symbol attributes

+ ///
+ /// Original including alignment patterns + /// encapsulating the Data Matrix Code's "version" + /// if the dimensions of the mapping matrix are not valid + /// Data Matrix dimensions. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static Version readVersion(com.google.zxing.common.BitMatrix bitMatrix) throws com.google.zxing.FormatException + private static Version readVersion(BitMatrix bitMatrix) + { + int numRows = bitMatrix.Height; + int numColumns = bitMatrix.Width; + return Version.getVersionForDimensions(numRows, numColumns); + } + + /// + ///

Reads the bits in the representing the mapping matrix (No alignment patterns) + /// in the correct order in order to reconstitute the codewords bytes contained within the + /// Data Matrix Code.

+ ///
+ /// bytes encoded within the Data Matrix Code + /// if the exact number of bytes expected is not read +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: byte[] readCodewords() throws com.google.zxing.FormatException + internal sbyte[] readCodewords() + { + + sbyte[] result = new sbyte[version.TotalCodewords]; + int resultOffset = 0; + + int row = 4; + int column = 0; + + int numRows = mappingBitMatrix.Height; + int numColumns = mappingBitMatrix.Width; + + bool corner1Read = false; + bool corner2Read = false; + bool corner3Read = false; + bool corner4Read = false; + + // Read all of the codewords + do { - - if (version != null) + // Check the four corner cases + if ((row == numRows) && (column == 0) && !corner1Read) + { + result[resultOffset++] = (sbyte) readCorner1(numRows, numColumns); + row -= 2; + column += 2; + corner1Read = true; + } + else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) + { + result[resultOffset++] = (sbyte) readCorner2(numRows, numColumns); + row -= 2; + column += 2; + corner2Read = true; + } + else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) + { + result[resultOffset++] = (sbyte) readCorner3(numRows, numColumns); + row -= 2; + column += 2; + corner3Read = true; + } + else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) + { + result[resultOffset++] = (sbyte) readCorner4(numRows, numColumns); + row -= 2; + column += 2; + corner4Read = true; + } + else + { + // Sweep upward diagonally to the right + do { - return version; - } - - // TODO(bbrown): make this work for rectangular dimensions as well. - int numRows = bitMatrix.Dimension; - int numColumns = numRows; - - return Version.getVersionForDimensions(numRows, numColumns); + if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(column, row)) + { + result[resultOffset++] = (sbyte) 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++] = (sbyte) 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.TotalCodewords) + { + throw FormatException.FormatInstance; } - - ///

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.

- /// - ///
- /// bytes encoded within the Data Matrix Code - /// - /// ReaderException if the exact number of bytes expected is not read - internal sbyte[] readCodewords() + return result; + } + + /// + ///

Reads a bit of the mapping matrix accounting for boundary wrapping.

+ ///
+ /// Row to read in the mapping matrix + /// Column to read in the mapping matrix + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// value of the given bit in the mapping matrix + internal bool readModule(int row, int column, int numRows, int numColumns) + { + // Adjust the row and column indices based on boundary wrapping + if (row < 0) { - - sbyte[] result = new sbyte[version.TotalCodewords]; - int resultOffset = 0; - - int row = 4; - int column = 0; - // TODO(bbrown): Data Matrix can be rectangular, assuming square for now - int numRows = mappingBitMatrix.Dimension; - int numColumns = numRows; - - bool corner1Read = false; - bool corner2Read = false; - bool corner3Read = false; - bool corner4Read = false; - - // Read all of the codewords - do + 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); + } + + /// + ///

Reads the 8 bits of the standard Utah-shaped pattern.

+ /// + ///

See ISO 16022:2006, 5.8.1 Figure 6

+ ///
+ /// Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + /// Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the utah shape + internal int readUtah(int row, int column, int numRows, int numColumns) + { + int currentByte = 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; + } + + /// + ///

Reads the 8 bits of the special corner condition 1.

+ /// + ///

See ISO 16022:2006, Figure F.3

+ ///
+ /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 1 + internal int readCorner1(int numRows, int numColumns) + { + int currentByte = 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; + } + + /// + ///

Reads the 8 bits of the special corner condition 2.

+ /// + ///

See ISO 16022:2006, Figure F.4

+ ///
+ /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 2 + internal int readCorner2(int numRows, int numColumns) + { + int currentByte = 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; + } + + /// + ///

Reads the 8 bits of the special corner condition 3.

+ /// + ///

See ISO 16022:2006, Figure F.5

+ ///
+ /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 3 + internal int readCorner3(int numRows, int numColumns) + { + int currentByte = 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; + } + + /// + ///

Reads the 8 bits of the special corner condition 4.

+ /// + ///

See ISO 16022:2006, Figure F.6

+ ///
+ /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 4 + internal int readCorner4(int numRows, int numColumns) + { + int currentByte = 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; + } + + /// + ///

Extracts the data region from a that contains + /// alignment patterns.

+ ///
+ /// Original with alignment patterns + /// BitMatrix that has the alignment patterns removed + internal BitMatrix extractDataRegion(BitMatrix bitMatrix) + { + int symbolSizeRows = version.SymbolSizeRows; + int symbolSizeColumns = version.SymbolSizeColumns; + + if (bitMatrix.Height != symbolSizeRows) + { + throw new System.ArgumentException("Dimension of bitMarix must match the version size"); + } + + int dataRegionSizeRows = version.DataRegionSizeRows; + int dataRegionSizeColumns = version.DataRegionSizeColumns; + + int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; + int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; + + int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; + int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; + + BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow); + for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) + { + int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; + for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) + { + int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; + for (int i = 0; i < dataRegionSizeRows; ++i) { - // Check the four corner cases - if ((row == numRows) && (column == 0) && !corner1Read) + int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; + int writeRowOffset = dataRegionRowOffset + i; + for (int j = 0; j < dataRegionSizeColumns; ++j) + { + int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; + if (bitMatrix.get(readColumnOffset, readRowOffset)) { - result[resultOffset++] = (sbyte) readCorner1(numRows, numColumns); - row -= 2; - column += 2; - corner1Read = true; - } - else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) - { - result[resultOffset++] = (sbyte) readCorner2(numRows, numColumns); - row -= 2; - column += 2; - corner2Read = true; - } - else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) - { - result[resultOffset++] = (sbyte) readCorner3(numRows, numColumns); - row -= 2; - column += 2; - corner3Read = true; - } - else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) - { - result[resultOffset++] = (sbyte) readCorner4(numRows, numColumns); - row -= 2; - column += 2; - corner4Read = true; - } - else - { - // Sweep upward diagonally to the right - do - { - if ((row < numRows) && (column >= 0) && !readMappingMatrix.get_Renamed(column, row)) - { - result[resultOffset++] = (sbyte) 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_Renamed(column, row)) - { - result[resultOffset++] = (sbyte) readUtah(row, column, numRows, numColumns); - } - row += 2; - column -= 2; - } - while ((row < numRows) && (column >= 0)); - row += 3; - column += 1; + int writeColumnOffset = dataRegionColumnOffset + j; + bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset); } + } } - while ((row < numRows) || (column < numColumns)); - - if (resultOffset != version.TotalCodewords) - { - throw ReaderException.Instance; - } - return result; - } - - ///

Reads a bit of the mapping matrix accounting for boundary wrapping.

- /// - ///
- /// Row to read in the mapping matrix - /// - /// Column to read in the mapping matrix - /// - /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// value of the given bit in the mapping matrix - /// - internal bool readModule(int row, int column, int numRows, int numColumns) - { - // 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_Renamed(column, row); - return mappingBitMatrix.get_Renamed(column, row); - } - - ///

Reads the 8 bits of the standard Utah-shaped pattern.

- /// - ///

See ISO 16022:2006, 5.8.1 Figure 6

- /// - ///
- /// Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern - /// - /// Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern - /// - /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// byte from the utah shape - /// - internal int readUtah(int row, int column, int numRows, int numColumns) - { - int currentByte = 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; - } - - ///

Reads the 8 bits of the special corner condition 1.

- /// - ///

See ISO 16022:2006, Figure F.3

- /// - ///
- /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// byte from the Corner condition 1 - /// - internal int readCorner1(int numRows, int numColumns) - { - int currentByte = 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; - } - - ///

Reads the 8 bits of the special corner condition 2.

- /// - ///

See ISO 16022:2006, Figure F.4

- /// - ///
- /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// byte from the Corner condition 2 - /// - internal int readCorner2(int numRows, int numColumns) - { - int currentByte = 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; - } - - ///

Reads the 8 bits of the special corner condition 3.

- /// - ///

See ISO 16022:2006, Figure F.5

- /// - ///
- /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// byte from the Corner condition 3 - /// - internal int readCorner3(int numRows, int numColumns) - { - int currentByte = 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; - } - - ///

Reads the 8 bits of the special corner condition 4.

- /// - ///

See ISO 16022:2006, Figure F.6

- /// - ///
- /// Number of rows in the mapping matrix - /// - /// Number of columns in the mapping matrix - /// - /// byte from the Corner condition 4 - /// - internal int readCorner4(int numRows, int numColumns) - { - int currentByte = 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; - } - - ///

Extracts the data region from a {@link BitMatrix} that contains - /// alignment patterns.

- /// - ///
- /// Original {@link BitMatrix} with alignment patterns - /// - /// BitMatrix that has the alignment patterns removed - /// - internal BitMatrix extractDataRegion(BitMatrix bitMatrix) - { - int symbolSizeRows = version.SymbolSizeRows; - int symbolSizeColumns = version.SymbolSizeColumns; - - // TODO(bbrown): Make this work with rectangular codes - if (bitMatrix.Dimension != symbolSizeRows) - { - throw new System.ArgumentException("Dimension of bitMarix must match the version size"); - } - - int dataRegionSizeRows = version.DataRegionSizeRows; - int dataRegionSizeColumns = version.DataRegionSizeColumns; - - int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; - int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; - - int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; - //int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; - - // TODO(bbrown): Make this work with rectangular codes - BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow); - for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) - { - int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; - for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) - { - int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; - for (int i = 0; i < dataRegionSizeRows; ++i) - { - int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; - int writeRowOffset = dataRegionRowOffset + i; - for (int j = 0; j < dataRegionSizeColumns; ++j) - { - int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; - if (bitMatrix.get_Renamed(readColumnOffset, readRowOffset)) - { - int writeColumnOffset = dataRegionColumnOffset + j; - bitMatrixWithoutAlignment.set_Renamed(writeColumnOffset, writeRowOffset); - } - } - } - } - } - return bitMatrixWithoutAlignment; + } } + return bitMatrixWithoutAlignment; + } + } } \ No newline at end of file diff --git a/csharp/datamatrix/decoder/DataBlock.cs b/csharp/datamatrix/decoder/DataBlock.cs index 28d48a19d..9a0305c8d 100755 --- a/csharp/datamatrix/decoder/DataBlock.cs +++ b/csharp/datamatrix/decoder/DataBlock.cs @@ -1,144 +1,138 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.datamatrix.decoder { - - ///

Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into + + ///

+ ///

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.

/// + /// @author bbrown@google.com (Brian Brown) ///
- /// bbrown@google.com (Brian Brown) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class DataBlock + internal sealed class DataBlock { - internal int NumDataCodewords + + private readonly int numDataCodewords; + private readonly sbyte[] codewords; + + private DataBlock(int numDataCodewords, sbyte[] codewords) + { + this.numDataCodewords = numDataCodewords; + this.codewords = codewords; + } + + /// + ///

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.

+ ///
+ /// bytes as read directly from the Data Matrix Code + /// version of the Data Matrix Code + /// DataBlocks containing original bytes, "de-interleaved" from representation in the + /// Data Matrix Code + internal static DataBlock[] getDataBlocks(sbyte[] rawCodewords, Version version) + { + // Figure out the number and size of data blocks used by this version + Version.ECBlocks ecBlocks = version.ECBlocks2; + + // First count the total number of data blocks + int totalBlocks = 0; + Version.ECB[] ecBlockArray = ecBlocks.GetECB; + foreach (Version.ECB ecBlock in ecBlockArray) { - get - { - return numDataCodewords; - } - + totalBlocks += ecBlock.Count; } - internal sbyte[] Codewords + + // Now establish DataBlocks of the appropriate size and number of data codewords + DataBlock[] result = new DataBlock[totalBlocks]; + int numResultBlocks = 0; + foreach (Version.ECB ecBlock in ecBlockArray) { - get - { - return codewords; - } - + for (int i = 0; i < ecBlock.Count; i++) + { + int numDataCodewords = ecBlock.DataCodewords; + int numBlockCodewords = ecBlocks.ECCodewords + numDataCodewords; + result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[numBlockCodewords]); + } } - - //UPGRADE_NOTE: Final was removed from the declaration of 'numDataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int numDataCodewords; - //UPGRADE_NOTE: Final was removed from the declaration of 'codewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte[] codewords; - - private DataBlock(int numDataCodewords, sbyte[] codewords) + + // 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 + int longerBlocksTotalCodewords = result[0].codewords.Length; + //int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1; + + int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.ECCodewords; + int shorterBlocksNumDataCodewords = 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 + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { - this.numDataCodewords = numDataCodewords; - this.codewords = codewords; + for (int j = 0; j < numResultBlocks; j++) + { + result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; + } } - - ///

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.

- /// - ///
- /// bytes as read directly from the Data Matrix Code - /// - /// version of the Data Matrix Code - /// - /// {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the - /// Data Matrix Code - /// - internal static DataBlock[] getDataBlocks(sbyte[] rawCodewords, Version version) + + // Fill out the last data block in the longer ones + bool specialVersion = version.VersionNumber == 24; + int numLongerBlocks = specialVersion ? 8 : numResultBlocks; + for (int j = 0; j < numLongerBlocks; j++) { - // Figure out the number and size of data blocks used by this version - Version.ECBlocks ecBlocks = version.getECBlocks(); - - // First count the total number of data blocks - int totalBlocks = 0; - Version.ECB[] ecBlockArray = ecBlocks.getECBlocks(); - for (int i = 0; i < ecBlockArray.Length; i++) - { - totalBlocks += ecBlockArray[i].Count; - } - - // Now establish DataBlocks of the appropriate size and number of data codewords - DataBlock[] result = new DataBlock[totalBlocks]; - int numResultBlocks = 0; - for (int j = 0; j < ecBlockArray.Length; j++) - { - Version.ECB ecBlock = ecBlockArray[j]; - for (int i = 0; i < ecBlock.Count; i++) - { - int numDataCodewords = ecBlock.DataCodewords; - int numBlockCodewords = ecBlocks.ECCodewords + numDataCodewords; - result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[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 - int longerBlocksTotalCodewords = result[0].codewords.Length; - //int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1; - - int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.ECCodewords; - int shorterBlocksNumDataCodewords = 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 - int rawCodewordsOffset = 0; - for (int i = 0; i < shorterBlocksNumDataCodewords; i++) - { - for (int j = 0; j < numResultBlocks; j++) - { - result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; - } - } - - // Fill out the last data block in the longer ones - bool specialVersion = version.VersionNumber == 24; - int numLongerBlocks = specialVersion?8:numResultBlocks; - for (int j = 0; j < numLongerBlocks; j++) - { - result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++]; - } - - // Now add in error correction blocks - int max = result[0].codewords.Length; - for (int i = longerBlocksNumDataCodewords; i < max; i++) - { - for (int j = 0; j < numResultBlocks; j++) - { - int iOffset = (specialVersion && j > 7)?i - 1:i; - result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; - } - } - - if (rawCodewordsOffset != rawCodewords.Length) - { - throw new System.ArgumentException(); - } - - return result; + result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++]; } + + // Now add in error correction blocks + int max = result[0].codewords.Length; + for (int i = longerBlocksNumDataCodewords; i < max; i++) + { + for (int j = 0; j < numResultBlocks; j++) + { + int iOffset = specialVersion && j > 7 ? i - 1 : i; + result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; + } + } + + if (rawCodewordsOffset != rawCodewords.Length) + { + throw new System.ArgumentException(); + } + + return result; + } + + internal int NumDataCodewords + { + get + { + return numDataCodewords; + } + } + + internal sbyte[] Codewords + { + get + { + return codewords; + } + } + } + } \ No newline at end of file diff --git a/csharp/datamatrix/decoder/DecodedBitStreamParser.cs b/csharp/datamatrix/decoder/DecodedBitStreamParser.cs index 12e3faa72..b7d958498 100755 --- a/csharp/datamatrix/decoder/DecodedBitStreamParser.cs +++ b/csharp/datamatrix/decoder/DecodedBitStreamParser.cs @@ -1,625 +1,644 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using BitSource = com.google.zxing.common.BitSource; -using DecoderResult = com.google.zxing.common.DecoderResult; +using System.Collections.Generic; +using System.Text; +using com.google.zxing.common; + +/* + * 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. + */ + namespace com.google.zxing.datamatrix.decoder { - - ///

Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes + + using FormatException = com.google.zxing.FormatException; + using BitSource = com.google.zxing.common.BitSource; + using DecoderResult = com.google.zxing.common.DecoderResult; + + + ///

+ ///

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.

/// ///

See ISO 16022:2006, 5.2.1 - 5.2.9.2

/// + /// @author bbrown@google.com (Brian Brown) + /// @author Sean Owen ///
- /// bbrown@google.com (Brian Brown) - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class DecodedBitStreamParser + internal sealed class DecodedBitStreamParser { - - /// See ISO 16022:2006, Annex C Table C.1 - /// The C40 Basic Character Set (*'s used for placeholders for the shift values) - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'C40_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] C40_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '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'}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'C40_SHIFT2_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] C40_SHIFT2_SET_CHARS = new char[]{'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'}; - - /// See ISO 16022:2006, Annex C Table C.2 - /// The Text Basic Character Set (*'s used for placeholders for the shift values) - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'TEXT_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] TEXT_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '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 char[] TEXT_SHIFT3_SET_CHARS = new char[]{'\'', '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', '{', '|', '}', '~', (char) 127}; - - private const int PAD_ENCODE = 0; // Not really an encoding - private const int ASCII_ENCODE = 1; - private const int C40_ENCODE = 2; - private const int TEXT_ENCODE = 3; - private const int ANSIX12_ENCODE = 4; - private const int EDIFACT_ENCODE = 5; - private const int BASE256_ENCODE = 6; - - private DecodedBitStreamParser() + + private enum Mode + { + PAD_ENCODE, // Not really a mode + ASCII_ENCODE, + C40_ENCODE, + TEXT_ENCODE, + ANSIX12_ENCODE, + EDIFACT_ENCODE, + BASE256_ENCODE + } + + /// + /// See ISO 16022:2006, Annex C Table C.1 + /// The C40 Basic Character Set (*'s used for placeholders for the shift values) + /// + private static readonly char[] C40_BASIC_SET_CHARS = {'*', '*', '*', ' ', '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 readonly char[] C40_SHIFT2_SET_CHARS = {'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'}; + + /// + /// See ISO 16022:2006, Annex C Table C.2 + /// The Text Basic Character Set (*'s used for placeholders for the shift values) + /// + private static readonly char[] TEXT_BASIC_SET_CHARS = {'*', '*', '*', ' ', '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 readonly char[] TEXT_SHIFT3_SET_CHARS = {'\'', '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', '{', '|', '}', '~', (char) 127}; + + private DecodedBitStreamParser() + { + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static com.google.zxing.common.DecoderResult decode(byte[] bytes) throws com.google.zxing.FormatException + internal static DecoderResult decode(sbyte[] bytes) + { + BitSource bits = new BitSource(bytes); + StringBuilder result = new StringBuilder(100); + StringBuilder resultTrailer = new StringBuilder(0); + IList byteSegments = new List(1); + Mode mode = Mode.ASCII_ENCODE; + do { - } - - internal static DecoderResult decode(sbyte[] bytes) - { - BitSource bits = new BitSource(bytes); - System.Text.StringBuilder result = new System.Text.StringBuilder(100); - System.Text.StringBuilder resultTrailer = new System.Text.StringBuilder(0); - System.Collections.ArrayList byteSegments = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(1)); - int mode = ASCII_ENCODE; - do + if (mode == Mode.ASCII_ENCODE) + { + mode = decodeAsciiSegment(bits, result, resultTrailer); + } + else + { + switch (mode) { - if (mode == ASCII_ENCODE) + case com.google.zxing.datamatrix.decoder.DecodedBitStreamParser.Mode.C40_ENCODE: + decodeC40Segment(bits, result); + break; + case com.google.zxing.datamatrix.decoder.DecodedBitStreamParser.Mode.TEXT_ENCODE: + decodeTextSegment(bits, result); + break; + case com.google.zxing.datamatrix.decoder.DecodedBitStreamParser.Mode.ANSIX12_ENCODE: + decodeAnsiX12Segment(bits, result); + break; + case com.google.zxing.datamatrix.decoder.DecodedBitStreamParser.Mode.EDIFACT_ENCODE: + decodeEdifactSegment(bits, result); + break; + case com.google.zxing.datamatrix.decoder.DecodedBitStreamParser.Mode.BASE256_ENCODE: + decodeBase256Segment(bits, result, byteSegments); + break; + default: + throw FormatException.FormatInstance; + } + mode = Mode.ASCII_ENCODE; + } + } while (mode != Mode.PAD_ENCODE && bits.available() > 0); + if (resultTrailer.Length > 0) + { + result.Append(resultTrailer.ToString()); + } + 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 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static Mode decodeAsciiSegment(com.google.zxing.common.BitSource bits, StringBuilder result, StringBuilder resultTrailer) throws com.google.zxing.FormatException + private static Mode decodeAsciiSegment(BitSource bits, StringBuilder result, StringBuilder resultTrailer) + { + bool upperShift = false; + do + { + int oneByte = bits.readBits(8); + if (oneByte == 0) + { + throw FormatException.FormatInstance; + } // ASCII data (ASCII value + 1) + else if (oneByte <= 128) + { + if (upperShift) + { + oneByte += 128; + //upperShift = false; + } + result.Append((char)(oneByte - 1)); + return Mode.ASCII_ENCODE; + } // Pad + else if (oneByte == 129) + { + return Mode.PAD_ENCODE; + } // 2-digit data 00-99 (Numeric Value + 130) + else if (oneByte <= 229) + { + int value = oneByte - 130; + if (value < 10) // padd with '0' for single digit values + { + result.Append('0'); + } + result.Append(value); + } // Latch to C40 encodation + else if (oneByte == 230) + { + return Mode.C40_ENCODE; + } // Latch to Base 256 encodation + else if (oneByte == 231) + { + return Mode.BASE256_ENCODE; + } + else if (oneByte == 232) + { + // FNC1 + result.Append((char) 29); // translate as ASCII 29 + } + else if (oneByte == 233 || oneByte == 234) + { + // Structured Append, Reader Programming + // Ignore these symbols for now + //throw ReaderException.getInstance(); + } // Upper Shift (shift to Extended ASCII) + else if (oneByte == 235) + { + upperShift = true; + } // 05 Macro + else if (oneByte == 236) + { + result.Append("[)>\u001E05\u001D"); + resultTrailer.Insert(0, "\u001E\u0004"); + } // 06 Macro + else if (oneByte == 237) + { + result.Append("[)>\u001E06\u001D"); + resultTrailer.Insert(0, "\u001E\u0004"); + } // Latch to ANSI X12 encodation + else if (oneByte == 238) + { + return Mode.ANSIX12_ENCODE; + } // Latch to Text encodation + else if (oneByte == 239) + { + return Mode.TEXT_ENCODE; + } // Latch to EDIFACT encodation + else if (oneByte == 240) + { + return Mode.EDIFACT_ENCODE; + } // ECI Character + else if (oneByte == 241) + { + // TODO(bbrown): I think we need to support ECI + //throw ReaderException.getInstance(); + // Ignore this symbol for now + } // Not to be used in ASCII encodation + else if (oneByte >= 242) + { + // ... but work around encoders that end with 254, latch back to ASCII + if (oneByte != 254 || bits.available() != 0) + { + throw FormatException.FormatInstance; + } + } + } while (bits.available() > 0); + return Mode.ASCII_ENCODE; + } + + /// + /// See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeC40Segment(com.google.zxing.common.BitSource bits, StringBuilder result) throws com.google.zxing.FormatException + private static void decodeC40Segment(BitSource bits, StringBuilder result) + { + // 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 + bool upperShift = false; + + int[] cValues = new int[3]; + int shift = 0; + + do + { + // If there is only one byte left then it will be encoded as ASCII + if (bits.available() == 8) + { + return; + } + int firstByte = bits.readBits(8); + if (firstByte == 254) // Unlatch codeword + { + return; + } + + parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for (int i = 0; i < 3; i++) + { + int cValue = cValues[i]; + switch (shift) + { + case 0: + if (cValue < 3) { - mode = decodeAsciiSegment(bits, result, resultTrailer); + shift = cValue + 1; + } + else if (cValue < C40_BASIC_SET_CHARS.Length) + { + char c40char = C40_BASIC_SET_CHARS[cValue]; + if (upperShift) + { + result.Append((char)(c40char + 128)); + upperShift = false; + } + else + { + result.Append(c40char); + } } 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 ReaderException.Instance; - - } - mode = ASCII_ENCODE; + throw FormatException.FormatInstance; } - } - while (mode != PAD_ENCODE && bits.available() > 0); - if (resultTrailer.Length > 0) - { - result.Append(resultTrailer.ToString()); - } - 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 int decodeAsciiSegment(BitSource bits, System.Text.StringBuilder result, System.Text.StringBuilder resultTrailer) - { - bool upperShift = false; - do - { - int oneByte = bits.readBits(8); - if (oneByte == 0) + break; + case 1: + if (upperShift) { - throw ReaderException.Instance; + result.Append((char)(cValue + 128)); + upperShift = false; } - else if (oneByte <= 128) + else { - // ASCII data (ASCII value + 1) - oneByte = upperShift?(oneByte + 128):oneByte; + result.Append((char) cValue); + } + shift = 0; + break; + case 2: + if (cValue < C40_SHIFT2_SET_CHARS.Length) + { + char c40char = C40_SHIFT2_SET_CHARS[cValue]; + if (upperShift) + { + result.Append((char)(c40char + 128)); upperShift = false; - result.Append((char) (oneByte - 1)); - return ASCII_ENCODE; - } - else if (oneByte == 129) + } + else + { + result.Append(c40char); + } + } // FNC1 + else if (cValue == 27) { - // Pad - return PAD_ENCODE; - } - else if (oneByte <= 229) + result.Append((char) 29); // translate as ASCII 29 + } // Upper Shift + else if (cValue == 30) { - // 2-digit data 00-99 (Numeric Value + 130) - int value_Renamed = oneByte - 130; - if (value_Renamed < 10) - { - // padd with '0' for single digit values - result.Append('0'); - } - result.Append(value_Renamed); + upperShift = true; } - else if (oneByte == 230) + else { - // Latch to C40 encodation - return C40_ENCODE; + throw FormatException.FormatInstance; } - else if (oneByte == 231) + shift = 0; + break; + case 3: + if (upperShift) { - // Latch to Base 256 encodation - return BASE256_ENCODE; + result.Append((char)(cValue + 224)); + upperShift = false; } - else if (oneByte == 232) + else { - // FNC1 - //throw ReaderException.getInstance(); - // Ignore this symbol for now - } - else if (oneByte == 233) - { - // Structured Append - //throw ReaderException.getInstance(); - // Ignore this symbol for now - } - else if (oneByte == 234) - { - // Reader Programming - //throw ReaderException.getInstance(); - // Ignore this symbol for now - } - 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 ReaderException.getInstance(); - // Ignore this symbol for now - } - else if (oneByte >= 242) - { - // Not to be used in ASCII encodation - throw ReaderException.Instance; + result.Append((char)(cValue + 96)); } + shift = 0; + break; + default: + throw FormatException.FormatInstance; } - while (bits.available() > 0); - return ASCII_ENCODE; - } - - /// See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 - private static void decodeC40Segment(BitSource bits, System.Text.StringBuilder result) + } + } while (bits.available() > 0); + } + + /// + /// See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeTextSegment(com.google.zxing.common.BitSource bits, StringBuilder result) throws com.google.zxing.FormatException + private static void decodeTextSegment(BitSource bits, StringBuilder result) + { + // 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 + bool upperShift = false; + + int[] cValues = new int[3]; + int shift = 0; + do { - // 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 - bool upperShift = false; - - int[] cValues = new int[3]; - do + // If there is only one byte left then it will be encoded as ASCII + if (bits.available() == 8) + { + return; + } + int firstByte = bits.readBits(8); + if (firstByte == 254) // Unlatch codeword + { + return; + } + + parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for (int i = 0; i < 3; i++) + { + int cValue = cValues[i]; + switch (shift) { - // If there is only one byte left then it will be encoded as ASCII - if (bits.available() == 8) + case 0: + if (cValue < 3) { - return ; + shift = cValue + 1; } - int firstByte = bits.readBits(8); - if (firstByte == 254) + else if (cValue < TEXT_BASIC_SET_CHARS.Length) { - // Unlatch codeword - return ; + char textChar = TEXT_BASIC_SET_CHARS[cValue]; + if (upperShift) + { + result.Append((char)(textChar + 128)); + upperShift = false; + } + else + { + result.Append(textChar); + } } - - parseTwoBytes(firstByte, bits.readBits(8), cValues); - - int shift = 0; - for (int i = 0; i < 3; i++) + else { - int cValue = cValues[i]; - switch (shift) - { - - case 0: - if (cValue < 3) - { - shift = cValue + 1; - } - else - { - if (upperShift) - { - result.Append((char) (C40_BASIC_SET_CHARS[cValue] + 128)); - upperShift = false; - } - else - { - result.Append(C40_BASIC_SET_CHARS[cValue]); - } - } - break; - - case 1: - if (upperShift) - { - result.Append((char) (cValue + 128)); - upperShift = false; - } - else - { - result.Append(cValue); - } - shift = 0; - break; - - case 2: - if (cValue < 27) - { - if (upperShift) - { - result.Append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128)); - upperShift = false; - } - else - { - result.Append(C40_SHIFT2_SET_CHARS[cValue]); - } - } - else if (cValue == 27) - { - // FNC1 - throw ReaderException.Instance; - } - else if (cValue == 30) - { - // Upper Shift - upperShift = true; - } - else - { - throw ReaderException.Instance; - } - shift = 0; - break; - - case 3: - if (upperShift) - { - result.Append((char) (cValue + 224)); - upperShift = false; - } - else - { - result.Append((char) (cValue + 96)); - } - shift = 0; - break; - - default: - throw ReaderException.Instance; - - } + throw FormatException.FormatInstance; } + break; + case 1: + if (upperShift) + { + result.Append((char)(cValue + 128)); + upperShift = false; + } + else + { + result.Append((char) cValue); + } + shift = 0; + break; + case 2: + // Shift 2 for Text is the same encoding as C40 + if (cValue < C40_SHIFT2_SET_CHARS.Length) + { + char c40char = C40_SHIFT2_SET_CHARS[cValue]; + if (upperShift) + { + result.Append((char)(c40char + 128)); + upperShift = false; + } + else + { + result.Append(c40char); + } + } // FNC1 + else if (cValue == 27) + { + result.Append((char) 29); // translate as ASCII 29 + } // Upper Shift + else if (cValue == 30) + { + upperShift = true; + } + else + { + throw FormatException.FormatInstance; + } + shift = 0; + break; + case 3: + if (cValue < TEXT_SHIFT3_SET_CHARS.Length) + { + char textChar = TEXT_SHIFT3_SET_CHARS[cValue]; + if (upperShift) + { + result.Append((char)(textChar + 128)); + upperShift = false; + } + else + { + result.Append(textChar); + } + shift = 0; + } + else + { + throw FormatException.FormatInstance; + } + break; + default: + throw FormatException.FormatInstance; } - while (bits.available() > 0); - } - - /// See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 - private static void decodeTextSegment(BitSource bits, System.Text.StringBuilder result) + } + } while (bits.available() > 0); + } + + /// + /// See ISO 16022:2006, 5.2.7 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeAnsiX12Segment(com.google.zxing.common.BitSource bits, StringBuilder result) throws com.google.zxing.FormatException + private static void decodeAnsiX12Segment(BitSource bits, StringBuilder result) + { + // Three ANSI X12 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + + int[] cValues = new int[3]; + do { - // 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 - bool upperShift = false; - - int[] cValues = new int[3]; - do + // If there is only one byte left then it will be encoded as ASCII + if (bits.available() == 8) + { + return; + } + int firstByte = bits.readBits(8); + if (firstByte == 254) // Unlatch codeword + { + return; + } + + parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for (int i = 0; i < 3; i++) + { + int cValue = cValues[i]; + if (cValue == 0) // X12 segment terminator { - // If there is only one byte left then it will be encoded as ASCII - if (bits.available() == 8) - { - return ; - } - int firstByte = bits.readBits(8); - if (firstByte == 254) - { - // Unlatch codeword - return ; - } - - parseTwoBytes(firstByte, bits.readBits(8), cValues); - - int shift = 0; - for (int i = 0; i < 3; i++) - { - int cValue = cValues[i]; - switch (shift) - { - - case 0: - if (cValue < 3) - { - shift = cValue + 1; - } - else - { - if (upperShift) - { - result.Append((char) (TEXT_BASIC_SET_CHARS[cValue] + 128)); - upperShift = false; - } - else - { - result.Append(TEXT_BASIC_SET_CHARS[cValue]); - } - } - break; - - case 1: - if (upperShift) - { - result.Append((char) (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((char) (C40_SHIFT2_SET_CHARS[cValue] + 128)); - upperShift = false; - } - else - { - result.Append(C40_SHIFT2_SET_CHARS[cValue]); - } - } - else if (cValue == 27) - { - // FNC1 - throw ReaderException.Instance; - } - else if (cValue == 30) - { - // Upper Shift - upperShift = true; - } - else - { - throw ReaderException.Instance; - } - shift = 0; - break; - - case 3: - if (upperShift) - { - result.Append((char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128)); - upperShift = false; - } - else - { - result.Append(TEXT_SHIFT3_SET_CHARS[cValue]); - } - shift = 0; - break; - - default: - throw ReaderException.Instance; - - } - } - } - while (bits.available() > 0); - } - - /// See ISO 16022:2006, 5.2.7 - private static void decodeAnsiX12Segment(BitSource bits, System.Text.StringBuilder result) - { - // Three ANSI X12 values are encoded in a 16-bit value as - // (1600 * C1) + (40 * C2) + C3 + 1 - - int[] cValues = new int[3]; - do + result.Append('\r'); + } // X12 segment separator * + else if (cValue == 1) { - // If there is only one byte left then it will be encoded as ASCII - if (bits.available() == 8) - { - return ; - } - int firstByte = bits.readBits(8); - if (firstByte == 254) - { - // Unlatch codeword - return ; - } - - parseTwoBytes(firstByte, bits.readBits(8), cValues); - - for (int i = 0; i < 3; i++) - { - int cValue = cValues[i]; - if (cValue == 0) - { - // X12 segment terminator - 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((char) (cValue + 44)); - } - else if (cValue < 40) - { - // A - Z - result.Append((char) (cValue + 51)); - } - else - { - throw ReaderException.Instance; - } - } - } - while (bits.available() > 0); - } - - private static void parseTwoBytes(int firstByte, int secondByte, int[] result) - { - int fullBitValue = (firstByte << 8) + secondByte - 1; - int temp = 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 void decodeEdifactSegment(BitSource bits, System.Text.StringBuilder result) - { - bool unlatch = false; - do + result.Append('*'); + } // X12 sub-element separator > + else if (cValue == 2) { - // If there is only two or less bytes left then it will be encoded as ASCII - if (bits.available() <= 16) - { - return ; - } - - for (int i = 0; i < 4; i++) - { - int edifactValue = 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 void decodeBase256Segment(BitSource bits, System.Text.StringBuilder result, System.Collections.ArrayList byteSegments) - { - // Figure out how long the Base 256 Segment is. - int d1 = bits.readBits(8); - int count; - if (d1 == 0) + result.Append('>'); + } // space + else if (cValue == 3) { - // Read the remainder of the symbol - count = bits.available() / 8; - } - else if (d1 < 250) + result.Append(' '); + } // 0 - 9 + else if (cValue < 14) { - count = d1; + result.Append((char)(cValue + 44)); + } // A - Z + else if (cValue < 40) + { + result.Append((char)(cValue + 51)); } else { - count = 250 * (d1 - 249) + bits.readBits(8); + throw FormatException.FormatInstance; } - sbyte[] bytes = new sbyte[count]; - for (int i = 0; i < count; i++) - { - bytes[i] = unrandomize255State(bits.readBits(8), i); - } - byteSegments.Add(SupportClass.ToByteArray(bytes)); - try - { - //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'" - result.Append(System.Text.Encoding.GetEncoding("ISO8859_1").GetString(SupportClass.ToByteArray(bytes))); - } - catch (System.IO.IOException uee) - { - //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" - throw new System.SystemException("Platform does not support required encoding: " + uee); - } - } - - /// See ISO 16022:2006, Annex B, B.2 - private static sbyte unrandomize255State(int randomizedBase256Codeword, int base256CodewordPosition) + } + } while (bits.available() > 0); + } + + private static void parseTwoBytes(int firstByte, int secondByte, int[] result) + { + int fullBitValue = (firstByte << 8) + secondByte - 1; + int temp = 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 void decodeEdifactSegment(BitSource bits, StringBuilder result) + { + do { - int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; - int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; - return (sbyte) (tempVariable >= 0?tempVariable:(tempVariable + 256)); + // If there is only two or less bytes left then it will be encoded as ASCII + if (bits.available() <= 16) + { + return; + } + + for (int i = 0; i < 4; i++) + { + int edifactValue = bits.readBits(6); + + // Check for the unlatch character + if (edifactValue == 0x1F) // 011111 + { + // Read rest of byte, which should be 0, and stop + int bitsLeft = 8 - bits.BitOffset; + if (bitsLeft != 8) + { + bits.readBits(bitsLeft); + } + return; + } + + if ((edifactValue & 0x20) == 0) // no 1 in the leading (6th) bit + { + edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value + } + result.Append((char) edifactValue); + } + } while (bits.available() > 0); + } + + /// + /// See ISO 16022:2006, 5.2.9 and Annex B, B.2 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeBase256Segment(com.google.zxing.common.BitSource bits, StringBuilder result, java.util.Collection byteSegments) throws com.google.zxing.FormatException + private static void decodeBase256Segment(BitSource bits, StringBuilder result, ICollection byteSegments) + { + // Figure out how long the Base 256 Segment is. + int codewordPosition = 1 + bits.ByteOffset; // position is 1-indexed + int d1 = unrandomize255State(bits.readBits(8), codewordPosition++); + int count; + if (d1 == 0) // Read the remainder of the symbol + { + count = bits.available() / 8; } + else if (d1 < 250) + { + count = d1; + } + else + { + count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++); + } + + // We're seeing NegativeArraySizeException errors from users. + if (count < 0) + { + throw FormatException.FormatInstance; + } + + sbyte[] bytes = new sbyte[count]; + for (int i = 0; i < count; i++) + { + // Have seen this particular error in the wild, such as at + // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 + if (bits.available() < 8) + { + throw FormatException.FormatInstance; + } + bytes[i] = (sbyte) unrandomize255State(bits.readBits(8), codewordPosition++); + } + byteSegments.Add(bytes); + try + { + //result.Append(new string(bytes, "ISO8859_1")); + result.Append(GetEncodedStringFromBuffer(bytes, "ISO-8859-1")); + } + catch (System.IO.IOException uee) + { + throw new InvalidOperationException("Platform does not support required encoding: " + uee); + } + } + private static string GetEncodedStringFromBuffer(sbyte[] buffer, string encoding) + { + byte[] bytes = buffer.ToBytes(); + Encoding en = Encoding.GetEncoding(encoding); + return en.GetString(bytes); + } + + /// + /// See ISO 16022:2006, Annex B, B.2 + /// + private static int unrandomize255State(int randomizedBase256Codeword, int base256CodewordPosition) + { + int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; + int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; + return tempVariable >= 0 ? tempVariable : tempVariable + 256; + } + } + } \ No newline at end of file diff --git a/csharp/datamatrix/decoder/Decoder.cs b/csharp/datamatrix/decoder/Decoder.cs index c53a27703..a3ed3243d 100755 --- a/csharp/datamatrix/decoder/Decoder.cs +++ b/csharp/datamatrix/decoder/Decoder.cs @@ -1,153 +1,158 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; -using GF256 = com.google.zxing.common.reedsolomon.GF256; -using ReedSolomonDecoder = com.google.zxing.common.reedsolomon.ReedSolomonDecoder; -using ReedSolomonException = com.google.zxing.common.reedsolomon.ReedSolomonException; + * 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. + */ + namespace com.google.zxing.datamatrix.decoder { - - ///

The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting + + using ChecksumException = com.google.zxing.ChecksumException; + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using GenericGF = com.google.zxing.common.reedsolomon.GenericGF; + using ReedSolomonDecoder = com.google.zxing.common.reedsolomon.ReedSolomonDecoder; + using ReedSolomonException = com.google.zxing.common.reedsolomon.ReedSolomonException; + + ///

+ ///

The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting /// the Data Matrix Code from an image.

/// + /// @author bbrown@google.com (Brian Brown) ///
- /// bbrown@google.com (Brian Brown) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Decoder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'rsDecoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ReedSolomonDecoder rsDecoder; - - public Decoder() + + private readonly ReedSolomonDecoder rsDecoder; + + public Decoder() + { + rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256); + } + + /// + ///

Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans. + /// "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black Data Matrix Code modules + /// text and bytes encoded within the Data Matrix Code + /// if the Data Matrix Code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(boolean[][] image) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + public DecoderResult decode(bool[][] image) + { + int dimension = image.Length; + BitMatrix bits = new BitMatrix(dimension); + for (int i = 0; i < dimension; i++) { - rsDecoder = new ReedSolomonDecoder(GF256.DATA_MATRIX_FIELD); + for (int j = 0; j < dimension; j++) + { + if (image[i][j]) + { + bits.set(j, i); + } + } } - - ///

Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans. - /// "true" is taken to mean a black module.

- /// - ///
- /// booleans representing white/black Data Matrix Code modules - /// - /// text and bytes encoded within the Data Matrix Code - /// - /// ReaderException if the Data Matrix Code cannot be decoded - public DecoderResult decode(bool[][] image) + return decode(bits); + } + + /// + ///

Decodes a Data Matrix Code represented as a . A 1 or "true" is taken + /// to mean a black module.

+ ///
+ /// booleans representing white/black Data Matrix Code modules + /// text and bytes encoded within the Data Matrix Code + /// if the Data Matrix Code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(com.google.zxing.common.BitMatrix bits) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + public DecoderResult decode(BitMatrix bits) + { + + // Construct a parser and read version, error-correction level + BitMatrixParser parser = new BitMatrixParser(bits); + Version version = parser.Version; + + // Read codewords + sbyte[] codewords = parser.readCodewords(); + // Separate into data blocks + DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version); + + int dataBlocksCount = dataBlocks.Length; + + // Count total number of data bytes + int totalBytes = 0; + foreach (DataBlock db in dataBlocks) { - int dimension = image.Length; - BitMatrix bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - for (int j = 0; j < dimension; j++) - { - if (image[i][j]) - { - bits.set_Renamed(j, i); - } - } - } - return decode(bits); + totalBytes += db.NumDataCodewords; } - - ///

Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken - /// to mean a black module.

- /// - ///
- /// booleans representing white/black Data Matrix Code modules - /// - /// text and bytes encoded within the Data Matrix Code - /// - /// ReaderException if the Data Matrix Code cannot be decoded - public DecoderResult decode(BitMatrix bits) + sbyte[] resultBytes = new sbyte[totalBytes]; + + // Error-correct and copy data blocks together into a stream of bytes + for (int j = 0; j < dataBlocksCount; j++) { - - // Construct a parser and read version, error-correction level - BitMatrixParser parser = new BitMatrixParser(bits); - Version version = parser.readVersion(bits); - - // Read codewords - sbyte[] codewords = parser.readCodewords(); - // Separate into data blocks - DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version); - - // Count total number of data bytes - int totalBytes = 0; - for (int i = 0; i < dataBlocks.Length; i++) - { - totalBytes += dataBlocks[i].NumDataCodewords; - } - sbyte[] resultBytes = new sbyte[totalBytes]; - int resultOffset = 0; - - // Error-correct and copy data blocks together into a stream of bytes - for (int j = 0; j < dataBlocks.Length; j++) - { - DataBlock dataBlock = dataBlocks[j]; - sbyte[] codewordBytes = dataBlock.Codewords; - int numDataCodewords = dataBlock.NumDataCodewords; - correctErrors(codewordBytes, numDataCodewords); - for (int i = 0; i < numDataCodewords; i++) - { - resultBytes[resultOffset++] = codewordBytes[i]; - } - } - - // Decode the contents of that stream of bytes - return DecodedBitStreamParser.decode(resultBytes); + DataBlock dataBlock = dataBlocks[j]; + sbyte[] codewordBytes = dataBlock.Codewords; + int numDataCodewords = dataBlock.NumDataCodewords; + correctErrors(codewordBytes, numDataCodewords); + for (int i = 0; i < numDataCodewords; i++) + { + // De-interlace data blocks. + resultBytes[i * dataBlocksCount + j] = codewordBytes[i]; + } } - - ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to - /// correct the errors in-place using Reed-Solomon error correction.

- /// - ///
- /// data and error correction codewords - /// - /// number of codewords that are data bytes - /// - /// ReaderException if error correction fails - private void correctErrors(sbyte[] codewordBytes, int numDataCodewords) + + // Decode the contents of that stream of bytes + return DecodedBitStreamParser.decode(resultBytes); + } + + /// + ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to + /// correct the errors in-place using Reed-Solomon error correction.

+ ///
+ /// data and error correction codewords + /// number of codewords that are data bytes + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private void correctErrors(byte[] codewordBytes, int numDataCodewords) throws com.google.zxing.ChecksumException + private void correctErrors(sbyte[] codewordBytes, int numDataCodewords) + { + int numCodewords = codewordBytes.Length; + // First read into an array of ints + int[] codewordsInts = new int[numCodewords]; + for (int i = 0; i < numCodewords; i++) { - int numCodewords = codewordBytes.Length; - // First read into an array of ints - int[] codewordsInts = new int[numCodewords]; - for (int i = 0; i < numCodewords; i++) - { - codewordsInts[i] = codewordBytes[i] & 0xFF; - } - int numECCodewords = codewordBytes.Length - numDataCodewords; - try - { - rsDecoder.decode(codewordsInts, numECCodewords); - } - catch (ReedSolomonException) - { - throw ReaderException.Instance; - } - // 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 (int i = 0; i < numDataCodewords; i++) - { - codewordBytes[i] = (sbyte) codewordsInts[i]; - } + codewordsInts[i] = codewordBytes[i] & 0xFF; } + int numECCodewords = codewordBytes.Length - numDataCodewords; + try + { + rsDecoder.decode(codewordsInts, numECCodewords); + } + catch (ReedSolomonException rse) + { + throw ChecksumException.ChecksumInstance; + } + // 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 (int i = 0; i < numDataCodewords; i++) + { + codewordBytes[i] = (sbyte) codewordsInts[i]; + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/datamatrix/decoder/Version.cs b/csharp/datamatrix/decoder/Version.cs index e91ef7d7f..0a6525826 100755 --- a/csharp/datamatrix/decoder/Version.cs +++ b/csharp/datamatrix/decoder/Version.cs @@ -1,241 +1,234 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; + +/* + * 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. + */ + namespace com.google.zxing.datamatrix.decoder { - - /// The Version object encapsulates attributes about a particular + + using FormatException = com.google.zxing.FormatException; + + /// + /// The Version object encapsulates attributes about a particular /// size Data Matrix Code. /// + /// @author bbrown@google.com (Brian Brown) /// - /// bbrown@google.com (Brian Brown) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Version { - public int VersionNumber + + private static readonly Version[] VERSIONS = buildVersions(); + + private readonly int versionNumber; + private readonly int symbolSizeRows; + private readonly int symbolSizeColumns; + private readonly int dataRegionSizeRows; + private readonly int dataRegionSizeColumns; + private readonly ECBlocks ecBlocks; + private readonly int totalCodewords; + + private Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, int dataRegionSizeColumns, 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 + int total = 0; + int ecCodewords = ecBlocks.ECCodewords; + ECB[] ecbArray = ecBlocks.GetECB; + foreach (ECB ecBlock in ecbArray) { - get - { - return versionNumber; - } - + total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); } - public int SymbolSizeRows - { - get - { - return symbolSizeRows; - } - - } - public int SymbolSizeColumns - { - get - { - return symbolSizeColumns; - } - - } - public int DataRegionSizeRows - { - get - { - return dataRegionSizeRows; - } - - } - public int DataRegionSizeColumns - { - get - { - return dataRegionSizeColumns; - } - - } - public int TotalCodewords - { - get - { - return totalCodewords; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'VERSIONS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly Version[] VERSIONS = buildVersions(); - - //UPGRADE_NOTE: Final was removed from the declaration of 'versionNumber '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int versionNumber; - //UPGRADE_NOTE: Final was removed from the declaration of 'symbolSizeRows '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int symbolSizeRows; - //UPGRADE_NOTE: Final was removed from the declaration of 'symbolSizeColumns '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int symbolSizeColumns; - //UPGRADE_NOTE: Final was removed from the declaration of 'dataRegionSizeRows '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int dataRegionSizeRows; - //UPGRADE_NOTE: Final was removed from the declaration of 'dataRegionSizeColumns '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int dataRegionSizeColumns; - //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ECBlocks ecBlocks; - //UPGRADE_NOTE: Final was removed from the declaration of 'totalCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int totalCodewords; - - private Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, int dataRegionSizeColumns, 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 - int total = 0; - int ecCodewords = ecBlocks.ECCodewords; - ECB[] ecbArray = ecBlocks.getECBlocks(); - for (int i = 0; i < ecbArray.Length; i++) - { - ECB ecBlock = ecbArray[i]; - total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); - } - this.totalCodewords = total; - } - - internal ECBlocks getECBlocks() - { + this.totalCodewords = total; + } + + public int VersionNumber + { + get + { + return versionNumber; + } + } + + public int SymbolSizeRows + { + get + { + return symbolSizeRows; + } + } + + public int SymbolSizeColumns + { + get + { + return symbolSizeColumns; + } + } + + public int DataRegionSizeRows + { + get + { + return dataRegionSizeRows; + } + } + + public int DataRegionSizeColumns + { + get + { + return dataRegionSizeColumns; + } + } + + public int TotalCodewords + { + get + { + return totalCodewords; + } + } + + internal ECBlocks ECBlocks2 + { + get + { return ecBlocks; - } - - ///

Deduces version information from Data Matrix dimensions.

- /// - ///
- /// Number of rows in modules - /// - /// Number of columns in modules - /// - /// {@link Version} for a Data Matrix Code of those dimensions - /// - /// ReaderException if dimensions do correspond to a valid Data Matrix size - public static Version getVersionForDimensions(int numRows, int numColumns) + } + } + + /// + ///

Deduces version information from Data Matrix dimensions.

+ ///
+ /// Number of rows in modules + /// Number of columns in modules + /// Version for a Data Matrix Code of those dimensions + /// if dimensions do correspond to a valid Data Matrix size +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public static Version getVersionForDimensions(int numRows, int numColumns) throws com.google.zxing.FormatException + public static Version getVersionForDimensions(int numRows, int numColumns) + { + if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) { - if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) - { - throw ReaderException.Instance; - } - - // 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. - int numVersions = VERSIONS.Length; - for (int i = 0; i < numVersions; ++i) - { - Version version = VERSIONS[i]; - if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) - { - return version; - } - } - - throw ReaderException.Instance; + throw FormatException.FormatInstance; } - - ///

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.

- ///
- internal sealed class ECBlocks + + foreach (Version version in VERSIONS) { - internal int ECCodewords - { - get - { - return ecCodewords; - } - - } - //UPGRADE_NOTE: Final was removed from the declaration of 'ecCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int ecCodewords; - //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ECB[] ecBlocks; - - internal ECBlocks(int ecCodewords, ECB ecBlocks) - { - this.ecCodewords = ecCodewords; - this.ecBlocks = new ECB[]{ecBlocks}; - } - - internal ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) - { - this.ecCodewords = ecCodewords; - this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2}; - } - - internal ECB[] getECBlocks() - { - return ecBlocks; - } + if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) + { + return version; + } } - - ///

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.

- ///
- internal sealed class ECB + + throw FormatException.FormatInstance; + } + + /// + ///

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.

+ ///
+ internal sealed class ECBlocks + { + private readonly int ecCodewords; + private readonly ECB[] ecBlocks; + + internal ECBlocks(int ecCodewords, ECB ecBlocks) { - internal int Count - { - get - { - return count; - } - - } - internal int DataCodewords - { - get - { - return dataCodewords; - } - - } - //UPGRADE_NOTE: Final was removed from the declaration of 'count '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int count; - //UPGRADE_NOTE: Final was removed from the declaration of 'dataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int dataCodewords; - - internal ECB(int count, int dataCodewords) - { - this.count = count; - this.dataCodewords = dataCodewords; - } + this.ecCodewords = ecCodewords; + this.ecBlocks = new ECB[] {ecBlocks}; } - - public override System.String ToString() + + internal ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) { - return System.Convert.ToString(versionNumber); + this.ecCodewords = ecCodewords; + this.ecBlocks = new ECB[] {ecBlocks1, ecBlocks2}; } - - /// See ISO 16022:2006 5.5.1 Table 7 - private static Version[] buildVersions() + + internal int ECCodewords { - return new Version[]{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)))}; + get + { + return ecCodewords; + } } + + internal ECB[] GetECB + { + get + { + return ecBlocks; + } + } + } + + /// + ///

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.

+ ///
+ internal sealed class ECB + { + private readonly int count; + private readonly int dataCodewords; + + internal ECB(int count, int dataCodewords) + { + this.count = count; + this.dataCodewords = dataCodewords; + } + + internal int Count + { + get + { + return count; + } + } + + internal int DataCodewords + { + get + { + return dataCodewords; + } + } + } + + public override string ToString() + { + return Convert.ToString(versionNumber); + } + + /// + /// See ISO 16022:2006 5.5.1 Table 7 + /// + private static Version[] buildVersions() + { + return new Version[]{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, 14, 16, new ECBlocks(24, new ECB(1, 32))), new Version(30, 16, 48, 14, 22, new ECBlocks(28, new ECB(1, 49)))}; + } + } + } \ No newline at end of file diff --git a/csharp/datamatrix/detector/Detector.cs b/csharp/datamatrix/detector/Detector.cs index 31278d006..bad0ad35f 100755 --- a/csharp/datamatrix/detector/Detector.cs +++ b/csharp/datamatrix/detector/Detector.cs @@ -1,325 +1,466 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using BitMatrix = com.google.zxing.common.BitMatrix; -using Collections = com.google.zxing.common.Collections; -using Comparator = com.google.zxing.common.Comparator; -using DetectorResult = com.google.zxing.common.DetectorResult; -using GridSampler = com.google.zxing.common.GridSampler; -using MonochromeRectangleDetector = com.google.zxing.common.detector.MonochromeRectangleDetector; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.datamatrix.detector { - - ///

Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code + + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DetectorResult = com.google.zxing.common.DetectorResult; + using GridSampler = com.google.zxing.common.GridSampler; + using MathUtils = com.google.zxing.common.detector.MathUtils; + using WhiteRectangleDetector = com.google.zxing.common.detector.WhiteRectangleDetector; + + + ///

+ ///

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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Detector { - - //private static final int MAX_MODULES = 32; - - // Trick to avoid creating new Integer objects below -- a sort of crude copy of - // the Integer.valueOf(int) optimization added in Java 5, not in J2ME - //UPGRADE_NOTE: Final was removed from the declaration of 'INTEGERS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly System.Int32[] INTEGERS = new System.Int32[]{0, 1, 2, 3, 4}; - // No, can't use valueOf() - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix image; - //UPGRADE_NOTE: Final was removed from the declaration of 'rectangleDetector '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private MonochromeRectangleDetector rectangleDetector; - - public Detector(BitMatrix image) + + private readonly BitMatrix image; + private readonly WhiteRectangleDetector rectangleDetector; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public Detector(com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + public Detector(BitMatrix image) + { + this.image = image; + rectangleDetector = new WhiteRectangleDetector(image); + } + + /// + ///

Detects a Data Matrix Code in an image.

+ ///
+ /// encapsulating results of detecting a Data Matrix Code + /// if no Data Matrix Code can be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect() throws com.google.zxing.NotFoundException + public DetectorResult detect() + { + + ResultPoint[] cornerPoints = rectangleDetector.detect(); + ResultPoint pointA = cornerPoints[0]; + ResultPoint pointB = cornerPoints[1]; + ResultPoint pointC = cornerPoints[2]; + ResultPoint pointD = 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 + List transitions = new List(4); + transitions.Add(transitionsBetween(pointA, pointB)); + transitions.Add(transitionsBetween(pointA, pointC)); + transitions.Add(transitionsBetween(pointB, pointD)); + transitions.Add(transitionsBetween(pointC, pointD)); + transitions.Sort(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 + ResultPointsAndTransitions lSideOne = transitions[0]; + ResultPointsAndTransitions lSideTwo = transitions[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. + IDictionary pointCount = new Dictionary(); + increment(pointCount, lSideOne.From); + increment(pointCount, lSideOne.To); + increment(pointCount, lSideTwo.From); + increment(pointCount, lSideTwo.To); + + ResultPoint maybeTopLeft = null; + ResultPoint bottomLeft = null; + ResultPoint maybeBottomRight = null; + foreach (KeyValuePair entry in pointCount) { - this.image = image; - rectangleDetector = new MonochromeRectangleDetector(image); - } - - ///

Detects a Data Matrix Code in an image.

- /// - ///
- /// {@link DetectorResult} encapsulating results of detecting a QR Code - /// - /// ReaderException if no Data Matrix Code can be found - public DetectorResult detect() - { - - ResultPoint[] cornerPoints = rectangleDetector.detect(); - ResultPoint pointA = cornerPoints[0]; - ResultPoint pointB = cornerPoints[1]; - ResultPoint pointC = cornerPoints[2]; - ResultPoint pointD = 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 - System.Collections.ArrayList transitions = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(4)); - transitions.Add(transitionsBetween(pointA, pointB)); - transitions.Add(transitionsBetween(pointA, pointC)); - transitions.Add(transitionsBetween(pointB, pointD)); - transitions.Add(transitionsBetween(pointC, pointD)); - 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 - ResultPointsAndTransitions lSideOne = (ResultPointsAndTransitions) transitions[0]; - ResultPointsAndTransitions lSideTwo = (ResultPointsAndTransitions) transitions[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. - System.Collections.Hashtable pointCount = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); - increment(pointCount, lSideOne.From); - increment(pointCount, lSideOne.To); - increment(pointCount, lSideTwo.From); - increment(pointCount, lSideTwo.To); - - ResultPoint maybeTopLeft = null; - ResultPoint bottomLeft = null; - ResultPoint maybeBottomRight = null; - System.Collections.IEnumerator points = pointCount.Keys.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'" - while (points.MoveNext()) + ResultPoint point = entry.Key; + int? value = entry.Value; + 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) { - //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'" - ResultPoint point = (ResultPoint) points.Current; - System.Int32 value_Renamed = (System.Int32) pointCount[point]; - if (value_Renamed == 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 ReaderException.Instance; - } - - // Bottom left is correct but top left and bottom right might be switched - ResultPoint[] corners = new ResultPoint[]{maybeTopLeft, bottomLeft, maybeBottomRight}; - // Use the dot product trick to sort them out - ResultPoint.orderBestPatterns(corners); - - // Now we know which is which: - ResultPoint bottomRight = corners[0]; - bottomLeft = corners[1]; - ResultPoint topLeft = corners[2]; - - // Which point didn't we find in relation to the "L" sides? that's the top right corner - ResultPoint topRight; - if (!pointCount.ContainsKey(pointA)) - { - topRight = pointA; - } - else if (!pointCount.ContainsKey(pointB)) - { - topRight = pointB; - } - else if (!pointCount.ContainsKey(pointC)) - { - topRight = pointC; + maybeTopLeft = point; } else { - topRight = pointD; + maybeBottomRight = point; } - - // 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. The number of transitions could be higher than it should be - // due to noise. So we try both and take the min. - - int dimension = System.Math.Min(transitionsBetween(topLeft, topRight).Transitions, transitionsBetween(bottomRight, topRight).Transitions); - if ((dimension & 0x01) == 1) - { - // it can't be odd, so, round... up? - dimension++; - } - dimension += 2; - - BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension); - return new DetectorResult(bits, new ResultPoint[]{pointA, pointB, pointC, pointD}); + } } - - /// Increments the Integer associated with a key by one. - private static void increment(System.Collections.Hashtable table, ResultPoint key) + + if (maybeTopLeft == null || bottomLeft == null || maybeBottomRight == null) { - //System.Int32 value_Renamed = (System.Int32) table[key]; - ////UPGRADE_TODO: The 'System.Int32' structure does not have an equivalent to NULL. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1291'" - //table[key] = value_Renamed == null?INTEGERS[1]:INTEGERS[value_Renamed + 1]; - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Added - // START - System.Int32 value_Renamed = 0; - try - { - if (table.Count > 0) - value_Renamed = (System.Int32)table[key]; - } - catch - { - value_Renamed = 0; - } - table[key] = value_Renamed == 0 ? INTEGERS[1] : INTEGERS[value_Renamed + 1]; - //END + throw NotFoundException.NotFoundInstance; } - - private static BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, int dimension) + + // Bottom left is correct but top left and bottom right might be switched + ResultPoint[] corners = {maybeTopLeft, bottomLeft, maybeBottomRight}; + // Use the dot product trick to sort them out + ResultPoint.orderBestPatterns(corners); + + // Now we know which is which: + ResultPoint bottomRight = corners[0]; + bottomLeft = corners[1]; + ResultPoint topLeft = corners[2]; + + // Which point didn't we find in relation to the "L" sides? that's the top right corner + ResultPoint topRight; + if (!pointCount.ContainsKey(pointA)) { - - // 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. - float topRightX = (bottomRight.X - bottomLeft.X) + topLeft.X; - float topRightY = (bottomRight.Y - bottomLeft.Y) + topLeft.Y; - - // 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. - GridSampler sampler = GridSampler.Instance; - return sampler.sampleGrid(image, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRightX, topRightY, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); + topRight = pointA; } - - /// Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. - private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to) + else if (!pointCount.ContainsKey(pointB)) { - // See QR Code Detector, sizeOfBlackWhiteBlackRun() - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int fromX = (int) from.X; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int fromY = (int) from.Y; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int toX = (int) to.X; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int toY = (int) to.Y; - bool steep = System.Math.Abs(toY - fromY) > System.Math.Abs(toX - fromX); - if (steep) - { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = System.Math.Abs(toX - fromX); - int dy = System.Math.Abs(toY - fromY); - int error = - dx >> 1; - int ystep = fromY < toY?1:- 1; - int xstep = fromX < toX?1:- 1; - int transitions = 0; - bool inBlack = image.get_Renamed(steep?fromY:fromX, steep?fromX:fromY); - for (int x = fromX, y = fromY; x != toX; x += xstep) - { - bool isBlack = image.get_Renamed(steep?y:x, steep?x:y); - if (isBlack != inBlack) - { - transitions++; - inBlack = isBlack; - } - error += dy; - if (error > 0) - { - if (y == toY) - { - break; - } - y += ystep; - error -= dx; - } - } - return new ResultPointsAndTransitions(from, to, transitions); + topRight = pointB; } - - /// Simply encapsulates two points and a number of transitions between them. - private class ResultPointsAndTransitions + else if (!pointCount.ContainsKey(pointC)) { - public ResultPoint From - { - get - { - return from; - } - - } - public ResultPoint To - { - get - { - return to; - } - - } - public int Transitions - { - get - { - return transitions; - } - - } - //UPGRADE_NOTE: Final was removed from the declaration of 'from '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPoint from; - //UPGRADE_NOTE: Final was removed from the declaration of 'to '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPoint to; - //UPGRADE_NOTE: Final was removed from the declaration of 'transitions '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int transitions; - internal ResultPointsAndTransitions(ResultPoint from, ResultPoint to, int transitions) - { - this.from = from; - this.to = to; - this.transitions = transitions; - } - public override System.String ToString() - { - return from + "/" + to + '/' + transitions; - } + topRight = pointC; } - - /// Orders ResultPointsAndTransitions by number of transitions, ascending. - private class ResultPointsAndTransitionsComparator : Comparator + else { - public int compare(System.Object o1, System.Object o2) + 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. + + int dimensionTop = transitionsBetween(topLeft, topRight).Transitions; + int dimensionRight = transitionsBetween(bottomRight, topRight).Transitions; + + if ((dimensionTop & 0x01) == 1) + { + // it can't be odd, so, round... up? + dimensionTop++; + } + dimensionTop += 2; + + if ((dimensionRight & 0x01) == 1) + { + // it can't be odd, so, round... up? + dimensionRight++; + } + dimensionRight += 2; + + BitMatrix bits; + ResultPoint correctedTopRight; + + // Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more + // than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as + // rectangular if the bigger side is at least 7/4 times the other: + if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) + { + // The matrix is rectangular + + correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, dimensionTop, dimensionRight); + if (correctedTopRight == null) + { + correctedTopRight = topRight; + } + + dimensionTop = transitionsBetween(topLeft, correctedTopRight).Transitions; + dimensionRight = transitionsBetween(bottomRight, correctedTopRight).Transitions; + + if ((dimensionTop & 0x01) == 1) + { + // it can't be odd, so, round... up? + dimensionTop++; + } + + if ((dimensionRight & 0x01) == 1) + { + // it can't be odd, so, round... up? + dimensionRight++; + } + + bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionTop, dimensionRight); + + } + else + { + // The matrix is square + + int dimension = Math.Min(dimensionRight, dimensionTop); + // correct top right point to match the white module + correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension); + if (correctedTopRight == null) + { + correctedTopRight = topRight; + } + + // Redetermine the dimension using the corrected top right point + int dimensionCorrected = Math.Max(transitionsBetween(topLeft, correctedTopRight).Transitions, transitionsBetween(bottomRight, correctedTopRight).Transitions); + dimensionCorrected++; + if ((dimensionCorrected & 0x01) == 1) + { + dimensionCorrected++; + } + + bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionCorrected, dimensionCorrected); + } + + return new DetectorResult(bits, new ResultPoint[]{topLeft, bottomLeft, bottomRight, correctedTopRight}); + } + + /// + /// Calculates the position of the white top right module using the output of the rectangle detector + /// for a rectangular matrix + /// + private ResultPoint correctTopRightRectangular(ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight, int dimensionTop, int dimensionRight) + { + + float corr = distance(bottomLeft, bottomRight) / (float)dimensionTop; + int norm = distance(topLeft, topRight); + float cos = (topRight.X - topLeft.X) / norm; + float sin = (topRight.Y - topLeft.Y) / norm; + + ResultPoint c1 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); + + corr = distance(bottomLeft, topLeft) / (float)dimensionRight; + norm = distance(bottomRight, topRight); + cos = (topRight.X - bottomRight.X) / norm; + sin = (topRight.Y - bottomRight.Y) / norm; + + ResultPoint c2 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); + + if (!isValid(c1)) + { + if (isValid(c2)) + { + return c2; + } + return null; + } + if (!isValid(c2)) + { + return c1; + } + + int l1 = Math.Abs(dimensionTop - transitionsBetween(topLeft, c1).Transitions) + Math.Abs(dimensionRight - transitionsBetween(bottomRight, c1).Transitions); + int l2 = Math.Abs(dimensionTop - transitionsBetween(topLeft, c2).Transitions) + Math.Abs(dimensionRight - transitionsBetween(bottomRight, c2).Transitions); + + if (l1 <= l2) + { + return c1; + } + + return c2; + } + + /// + /// Calculates the position of the white top right module using the output of the rectangle detector + /// for a square matrix + /// + private ResultPoint correctTopRight(ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight, int dimension) + { + + float corr = distance(bottomLeft, bottomRight) / (float) dimension; + int norm = distance(topLeft, topRight); + float cos = (topRight.X - topLeft.X) / norm; + float sin = (topRight.Y - topLeft.Y) / norm; + + ResultPoint c1 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); + + corr = distance(bottomLeft, topLeft) / (float) dimension; + norm = distance(bottomRight, topRight); + cos = (topRight.X - bottomRight.X) / norm; + sin = (topRight.Y - bottomRight.Y) / norm; + + ResultPoint c2 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); + + if (!isValid(c1)) + { + if (isValid(c2)) + { + return c2; + } + return null; + } + if (!isValid(c2)) + { + return c1; + } + + int l1 = Math.Abs(transitionsBetween(topLeft, c1).Transitions - transitionsBetween(bottomRight, c1).Transitions); + int l2 = Math.Abs(transitionsBetween(topLeft, c2).Transitions - transitionsBetween(bottomRight, c2).Transitions); + + return l1 <= l2 ? c1 : c2; + } + + private bool isValid(ResultPoint p) + { + return p.X >= 0 && p.X < image.Width && p.Y > 0 && p.Y < image.Height; + } + + private static int distance(ResultPoint a, ResultPoint b) + { + return MathUtils.round(ResultPoint.distance(a, b)); + } + + /// + /// Increments the Integer associated with a key by one. + /// + private static void increment(IDictionary table, ResultPoint key) + { + int? value = null; + if (table.ContainsKey(key)) + { + value = table[key]; + } + + table[key] = value == null ? 1 : value + 1; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix sampleGrid(com.google.zxing.common.BitMatrix image, com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint bottomLeft, com.google.zxing.ResultPoint bottomRight, com.google.zxing.ResultPoint topRight, int dimensionX, int dimensionY) throws com.google.zxing.NotFoundException + private static BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topRight, int dimensionX, int dimensionY) + { + + GridSampler sampler = GridSampler.Instance; + + return sampler.sampleGrid(image, dimensionX, dimensionY, 0.5f, 0.5f, dimensionX - 0.5f, 0.5f, dimensionX - 0.5f, dimensionY - 0.5f, 0.5f, dimensionY - 0.5f, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); + } + + /// + /// Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. + /// + private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to) + { + // See QR Code Detector, sizeOfBlackWhiteBlackRun() + int fromX = (int) from.X; + int fromY = (int) from.Y; + int toX = (int) to.X; + int toY = (int) to.Y; + bool steep = Math.Abs(toY - fromY) > Math.Abs(toX - fromX); + if (steep) + { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = Math.Abs(toX - fromX); + int dy = Math.Abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? 1 : -1; + int xstep = fromX < toX ? 1 : -1; + int transitions = 0; + bool inBlack = image.get(steep ? fromY : fromX, steep ? fromX : fromY); + for (int x = fromX, y = fromY; x != toX; x += xstep) + { + bool isBlack = image.get(steep ? y : x, steep ? x : y); + if (isBlack != inBlack) + { + transitions++; + inBlack = isBlack; + } + error += dy; + if (error > 0) + { + if (y == toY) { - return ((ResultPointsAndTransitions) o1).Transitions - ((ResultPointsAndTransitions) o2).Transitions; + break; + } + y += ystep; + error -= dx; + } + } + return new ResultPointsAndTransitions(from, to, transitions); + } + + /// + /// Simply encapsulates two points and a number of transitions between them. + /// + private sealed class ResultPointsAndTransitions + { + + private readonly ResultPoint from; + private readonly ResultPoint to; + private readonly int transitions; + + internal ResultPointsAndTransitions(ResultPoint from, ResultPoint to, int transitions) + { + this.from = from; + this.to = to; + this.transitions = transitions; + } + + internal ResultPoint From + { + get + { + return from; } } + + internal ResultPoint To + { + get + { + return to; + } + } + + public int Transitions + { + get + { + return transitions; + } + } + + public override string ToString() + { + return from + "/" + to + '/' + transitions; + } + } + + /// + /// Orders ResultPointsAndTransitions by number of transitions, ascending. + /// + [Serializable] + private sealed class ResultPointsAndTransitionsComparator : IComparer + { + public int Compare(ResultPointsAndTransitions o1, ResultPointsAndTransitions o2) + { + return o1.Transitions - o2.Transitions; + } + } + } + } \ No newline at end of file diff --git a/csharp/multi/ByQuadrantReader.cs b/csharp/multi/ByQuadrantReader.cs index 47a69c0a3..2ee769296 100755 --- a/csharp/multi/ByQuadrantReader.cs +++ b/csharp/multi/ByQuadrantReader.cs @@ -1,103 +1,119 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using Reader = com.google.zxing.Reader; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; + * 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. + */ + namespace com.google.zxing.multi { - - /// This class attempts to decode a barcode from an image, not by scanning the whole image, + + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using Result = com.google.zxing.Result; + + + /// + /// This class attempts to decode a barcode from an image, not by scanning the whole image, /// but by scanning subsets of the image. This is important when there may be multiple barcodes in /// an image, and detecting a barcode may find parts of multiple barcode and fail to decode /// (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center /// 'quadrant' to cover the case where a barcode is found in the center. - /// /// - /// - /// - public sealed class ByQuadrantReader : Reader + /// + public sealed class ByQuadrantReader : com.google.zxing.Reader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'delegate '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Reader delegate_Renamed; - - public ByQuadrantReader(Reader delegate_Renamed) + + private readonly Reader @delegate; + + public ByQuadrantReader(Reader @delegate) + { + this.@delegate = @delegate; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image) + { + return decode(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image, IDictionary hints) + { + + int width = image.Width; + int height = image.Height; + int halfWidth = width / 2; + int halfHeight = height / 2; + + BinaryBitmap topLeft = image.crop(0, 0, halfWidth, halfHeight); + try { - this.delegate_Renamed = delegate_Renamed; + return @delegate.decode(topLeft, hints); } - - public Result decode(BinaryBitmap image) + catch (NotFoundException re) { - return decode(image, null); + // continue } - - public Result decode(BinaryBitmap image, System.Collections.Hashtable hints) + + BinaryBitmap topRight = image.crop(halfWidth, 0, halfWidth, halfHeight); + try { - - int width = image.Width; - int height = image.Height; - int halfWidth = width / 2; - int halfHeight = height / 2; - - BinaryBitmap topLeft = image.crop(0, 0, halfWidth, halfHeight); - try - { - return delegate_Renamed.decode(topLeft, hints); - } - catch (ReaderException) - { - // continue - } - - BinaryBitmap topRight = image.crop(halfWidth, 0, halfWidth, halfHeight); - try - { - return delegate_Renamed.decode(topRight, hints); - } - catch (ReaderException) - { - // continue - } - - BinaryBitmap bottomLeft = image.crop(0, halfHeight, halfWidth, halfHeight); - try - { - return delegate_Renamed.decode(bottomLeft, hints); - } - catch (ReaderException) - { - // continue - } - - BinaryBitmap bottomRight = image.crop(halfWidth, halfHeight, halfWidth, halfHeight); - try - { - return delegate_Renamed.decode(bottomRight, hints); - } - catch (ReaderException) - { - // continue - } - - int quarterWidth = halfWidth / 2; - int quarterHeight = halfHeight / 2; - BinaryBitmap center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight); - return delegate_Renamed.decode(center, hints); + return @delegate.decode(topRight, hints); } + catch (NotFoundException re) + { + // continue + } + + BinaryBitmap bottomLeft = image.crop(0, halfHeight, halfWidth, halfHeight); + try + { + return @delegate.decode(bottomLeft, hints); + } + catch (NotFoundException re) + { + // continue + } + + BinaryBitmap bottomRight = image.crop(halfWidth, halfHeight, halfWidth, halfHeight); + try + { + return @delegate.decode(bottomRight, hints); + } + catch (NotFoundException re) + { + // continue + } + + int quarterWidth = halfWidth / 2; + int quarterHeight = halfHeight / 2; + BinaryBitmap center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight); + return @delegate.decode(center, hints); + } + + public void reset() + { + @delegate.reset(); + } + } -} + +} \ No newline at end of file diff --git a/csharp/multi/GenericMultipleBarcodeReader.cs b/csharp/multi/GenericMultipleBarcodeReader.cs index 708b84fc3..bfe761feb 100755 --- a/csharp/multi/GenericMultipleBarcodeReader.cs +++ b/csharp/multi/GenericMultipleBarcodeReader.cs @@ -1,175 +1,174 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Reader = com.google.zxing.Reader; -using Result = com.google.zxing.Result; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; + * 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. + */ + namespace com.google.zxing.multi { - - ///

Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. + + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using ResultPoint = com.google.zxing.ResultPoint; + + + ///

+ ///

Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. /// After one barcode is found, the areas left, above, right and below the barcode's - /// {@link com.google.zxing.ResultPoint}s are scanned, recursively.

+ /// s are scanned, recursively.

/// - ///

A caller may want to also employ {@link ByQuadrantReader} when attempting to find multiple + ///

A caller may want to also employ when attempting to find multiple /// 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent /// detecting any one of them.

/// - ///

That is, instead of passing a {@link Reader} a caller might pass - /// new ByQuadrantReader(reader).

+ ///

That is, instead of passing a a caller might pass + /// {@code new ByQuadrantReader(reader)}.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class GenericMultipleBarcodeReader : MultipleBarcodeReader { - - private const int MIN_DIMENSION_TO_RECUR = 30; - - //UPGRADE_NOTE: Final was removed from the declaration of 'delegate '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Reader delegate_Renamed; - - public GenericMultipleBarcodeReader(Reader delegate_Renamed) + + private const int MIN_DIMENSION_TO_RECUR = 100; + + private readonly Reader @delegate; + + public GenericMultipleBarcodeReader(Reader @delegate) + { + this.@delegate = @delegate; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException + public Result[] decodeMultiple(BinaryBitmap image) + { + return decodeMultiple(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException + public Result[] decodeMultiple(BinaryBitmap image, IDictionary hints) + { + List results = new List(); + doDecodeMultiple(image, hints, results, 0, 0); + if (results.Count == 0) { - this.delegate_Renamed = delegate_Renamed; + throw NotFoundException.NotFoundInstance; } - - public Result[] decodeMultiple(BinaryBitmap image) + return results.ToArray(); + } + + private void doDecodeMultiple(BinaryBitmap image, IDictionary hints, IList results, int xOffset, int yOffset) + { + Result result; + try { - return decodeMultiple(image, null); + result = @delegate.decode(image, hints); } - - public Result[] decodeMultiple(BinaryBitmap image, System.Collections.Hashtable hints) + catch (ReaderException re) { - System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - doDecodeMultiple(image, hints, results, 0, 0); - if ((results.Count == 0)) - { - throw ReaderException.Instance; - } - int numResults = results.Count; - Result[] resultArray = new Result[numResults]; - for (int i = 0; i < numResults; i++) - { - resultArray[i] = (Result) results[i]; - } - return resultArray; + return; } - - private void doDecodeMultiple(BinaryBitmap image, System.Collections.Hashtable hints, System.Collections.ArrayList results, int xOffset, int yOffset) + bool alreadyFound = false; + foreach (Result existingResult in results) { - Result result; - try - { - result = delegate_Renamed.decode(image, hints); - } - catch (ReaderException) - { - return ; - } - bool alreadyFound = false; - for (int i = 0; i < results.Count; i++) - { - Result existingResult = (Result) results[i]; - if (existingResult.Text.Equals(result.Text)) - { - alreadyFound = true; - break; - } - } - if (alreadyFound) - { - return ; - } - results.Add(translateResultPoints(result, xOffset, yOffset)); - ResultPoint[] resultPoints = result.ResultPoints; - if (resultPoints == null || resultPoints.Length == 0) - { - return ; - } - int width = image.Width; - int height = image.Height; - float minX = width; - float minY = height; - float maxX = 0.0f; - float maxY = 0.0f; - for (int i = 0; i < resultPoints.Length; i++) - { - ResultPoint point = resultPoints[i]; - float x = point.X; - float y = point.Y; - if (x < minX) - { - minX = x; - } - if (y < minY) - { - minY = y; - } - if (x > maxX) - { - maxX = x; - } - if (y > maxY) - { - maxY = y; - } - } - - // Decode left of barcode - if (minX > MIN_DIMENSION_TO_RECUR) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - doDecodeMultiple(image.crop(0, 0, (int) minX, height), hints, results, xOffset, yOffset); - } - // Decode above barcode - if (minY > MIN_DIMENSION_TO_RECUR) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - doDecodeMultiple(image.crop(0, 0, width, (int) minY), hints, results, xOffset, yOffset); - } - // Decode right of barcode - if (maxX < width - MIN_DIMENSION_TO_RECUR) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - doDecodeMultiple(image.crop((int) maxX, 0, width - (int) maxX, height), hints, results, xOffset + (int) maxX, yOffset); - } - // Decode below barcode - if (maxY < height - MIN_DIMENSION_TO_RECUR) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - doDecodeMultiple(image.crop(0, (int) maxY, width, height - (int) maxY), hints, results, xOffset, yOffset + (int) maxY); - } + if (existingResult.Text.Equals(result.Text)) + { + alreadyFound = true; + break; + } } - - private static Result translateResultPoints(Result result, int xOffset, int yOffset) + if (!alreadyFound) { - ResultPoint[] oldResultPoints = result.ResultPoints; - ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.Length]; - for (int i = 0; i < oldResultPoints.Length; i++) - { - ResultPoint oldPoint = oldResultPoints[i]; - newResultPoints[i] = new ResultPoint(oldPoint.X + xOffset, oldPoint.Y + yOffset); - } - return new Result(result.Text, result.RawBytes, newResultPoints, result.BarcodeFormat); + results.Add(translateResultPoints(result, xOffset, yOffset)); } + ResultPoint[] resultPoints = result.ResultPoints; + if (resultPoints == null || resultPoints.Length == 0) + { + return; + } + int width = image.Width; + int height = image.Height; + float minX = width; + float minY = height; + float maxX = 0.0f; + float maxY = 0.0f; + foreach (ResultPoint point in resultPoints) + { + float x = point.X; + float y = point.Y; + if (x < minX) + { + minX = x; + } + if (y < minY) + { + minY = y; + } + if (x > maxX) + { + maxX = x; + } + if (y > maxY) + { + maxY = y; + } + } + + // Decode left of barcode + if (minX > MIN_DIMENSION_TO_RECUR) + { + doDecodeMultiple(image.crop(0, 0, (int) minX, height), hints, results, xOffset, yOffset); + } + // Decode above barcode + if (minY > MIN_DIMENSION_TO_RECUR) + { + doDecodeMultiple(image.crop(0, 0, width, (int) minY), hints, results, xOffset, yOffset); + } + // Decode right of barcode + if (maxX < width - MIN_DIMENSION_TO_RECUR) + { + doDecodeMultiple(image.crop((int) maxX, 0, width - (int) maxX, height), hints, results, xOffset + (int) maxX, yOffset); + } + // Decode below barcode + if (maxY < height - MIN_DIMENSION_TO_RECUR) + { + doDecodeMultiple(image.crop(0, (int) maxY, width, height - (int) maxY), hints, results, xOffset, yOffset + (int) maxY); + } + } + + private static Result translateResultPoints(Result result, int xOffset, int yOffset) + { + ResultPoint[] oldResultPoints = result.ResultPoints; + if (oldResultPoints == null) + { + return result; + } + ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.Length]; + for (int i = 0; i < oldResultPoints.Length; i++) + { + ResultPoint oldPoint = oldResultPoints[i]; + newResultPoints[i] = new ResultPoint(oldPoint.X + xOffset, oldPoint.Y + yOffset); + } + return new Result(result.Text, result.RawBytes, newResultPoints, result.BarcodeFormat); + } + } -} + +} \ No newline at end of file diff --git a/csharp/multi/MultipleBarcodeReader.cs b/csharp/multi/MultipleBarcodeReader.cs index 3a0dcba5b..652fe6cc3 100755 --- a/csharp/multi/MultipleBarcodeReader.cs +++ b/csharp/multi/MultipleBarcodeReader.cs @@ -1,40 +1,46 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using Result = com.google.zxing.Result; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using ReaderException = com.google.zxing.ReaderException; + * 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. + */ + namespace com.google.zxing.multi { - - /// Implementation of this interface attempt to read several barcodes from one image. - /// - /// - /// - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using Result = com.google.zxing.Result; + + + /// + /// Implementation of this interface attempt to read several barcodes from one image. + /// + /// public interface MultipleBarcodeReader { - - Result[] decodeMultiple(BinaryBitmap image); - - Result[] decodeMultiple(BinaryBitmap image, System.Collections.Hashtable hints); + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException; + Result[] decodeMultiple(BinaryBitmap image); + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException; + Result[] decodeMultiple(BinaryBitmap image, IDictionary hints); + } + } \ No newline at end of file diff --git a/csharp/multi/qrcode/QRCodeMultiReader.cs b/csharp/multi/qrcode/QRCodeMultiReader.cs index e27f3657d..01757ac44 100755 --- a/csharp/multi/qrcode/QRCodeMultiReader.cs +++ b/csharp/multi/qrcode/QRCodeMultiReader.cs @@ -1,93 +1,97 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultMetadataType = com.google.zxing.ResultMetadataType; -using ResultPoint = com.google.zxing.ResultPoint; -using DecoderResult = com.google.zxing.common.DecoderResult; -using DetectorResult = com.google.zxing.common.DetectorResult; -using MultipleBarcodeReader = com.google.zxing.multi.MultipleBarcodeReader; -using MultiDetector = com.google.zxing.multi.qrcode.detector.MultiDetector; -using QRCodeReader = com.google.zxing.qrcode.QRCodeReader; + * 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. + */ + namespace com.google.zxing.multi.qrcode { - - /// This implementation can detect and decode multiple QR Codes in an image. - /// - /// - /// Sean Owen - /// - /// Hannes Erven - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class QRCodeMultiReader:QRCodeReader, MultipleBarcodeReader + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using ResultMetadataType = com.google.zxing.ResultMetadataType; + using ResultPoint = com.google.zxing.ResultPoint; + using DecoderResult = com.google.zxing.common.DecoderResult; + using DetectorResult = com.google.zxing.common.DetectorResult; + using MultipleBarcodeReader = com.google.zxing.multi.MultipleBarcodeReader; + using MultiDetector = com.google.zxing.multi.qrcode.detector.MultiDetector; + using QRCodeReader = com.google.zxing.qrcode.QRCodeReader; + + + /// + /// This implementation can detect and decode multiple QR Codes in an image. + /// + /// @author Sean Owen + /// @author Hannes Erven + /// + public sealed class QRCodeMultiReader : com.google.zxing.qrcode.QRCodeReader, com.google.zxing.multi.MultipleBarcodeReader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'EMPTY_RESULT_ARRAY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly Result[] EMPTY_RESULT_ARRAY = new Result[0]; - - public Result[] decodeMultiple(BinaryBitmap image) + + private static readonly Result[] EMPTY_RESULT_ARRAY = new Result[0]; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException + public Result[] decodeMultiple(BinaryBitmap image) + { + return decodeMultiple(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result[] decodeMultiple(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException + public Result[] decodeMultiple(BinaryBitmap image, IDictionary hints) + { + List results = new List(); + DetectorResult[] detectorResults = (new MultiDetector(image.BlackMatrix)).detectMulti(hints); + foreach (DetectorResult detectorResult in detectorResults) { - return decodeMultiple(image, null); + try + { + DecoderResult decoderResult = Decoder.decode(detectorResult.Bits, hints); + ResultPoint[] points = detectorResult.Points; + Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); + IList byteSegments = decoderResult.ByteSegments; + if (byteSegments != null) + { + result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); + } + string ecLevel = decoderResult.ECLevel; + if (ecLevel != null) + { + result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); + } + results.Add(result); + } + catch (ReaderException re) + { + // ignore and continue + } } - - public Result[] decodeMultiple(BinaryBitmap image, System.Collections.Hashtable hints) + if (results.Count == 0) { - System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - DetectorResult[] detectorResult = new MultiDetector(image.BlackMatrix).detectMulti(hints); - for (int i = 0; i < detectorResult.Length; i++) - { - try - { - DecoderResult decoderResult = Decoder.decode(detectorResult[i].Bits); - ResultPoint[] points = detectorResult[i].Points; - Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); - if (decoderResult.ByteSegments != null) - { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.ByteSegments); - } - if (decoderResult.ECLevel != null) - { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel.ToString()); - } - results.Add(result); - } - catch (ReaderException) - { - // ignore and continue - } - } - if ((results.Count == 0)) - { - return EMPTY_RESULT_ARRAY; - } - else - { - Result[] resultArray = new Result[results.Count]; - for (int i = 0; i < results.Count; i++) - { - resultArray[i] = (Result) results[i]; - } - return resultArray; - } + return EMPTY_RESULT_ARRAY; } + else + { + return results.ToArray(); + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/multi/qrcode/detector/MultiDetector.cs b/csharp/multi/qrcode/detector/MultiDetector.cs index 8a7ac856f..eadcc1024 100755 --- a/csharp/multi/qrcode/detector/MultiDetector.cs +++ b/csharp/multi/qrcode/detector/MultiDetector.cs @@ -1,84 +1,92 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using DetectorResult = com.google.zxing.common.DetectorResult; -using BitMatrix = com.google.zxing.common.BitMatrix; -using Detector = com.google.zxing.qrcode.detector.Detector; -using FinderPatternInfo = com.google.zxing.qrcode.detector.FinderPatternInfo; + * 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. + */ + namespace com.google.zxing.multi.qrcode.detector { - - ///

Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code + + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using ReaderException = com.google.zxing.ReaderException; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DetectorResult = com.google.zxing.common.DetectorResult; + using Detector = com.google.zxing.qrcode.detector.Detector; + using FinderPatternInfo = com.google.zxing.qrcode.detector.FinderPatternInfo; + + + ///

+ ///

Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code /// is rotated or skewed, or partially obscured.

/// + /// @author Sean Owen + /// @author Hannes Erven ///
- /// Sean Owen - /// - /// Hannes Erven - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - - public sealed class MultiDetector:Detector + public sealed class MultiDetector : com.google.zxing.qrcode.detector.Detector { - - //UPGRADE_NOTE: Final was removed from the declaration of 'EMPTY_DETECTOR_RESULTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly DetectorResult[] EMPTY_DETECTOR_RESULTS = new DetectorResult[0]; - - public MultiDetector(BitMatrix image):base(image) + + private static readonly DetectorResult[] EMPTY_DETECTOR_RESULTS = new DetectorResult[0]; + + public MultiDetector(BitMatrix image) : base(image) + { + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DetectorResult[] detectMulti(java.util.Map hints) throws com.google.zxing.NotFoundException + public DetectorResult[] detectMulti(IDictionary hints) + { + BitMatrix image = Image; + //ResultPointCallback resultPointCallback = hints == null ? null : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + ResultPointCallback resultPointCallback = null; + if (hints !=null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) + { + resultPointCallback = (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + } + + MultiFinderPatternFinder finder = new MultiFinderPatternFinder(image, resultPointCallback); + FinderPatternInfo[] infos = finder.findMulti(hints); + + if (infos.Length == 0) { + throw NotFoundException.NotFoundInstance; } - - public DetectorResult[] detectMulti(System.Collections.Hashtable hints) + + List result = new List(); + foreach (FinderPatternInfo info in infos) { - BitMatrix image = Image; - MultiFinderPatternFinder finder = new MultiFinderPatternFinder(image); - FinderPatternInfo[] info = finder.findMulti(hints); - - if (info == null || info.Length == 0) - { - throw ReaderException.Instance; - } - - System.Collections.ArrayList result = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - for (int i = 0; i < info.Length; i++) - { - try - { - result.Add(processFinderPatternInfo(info[i])); - } - catch (ReaderException) - { - // ignore - } - } - if ((result.Count == 0)) - { - return EMPTY_DETECTOR_RESULTS; - } - else - { - DetectorResult[] resultArray = new DetectorResult[result.Count]; - for (int i = 0; i < result.Count; i++) - { - resultArray[i] = (DetectorResult) result[i]; - } - return resultArray; - } + try + { + result.Add(processFinderPatternInfo(info)); + } + catch (ReaderException e) + { + // ignore + } } + if (result.Count == 0) + { + return EMPTY_DETECTOR_RESULTS; + } + else + { + return result.ToArray(); + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/multi/qrcode/detector/MultiFinderPatternFinder.cs b/csharp/multi/qrcode/detector/MultiFinderPatternFinder.cs index 7766b19b6..9bf709c5a 100755 --- a/csharp/multi/qrcode/detector/MultiFinderPatternFinder.cs +++ b/csharp/multi/qrcode/detector/MultiFinderPatternFinder.cs @@ -1,367 +1,351 @@ -/* -* 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. -*/ using System; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultPointCallback = com.google.zxing.ResultPointCallback; -using Collections = com.google.zxing.common.Collections; -using Comparator = com.google.zxing.common.Comparator; -using BitMatrix = com.google.zxing.common.BitMatrix; -using FinderPattern = com.google.zxing.qrcode.detector.FinderPattern; -using FinderPatternFinder = com.google.zxing.qrcode.detector.FinderPatternFinder; -using FinderPatternInfo = com.google.zxing.qrcode.detector.FinderPatternInfo; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.multi.qrcode.detector { - - ///

This class attempts to find finder patterns in a QR Code. Finder patterns are the square + + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitMatrix = com.google.zxing.common.BitMatrix; + using FinderPattern = com.google.zxing.qrcode.detector.FinderPattern; + using FinderPatternFinder = com.google.zxing.qrcode.detector.FinderPatternFinder; + using FinderPatternInfo = com.google.zxing.qrcode.detector.FinderPatternInfo; + + + ///

+ ///

This class attempts to find finder patterns in a QR Code. Finder patterns are the square /// markers at three corners of a QR Code.

/// ///

This class is thread-safe but not reentrant. Each thread must allocate its own object. /// - ///

In contrast to {@link FinderPatternFinder}, this class will return an array of all possible + ///

In contrast to , this class will return an array of all possible /// QR code locations in the image.

/// ///

Use the TRY_HARDER hint to ask for a more thorough detection.

/// + /// @author Sean Owen + /// @author Hannes Erven ///
- /// Sean Owen - /// - /// Hannes Erven - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - - - sealed class MultiFinderPatternFinder:FinderPatternFinder + internal sealed class MultiFinderPatternFinder : com.google.zxing.qrcode.detector.FinderPatternFinder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'EMPTY_RESULT_ARRAY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly FinderPatternInfo[] EMPTY_RESULT_ARRAY = new FinderPatternInfo[0]; - - // TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for - // since it limits the number of regions to decode - - // max. legal count of modules per QR code edge (177) - private const float MAX_MODULE_COUNT_PER_EDGE = 180; - // min. legal count per modules per QR code edge (11) - private const float MIN_MODULE_COUNT_PER_EDGE = 9; - - /// More or less arbitrary cutoff point for determining if two finder patterns might belong - /// to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their - /// estimated modules sizes. - /// - private const float DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; - - /// More or less arbitrary cutoff point for determining if two finder patterns might belong - /// to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their - /// estimated modules sizes. - /// - private const float DIFF_MODSIZE_CUTOFF = 0.5f; - - - /// A comparator that orders FinderPatterns by their estimated module size. - private class ModuleSizeComparator : Comparator + + private static readonly FinderPatternInfo[] EMPTY_RESULT_ARRAY = new FinderPatternInfo[0]; + + // TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for + // since it limits the number of regions to decode + + // max. legal count of modules per QR code edge (177) + private const float MAX_MODULE_COUNT_PER_EDGE = 180; + // min. legal count per modules per QR code edge (11) + private const float MIN_MODULE_COUNT_PER_EDGE = 9; + + /// + /// More or less arbitrary cutoff point for determining if two finder patterns might belong + /// to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their + /// estimated modules sizes. + /// + private const float DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; + + /// + /// More or less arbitrary cutoff point for determining if two finder patterns might belong + /// to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their + /// estimated modules sizes. + /// + private const float DIFF_MODSIZE_CUTOFF = 0.5f; + + + /// + /// A comparator that orders FinderPatterns by their estimated module size. + /// + [Serializable] + private sealed class ModuleSizeComparator : IComparer + { + public int Compare(FinderPattern center1, FinderPattern center2) { - public int compare(System.Object center1, System.Object center2) - { - float value_Renamed = ((FinderPattern) center2).EstimatedModuleSize - ((FinderPattern) center1).EstimatedModuleSize; - return value_Renamed < 0.0?- 1:(value_Renamed > 0.0?1:0); - } + float value = center2.EstimatedModuleSize - center1.EstimatedModuleSize; + return value < 0.0 ? - 1 : value > 0.0 ? 1 : 0; } - - ///

Creates a finder that will search the image for three finder patterns.

- /// - ///
- /// image to search - /// - internal MultiFinderPatternFinder(BitMatrix image):base(image) + } + + /// + ///

Creates a finder that will search the image for three finder patterns.

+ ///
+ /// image to search + internal MultiFinderPatternFinder(BitMatrix image) : base(image) + { + } + + internal MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) : base(image, resultPointCallback) + { + } + + /// the 3 best s from our list of candidates. The "best" are + /// those that have been detected at least times, and whose module + /// size differs from the average among those patterns the least + /// if 3 such finder patterns do not exist +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private com.google.zxing.qrcode.detector.FinderPattern[][] selectMutipleBestPatterns() throws com.google.zxing.NotFoundException + private FinderPattern[][] selectMutipleBestPatterns() + { + List possibleCenters = PossibleCenters; + int size = possibleCenters.Count; + + if (size < 3) { + // Couldn't find enough finder patterns + throw NotFoundException.NotFoundInstance; } - - internal MultiFinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback):base(image, resultPointCallback) + + /* + * Begin HE modifications to safely detect multiple codes of equal size + */ + if (size == 3) { + return new FinderPattern[][]{new FinderPattern[]{possibleCenters[0], possibleCenters[1], possibleCenters[2]}}; } - - /// the 3 best {@link FinderPattern}s from our list of candidates. The "best" are - /// those that have been detected at least {@link #CENTER_QUORUM} times, and whose module - /// size differs from the average among those patterns the least - /// - /// ReaderException if 3 such finder patterns do not exist - private FinderPattern[][] selectBestPatterns() + + // Sort by estimated module size to speed up the upcoming checks + possibleCenters.Sort(new ModuleSizeComparator()); + + /* + * Now lets start: build a list of tuples of three finder locations that + * - feature similar module sizes + * - are placed in a distance so the estimated module count is within the QR specification + * - have similar distance between upper left/right and left top/bottom finder patterns + * - form a triangle with 90° angle (checked by comparing top right/bottom left distance + * with pythagoras) + * + * Note: we allow each point to be used for more than one code region: this might seem + * counterintuitive at first, but the performance penalty is not that big. At this point, + * we cannot make a good quality decision whether the three finders actually represent + * a QR code, or are just by chance layouted so it looks like there might be a QR code there. + * So, if the layout seems right, lets have the decoder try to decode. + */ + + List results = new List(); // holder for the results + + for (int i1 = 0; i1 < (size - 2); i1++) { - System.Collections.ArrayList possibleCenters = PossibleCenters; - int size = possibleCenters.Count; - - if (size < 3) + FinderPattern p1 = possibleCenters[i1]; + if (p1 == null) + { + continue; + } + + for (int i2 = i1 + 1; i2 < (size - 1); i2++) + { + FinderPattern p2 = possibleCenters[i2]; + if (p2 == null) { - // Couldn't find enough finder patterns - throw ReaderException.Instance; + continue; } - - /* - * Begin HE modifications to safely detect multiple codes of equal size - */ - if (size == 3) + + // Compare the expected module sizes; if they are really off, skip + float vModSize12 = (p1.EstimatedModuleSize - p2.EstimatedModuleSize) / Math.Min(p1.EstimatedModuleSize, p2.EstimatedModuleSize); + float vModSize12A = Math.Abs(p1.EstimatedModuleSize - p2.EstimatedModuleSize); + if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) { - return new FinderPattern[][]{new FinderPattern[]{(FinderPattern) possibleCenters[0], (FinderPattern) possibleCenters[1], (FinderPattern) possibleCenters[2]}}; + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; } - - // Sort by estimated module size to speed up the upcoming checks - Collections.insertionSort(possibleCenters, new ModuleSizeComparator()); - - /* - * Now lets start: build a list of tuples of three finder locations that - * - feature similar module sizes - * - are placed in a distance so the estimated module count is within the QR specification - * - have similar distance between upper left/right and left top/bottom finder patterns - * - form a triangle with 90° angle (checked by comparing top right/bottom left distance - * with pythagoras) - * - * Note: we allow each point to be used for more than one code region: this might seem - * counterintuitive at first, but the performance penalty is not that big. At this point, - * we cannot make a good quality decision whether the three finders actually represent - * a QR code, or are just by chance layouted so it looks like there might be a QR code there. - * So, if the layout seems right, lets have the decoder try to decode. - */ - - System.Collections.ArrayList results = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); // holder for the results - - for (int i1 = 0; i1 < (size - 2); i1++) + + for (int i3 = i2 + 1; i3 < size; i3++) { - FinderPattern p1 = (FinderPattern) possibleCenters[i1]; - if (p1 == null) - { - continue; - } - - for (int i2 = i1 + 1; i2 < (size - 1); i2++) - { - FinderPattern p2 = (FinderPattern) possibleCenters[i2]; - if (p2 == null) - { - continue; - } - - // Compare the expected module sizes; if they are really off, skip - float vModSize12 = (p1.EstimatedModuleSize - p2.EstimatedModuleSize) / (System.Math.Min(p1.EstimatedModuleSize, p2.EstimatedModuleSize)); - float vModSize12A = System.Math.Abs(p1.EstimatedModuleSize - p2.EstimatedModuleSize); - if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) - { - // break, since elements are ordered by the module size deviation there cannot be - // any more interesting elements for the given p1. - break; - } - - for (int i3 = i2 + 1; i3 < size; i3++) - { - FinderPattern p3 = (FinderPattern) possibleCenters[i3]; - if (p3 == null) - { - continue; - } - - // Compare the expected module sizes; if they are really off, skip - float vModSize23 = (p2.EstimatedModuleSize - p3.EstimatedModuleSize) / (System.Math.Min(p2.EstimatedModuleSize, p3.EstimatedModuleSize)); - float vModSize23A = System.Math.Abs(p2.EstimatedModuleSize - p3.EstimatedModuleSize); - if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) - { - // break, since elements are ordered by the module size deviation there cannot be - // any more interesting elements for the given p1. - break; - } - - FinderPattern[] test = new FinderPattern[]{p1, p2, p3}; - ResultPoint.orderBestPatterns(test); - - // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal - FinderPatternInfo info = new FinderPatternInfo(test); - float dA = ResultPoint.distance(info.TopLeft, info.BottomLeft); - float dC = ResultPoint.distance(info.TopRight, info.BottomLeft); - float dB = ResultPoint.distance(info.TopLeft, info.TopRight); - - // Check the sizes - float estimatedModuleCount = ((dA + dB) / p1.EstimatedModuleSize) / 2; - if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) - { - continue; - } - - // Calculate the difference of the edge lengths in percent - float vABBC = System.Math.Abs(((dA - dB) / System.Math.Min(dA, dB))); - if (vABBC >= 0.1f) - { - continue; - } - - // Calculate the diagonal length by assuming a 90° angle at topleft - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float dCpy = (float) System.Math.Sqrt(dA * dA + dB * dB); - // Compare to the real distance in % - float vPyC = System.Math.Abs(((dC - dCpy) / System.Math.Min(dC, dCpy))); - - if (vPyC >= 0.1f) - { - continue; - } - - // All tests passed! - results.Add(test); - } // end iterate p3 - } // end iterate p2 - } // end iterate p1 - - if (!(results.Count == 0)) - { - FinderPattern[][] resultArray = new FinderPattern[results.Count][]; - for (int i = 0; i < results.Count; i++) - { - resultArray[i] = (FinderPattern[]) results[i]; - } - return resultArray; - } - - // Nothing found! - throw ReaderException.Instance; + FinderPattern p3 = possibleCenters[i3]; + if (p3 == null) + { + continue; + } + + // Compare the expected module sizes; if they are really off, skip + float vModSize23 = (p2.EstimatedModuleSize - p3.EstimatedModuleSize) / Math.Min(p2.EstimatedModuleSize, p3.EstimatedModuleSize); + float vModSize23A = Math.Abs(p2.EstimatedModuleSize - p3.EstimatedModuleSize); + if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) + { + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; + } + + FinderPattern[] test = {p1, p2, p3}; + ResultPoint.orderBestPatterns(test); + + // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal + FinderPatternInfo info = new FinderPatternInfo(test); + float dA = ResultPoint.distance(info.TopLeft, info.BottomLeft); + float dC = ResultPoint.distance(info.TopRight, info.BottomLeft); + float dB = ResultPoint.distance(info.TopLeft, info.TopRight); + + // Check the sizes + float estimatedModuleCount = (dA + dB) / (p1.EstimatedModuleSize * 2.0f); + if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) + { + continue; + } + + // Calculate the difference of the edge lengths in percent + float vABBC = Math.Abs((dA - dB) / Math.Min(dA, dB)); + if (vABBC >= 0.1f) + { + continue; + } + + // Calculate the diagonal length by assuming a 90° angle at topleft + float dCpy = (float) Math.Sqrt(dA * dA + dB * dB); + // Compare to the real distance in % + float vPyC = Math.Abs((dC - dCpy) / Math.Min(dC, dCpy)); + + if (vPyC >= 0.1f) + { + continue; + } + + // All tests passed! + results.Add(test); + } // end iterate p3 + } // end iterate p2 + } // end iterate p1 + + if (results.Count > 0) + { + return results.ToArray(); } - - public FinderPatternInfo[] findMulti(System.Collections.Hashtable hints) + + // Nothing found! + throw NotFoundException.NotFoundInstance; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.qrcode.detector.FinderPatternInfo[] findMulti(java.util.Map hints) throws com.google.zxing.NotFoundException + public FinderPatternInfo[] findMulti(IDictionary hints) + { + bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); + BitMatrix image = Image; + int maxI = image.Height; + int maxJ = image.Width; + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (int)(maxI / (MAX_MODULES * 4.0f) * 3); + if (iSkip < MIN_SKIP || tryHarder) { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - BitMatrix image = Image; - int maxI = image.Height; - int maxJ = image.Width; - // We are looking for black/white/black/white/black modules in - // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - - // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the - // image, and then account for the center being 3 modules in size. This gives the smallest - // number of pixels the center could be, so skip this often. When trying harder, look for all - // QR versions regardless of how dense they are. - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3); - if (iSkip < MIN_SKIP || tryHarder) + iSkip = MIN_SKIP; + } + + int[] stateCount = new int[5]; + for (int i = iSkip - 1; i < maxI; i += iSkip) + { + // Get a row of black/white values + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (int j = 0; j < maxJ; j++) + { + if (image.get(j, i)) { - iSkip = MIN_SKIP; - } - - int[] stateCount = new int[5]; - for (int i = iSkip - 1; i < maxI; i += iSkip) - { - // Get a row of black/white values - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - int currentState = 0; - for (int j = 0; j < maxJ; j++) - { - if (image.get_Renamed(j, i)) - { - // Black pixel - if ((currentState & 1) == 1) - { - // Counting white pixels - currentState++; - } - stateCount[currentState]++; - } - else - { - // White pixel - if ((currentState & 1) == 0) - { - // Counting black pixels - if (currentState == 4) - { - // A winner? - if (foundPatternCross(stateCount)) - { - // Yes - bool confirmed = handlePossibleCenter(stateCount, i, j); - if (!confirmed) - { - do - { - // Advance to next black pixel - j++; - } - while (j < maxJ && !image.get_Renamed(j, i)); - j--; // back up to that last white pixel - } - // Clear state to start looking again - currentState = 0; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - } - else - { - // No, shift counts back by two - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - } - } - else - { - stateCount[++currentState]++; - } - } - else - { - // Counting white pixels - stateCount[currentState]++; - } - } - } // for j=... - - if (foundPatternCross(stateCount)) - { - handlePossibleCenter(stateCount, i, maxJ); - } // end if foundPatternCross - } // for i=iSkip-1 ... - FinderPattern[][] patternInfo = selectBestPatterns(); - System.Collections.ArrayList result = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - for (int i = 0; i < patternInfo.Length; i++) - { - FinderPattern[] pattern = patternInfo[i]; - ResultPoint.orderBestPatterns(pattern); - result.Add(new FinderPatternInfo(pattern)); - } - - if ((result.Count == 0)) - { - return EMPTY_RESULT_ARRAY; - } + // Black pixel + if ((currentState & 1) == 1) // Counting white pixels + { + currentState++; + } + stateCount[currentState]++; + } // White pixel else { - FinderPatternInfo[] resultArray = new FinderPatternInfo[result.Count]; - for (int i = 0; i < result.Count; i++) + if ((currentState & 1) == 0) // Counting black pixels + { + if (currentState == 4) // A winner? { - resultArray[i] = (FinderPatternInfo) result[i]; + if (foundPatternCross(stateCount)) // Yes + { + bool confirmed = handlePossibleCenter(stateCount, i, j); + if (!confirmed) + { + do // Advance to next black pixel + { + j++; + } while (j < maxJ && !image.get(j, i)); + j--; // back up to that last white pixel + } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } // No, shift counts back by two + else + { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } } - return resultArray; + else + { + stateCount[++currentState]++; + } + } // Counting white pixels + else + { + stateCount[currentState]++; + } } + } // for j=... + + if (foundPatternCross(stateCount)) + { + handlePossibleCenter(stateCount, i, maxJ); + } // end if foundPatternCross + } // for i=iSkip-1 ... + FinderPattern[][] patternInfo = selectMutipleBestPatterns(); + List result = new List(); + foreach (FinderPattern[] pattern in patternInfo) + { + ResultPoint.orderBestPatterns(pattern); + result.Add(new FinderPatternInfo(pattern)); } + + if (result.Count == 0) + { + return EMPTY_RESULT_ARRAY; + } + else + { + return result.ToArray(); + } + } + } + } \ No newline at end of file diff --git a/csharp/oned/Code128Reader.cs b/csharp/oned/Code128Reader.cs index e7dc192f3..ac273a988 100755 --- a/csharp/oned/Code128Reader.cs +++ b/csharp/oned/Code128Reader.cs @@ -1,444 +1,407 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using BitArray = com.google.zxing.common.BitArray; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - ///

Decodes Code 128 barcodes.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Result = com.google.zxing.Result; + using ResultPoint = com.google.zxing.ResultPoint; + using BitArray = com.google.zxing.common.BitArray; + + + /// + ///

Decodes Code 128 barcodes.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class Code128Reader:OneDReader + public sealed class Code128Reader : OneDReader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'CODE_PATTERNS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] CODE_PATTERNS = new int[][]{new int[]{2, 1, 2, 2, 2, 2}, new int[]{2, 2, 2, 1, 2, 2}, new int[]{2, 2, 2, 2, 2, 1}, new int[]{1, 2, 1, 2, 2, 3}, new int[]{1, 2, 1, 3, 2, 2}, new int[]{1, 3, 1, 2, 2, 2}, new int[]{1, 2, 2, 2, 1, 3}, new int[]{1, 2, 2, 3, 1, 2}, new int[]{1, 3, 2, 2, 1, 2}, new int[]{2, 2, 1, 2, 1, 3}, new int[]{2, 2, 1, 3, 1, 2}, new int[]{2, 3, 1, 2, 1, 2}, new int[]{1, 1, 2, 2, 3, 2}, new int[]{1, 2, 2, 1, 3, 2}, new int[]{1, 2, 2, 2, 3, 1}, new int[]{1, 1, 3, 2, 2, 2}, new int[]{1, 2, 3, 1, 2, 2}, new int[]{1, 2, 3, 2, 2, 1}, new int[]{2, 2, 3, 2, 1, 1}, new int[]{2, 2, 1, 1, 3, 2}, new int[]{2, 2, 1, 2, 3, 1}, new int[]{2, 1, 3, 2, 1, 2}, new int[]{2, 2, 3, 1, 1, 2}, new int[]{3, 1, 2, 1, 3, 1}, new int[]{3, 1, 1, 2, 2, 2}, new int[]{3, 2, 1, 1, 2, 2}, new int[]{3, 2, 1, 2, 2, 1}, new int[]{3, 1, 2, 2, 1, 2}, new int[]{3, 2, 2, 1, 1, 2}, new int[]{3, 2, 2, 2, 1, 1}, new int[]{2, 1, 2, 1, 2, 3}, new int[]{2, 1, 2, 3, 2, 1}, new int[]{2, 3, 2, 1, 2, 1}, new int[]{1, 1, 1, 3, 2, 3}, new int[]{1, 3, 1, 1, 2, 3}, new int[]{1, 3, 1, 3, 2, 1}, new int[]{1, 1, 2, 3, 1, 3}, new int[]{1, 3, 2, 1, 1, 3}, new int[]{1, 3, 2, 3, 1, 1}, new int[]{2, 1, 1, 3, 1, 3}, new int[]{2, 3, 1, 1, 1, 3}, new int[]{2, 3, 1, 3, 1, 1}, new int[]{1, 1, 2, 1, 3, 3}, new int[]{1, 1, 2, 3, 3, 1}, new int[]{1, 3, 2, 1, 3, 1}, new int[]{1, 1, 3, 1, 2, 3}, new int[]{1, 1, 3, 3, 2, 1}, new int[]{1, 3, 3, 1, 2, 1}, new int[]{3, 1, 3, 1, 2, 1}, new int[]{2, 1, 1, 3, 3, 1}, new int[]{2, 3, 1, 1, 3, 1}, new int[]{2, 1, 3, 1, 1, 3}, new int[]{2, 1, 3, 3, 1, 1}, new int[]{2, 1, 3, 1, 3, 1}, new int[]{3, 1, 1, 1, 2, 3}, new int[]{3, 1, 1, 3, 2, 1}, new int[]{3, 3, 1, 1, 2, 1}, new int[]{3, 1, 2, 1, 1, 3}, new int[]{3, 1, 2, 3, 1, 1}, new int[]{3, 3, 2, 1, 1, 1}, new int[]{3, 1, 4, 1, 1, 1}, new int[]{2, 2, 1, 4, 1, 1}, new int[]{4, 3, 1, 1, 1, 1}, new int[]{1, 1, 1, 2, 2, 4}, new int[]{1, 1, 1, 4, 2, 2}, new int[]{1, 2, 1, 1, 2, 4}, new int[]{1, 2, 1, 4, 2, 1}, new int[]{1, 4, 1, 1, 2, 2}, new - int[]{1, 4, 1, 2, 2, 1}, new int[]{1, 1, 2, 2, 1, 4}, new int[]{1, 1, 2, 4, 1, 2}, new int[]{1, 2, 2, 1, 1, 4}, new int[]{1, 2, 2, 4, 1, 1}, new int[]{1, 4, 2, 1, 1, 2}, new int[]{1, 4, 2, 2, 1, 1}, new int[]{2, 4, 1, 2, 1, 1}, new int[]{2, 2, 1, 1, 1, 4}, new int[]{4, 1, 3, 1, 1, 1}, new int[]{2, 4, 1, 1, 1, 2}, new int[]{1, 3, 4, 1, 1, 1}, new int[]{1, 1, 1, 2, 4, 2}, new int[]{1, 2, 1, 1, 4, 2}, new int[]{1, 2, 1, 2, 4, 1}, new int[]{1, 1, 4, 2, 1, 2}, new int[]{1, 2, 4, 1, 1, 2}, new int[]{1, 2, 4, 2, 1, 1}, new int[]{4, 1, 1, 2, 1, 2}, new int[]{4, 2, 1, 1, 1, 2}, new int[]{4, 2, 1, 2, 1, 1}, new int[]{2, 1, 2, 1, 4, 1}, new int[]{2, 1, 4, 1, 2, 1}, new int[]{4, 1, 2, 1, 2, 1}, new int[]{1, 1, 1, 1, 4, 3}, new int[]{1, 1, 1, 3, 4, 1}, new int[]{1, 3, 1, 1, 4, 1}, new int[]{1, 1, 4, 1, 1, 3}, new int[]{1, 1, 4, 3, 1, 1}, new int[]{4, 1, 1, 1, 1, 3}, new int[]{4, 1, 1, 3, 1, 1}, new int[]{1, 1, 3, 1, 4, 1}, new int[]{1, 1, 4, 1, 3, 1}, new int[]{3, 1, 1, 1, 4, 1}, new int[]{4, 1, 1, 1, 3, 1}, new int[]{2, 1, 1, 4, 1, 2}, new int[]{2, 1, 1, 2, 1, 4}, new int[]{2, 1, 1, 2, 3, 2}, new int[]{2, 3, 3, 1, 1, 1, 2}}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_AVG_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f); - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_INDIVIDUAL_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); - - private const int CODE_SHIFT = 98; - - private const int CODE_CODE_C = 99; - private const int CODE_CODE_B = 100; - private const int CODE_CODE_A = 101; - - private const int CODE_FNC_1 = 102; - private const int CODE_FNC_2 = 97; - private const int CODE_FNC_3 = 96; - private const int CODE_FNC_4_A = 101; - private const int CODE_FNC_4_B = 100; - - private const int CODE_START_A = 103; - private const int CODE_START_B = 104; - private const int CODE_START_C = 105; - private const int CODE_STOP = 106; - - private static int[] findStartPattern(BitArray row) + + internal static readonly int[][] CODE_PATTERNS = {new int[] {2, 1, 2, 2, 2, 2}, new int[] {2, 2, 2, 1, 2, 2}, new int[] {2, 2, 2, 2, 2, 1}, new int[] {1, 2, 1, 2, 2, 3}, new int[] {1, 2, 1, 3, 2, 2}, new int[] {1, 3, 1, 2, 2, 2}, new int[] {1, 2, 2, 2, 1, 3}, new int[] {1, 2, 2, 3, 1, 2}, new int[] {1, 3, 2, 2, 1, 2}, new int[] {2, 2, 1, 2, 1, 3}, new int[] {2, 2, 1, 3, 1, 2}, new int[] {2, 3, 1, 2, 1, 2}, new int[] {1, 1, 2, 2, 3, 2}, new int[] {1, 2, 2, 1, 3, 2}, new int[] {1, 2, 2, 2, 3, 1}, new int[] {1, 1, 3, 2, 2, 2}, new int[] {1, 2, 3, 1, 2, 2}, new int[] {1, 2, 3, 2, 2, 1}, new int[] {2, 2, 3, 2, 1, 1}, new int[] {2, 2, 1, 1, 3, 2}, new int[] {2, 2, 1, 2, 3, 1}, new int[] {2, 1, 3, 2, 1, 2}, new int[] {2, 2, 3, 1, 1, 2}, new int[] {3, 1, 2, 1, 3, 1}, new int[] {3, 1, 1, 2, 2, 2}, new int[] {3, 2, 1, 1, 2, 2}, new int[] {3, 2, 1, 2, 2, 1}, new int[] {3, 1, 2, 2, 1, 2}, new int[] {3, 2, 2, 1, 1, 2}, new int[] {3, 2, 2, 2, 1, 1}, new int[] {2, 1, 2, 1, 2, 3}, new int[] {2, 1, 2, 3, 2, 1}, new int[] {2, 3, 2, 1, 2, 1}, new int[] {1, 1, 1, 3, 2, 3}, new int[] {1, 3, 1, 1, 2, 3}, new int[] {1, 3, 1, 3, 2, 1}, new int[] {1, 1, 2, 3, 1, 3}, new int[] {1, 3, 2, 1, 1, 3}, new int[] {1, 3, 2, 3, 1, 1}, new int[] {2, 1, 1, 3, 1, 3}, new int[] {2, 3, 1, 1, 1, 3}, new int[] {2, 3, 1, 3, 1, 1}, new int[] {1, 1, 2, 1, 3, 3}, new int[] {1, 1, 2, 3, 3, 1}, new int[] {1, 3, 2, 1, 3, 1}, new int[] {1, 1, 3, 1, 2, 3}, new int[] {1, 1, 3, 3, 2, 1}, new int[] {1, 3, 3, 1, 2, 1}, new int[] {3, 1, 3, 1, 2, 1}, new int[] {2, 1, 1, 3, 3, 1}, new int[] {2, 3, 1, 1, 3, 1}, new int[] {2, 1, 3, 1, 1, 3}, new int[] {2, 1, 3, 3, 1, 1}, new int[] {2, 1, 3, 1, 3, 1}, new int[] {3, 1, 1, 1, 2, 3}, new int[] {3, 1, 1, 3, 2, 1}, new int[] {3, 3, 1, 1, 2, 1}, new int[] {3, 1, 2, 1, 1, 3}, new int[] {3, 1, 2, 3, 1, 1}, new int[] {3, 3, 2, 1, 1, 1}, new int[] {3, 1, 4, 1, 1, 1}, new int[] {2, 2, 1, 4, 1, 1}, new int[] {4, 3, 1, 1, 1, 1}, new int[] {1, 1, 1, 2, 2, 4}, new int[] {1, 1, 1, 4, 2, 2}, new int[] {1, 2, 1, 1, 2, 4}, new int[] {1, 2, 1, 4, 2, 1}, new int[] {1, 4, 1, 1, 2, 2}, new int[] {1, 4, 1, 2, 2, 1}, new int[] {1, 1, 2, 2, 1, 4}, new int[] {1, 1, 2, 4, 1, 2}, new int[] {1, 2, 2, 1, 1, 4}, new int[] {1, 2, 2, 4, 1, 1}, new int[] {1, 4, 2, 1, 1, 2}, new int[] {1, 4, 2, 2, 1, 1}, new int[] {2, 4, 1, 2, 1, 1}, new int[] {2, 2, 1, 1, 1, 4}, new int[] {4, 1, 3, 1, 1, 1}, new int[] {2, 4, 1, 1, 1, 2}, new int[] {1, 3, 4, 1, 1, 1}, new int[] {1, 1, 1, 2, 4, 2}, new int[] {1, 2, 1, 1, 4, 2}, new int[] {1, 2, 1, 2, 4, 1}, new int[] {1, 1, 4, 2, 1, 2}, new int[] {1, 2, 4, 1, 1, 2}, new int[] {1, 2, 4, 2, 1, 1}, new int[] {4, 1, 1, 2, 1, 2}, new int[] {4, 2, 1, 1, 1, 2}, new int[] {4, 2, 1, 2, 1, 1}, new int[] {2, 1, 2, 1, 4, 1}, new int[] {2, 1, 4, 1, 2, 1}, new int[] {4, 1, 2, 1, 2, 1}, new int[] {1, 1, 1, 1, 4, 3}, new int[] {1, 1, 1, 3, 4, 1}, new int[] {1, 3, 1, 1, 4, 1}, new int[] {1, 1, 4, 1, 1, 3}, new int[] {1, 1, 4, 3, 1, 1}, new int[] {4, 1, 1, 1, 1, 3}, new int[] {4, 1, 1, 3, 1, 1}, new int[] {1, 1, 3, 1, 4, 1}, new int[] {1, 1, 4, 1, 3, 1}, new int[] {3, 1, 1, 1, 4, 1}, new int[] {4, 1, 1, 1, 3, 1}, new int[] {2, 1, 1, 4, 1, 2}, new int[] {2, 1, 1, 2, 1, 4}, new int[] {2, 1, 1, 2, 3, 2}, new int[] {2, 3, 3, 1, 1, 1, 2}}; + + private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f); + private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); + + private const int CODE_SHIFT = 98; + + private const int CODE_CODE_C = 99; + private const int CODE_CODE_B = 100; + private const int CODE_CODE_A = 101; + + private const int CODE_FNC_1 = 102; + private const int CODE_FNC_2 = 97; + private const int CODE_FNC_3 = 96; + private const int CODE_FNC_4_A = 101; + private const int CODE_FNC_4_B = 100; + + private const int CODE_START_A = 103; + private const int CODE_START_B = 104; + private const int CODE_START_C = 105; + private const int CODE_STOP = 106; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int[] findStartPattern(com.google.zxing.common.BitArray row) throws com.google.zxing.NotFoundException + private static int[] findStartPattern(BitArray row) + { + int width = row.Size; + int rowOffset = row.getNextSet(0); + + int counterPosition = 0; + int[] counters = new int[6]; + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = counters.Length; + + for (int i = rowOffset; i < width; i++) { - int width = row.Size; - int rowOffset = 0; - while (rowOffset < width) + if (row.get(i) ^ isWhite) + { + counters[counterPosition]++; + } + else + { + if (counterPosition == patternLength - 1) { - if (row.get_Renamed(rowOffset)) - { - break; - } - rowOffset++; - } - - int counterPosition = 0; - int[] counters = new int[6]; - int patternStart = rowOffset; - bool isWhite = false; - int patternLength = counters.Length; - - for (int i = rowOffset; i < width; i++) - { - bool pixel = row.get_Renamed(i); - if (pixel ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - int bestVariance = MAX_AVG_VARIANCE; - int bestMatch = - 1; - for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) - { - int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) - { - bestVariance = variance; - bestMatch = startCode; - } - } - if (bestMatch >= 0) - { - // Look for whitespace before start pattern, >= 50% of width of start pattern - if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) - { - return new int[]{patternStart, i, bestMatch}; - } - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) - { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - throw ReaderException.Instance; - } - - private static int decodeCode(BitArray row, int[] counters, int rowOffset) - { - recordPattern(row, rowOffset, counters); - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - int bestMatch = - 1; - for (int d = 0; d < CODE_PATTERNS.Length; d++) - { - int[] pattern = CODE_PATTERNS[d]; - int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + int bestVariance = MAX_AVG_VARIANCE; + int bestMatch = -1; + for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) + { + int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); if (variance < bestVariance) { - bestVariance = variance; - bestMatch = d; + bestVariance = variance; + bestMatch = startCode; } - } - // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. - if (bestMatch >= 0) - { - return bestMatch; + } + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (bestMatch >= 0 && row.isRange(Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) + { + return new int[]{patternStart, i, bestMatch}; + } + patternStart += counters[0] + counters[1]; + Array.Copy(counters, 2, counters, 0, patternLength - 2); + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } else { - throw ReaderException.Instance; + counterPosition++; } + counters[counterPosition] = 1; + isWhite = !isWhite; + } } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + throw NotFoundException.NotFoundInstance; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int decodeCode(com.google.zxing.common.BitArray row, int[] counters, int rowOffset) throws com.google.zxing.NotFoundException + private static int decodeCode(BitArray row, int[] counters, int rowOffset) + { + recordPattern(row, rowOffset, counters); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + for (int d = 0; d < CODE_PATTERNS.Length; d++) { - - int[] startPatternInfo = findStartPattern(row); - int startCode = startPatternInfo[2]; - int codeSet; - switch (startCode) - { - - case CODE_START_A: - codeSet = CODE_CODE_A; - break; - - case CODE_START_B: - codeSet = CODE_CODE_B; - break; - - case CODE_START_C: - codeSet = CODE_CODE_C; - break; - - default: - throw ReaderException.Instance; - - } - - bool done = false; - bool isNextShifted = false; - - System.Text.StringBuilder result = new System.Text.StringBuilder(20); - int lastStart = startPatternInfo[0]; - int nextStart = startPatternInfo[1]; - int[] counters = new int[6]; - - int lastCode = 0; - int code = 0; - int checksumTotal = startCode; - int multiplier = 0; - bool lastCharacterWasPrintable = true; - - while (!done) - { - - bool unshift = isNextShifted; - isNextShifted = false; - - // Save off last code - lastCode = code; - - // Decode another code from image - code = decodeCode(row, counters, nextStart); - - // Remember whether the last code was printable or not (excluding CODE_STOP) + int[] pattern = CODE_PATTERNS[d]; + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) + { + bestVariance = variance; + bestMatch = d; + } + } + // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. + if (bestMatch >= 0) + { + return bestMatch; + } + else + { + throw NotFoundException.NotFoundInstance; + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + + int[] startPatternInfo = findStartPattern(row); + int startCode = startPatternInfo[2]; + int codeSet; + switch (startCode) + { + case CODE_START_A: + codeSet = CODE_CODE_A; + break; + case CODE_START_B: + codeSet = CODE_CODE_B; + break; + case CODE_START_C: + codeSet = CODE_CODE_C; + break; + default: + throw FormatException.FormatInstance; + } + + bool done = false; + bool isNextShifted = false; + + StringBuilder result = new StringBuilder(20); + IList rawCodes = new List(20); + + int lastStart = startPatternInfo[0]; + int nextStart = startPatternInfo[1]; + int[] counters = new int[6]; + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + bool lastCharacterWasPrintable = true; + + while (!done) + { + + bool unshift = isNextShifted; + isNextShifted = false; + + // Save off last code + lastCode = code; + + // Decode another code from image + code = decodeCode(row, counters, nextStart); + + rawCodes.Add((sbyte) code); + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if (code != CODE_STOP) + { + lastCharacterWasPrintable = true; + } + + // Add to checksum computation (if not CODE_STOP of course) + if (code != CODE_STOP) + { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + foreach (int counter in counters) + { + nextStart += counter; + } + + // Take care of illegal start codes + switch (code) + { + case CODE_START_A: + case CODE_START_B: + case CODE_START_C: + throw FormatException.FormatInstance; + } + + switch (codeSet) + { + + case CODE_CODE_A: + if (code < 64) + { + result.Append((char)(' ' + code)); + } + else if (code < 96) + { + result.Append((char)(code - 64)); + } + else + { + // Don't let CODE_STOP, which always appears, affect whether whether we think the last + // code was printable or not. if (code != CODE_STOP) { - lastCharacterWasPrintable = true; + lastCharacterWasPrintable = false; } - - // Add to checksum computation (if not CODE_STOP of course) - if (code != CODE_STOP) - { - multiplier++; - checksumTotal += multiplier * code; - } - - // Advance to where the next code will to start - lastStart = nextStart; - for (int i = 0; i < counters.Length; i++) - { - nextStart += counters[i]; - } - - // Take care of illegal start codes switch (code) { - - case CODE_START_A: - case CODE_START_B: - case CODE_START_C: - throw ReaderException.Instance; - } - - switch (codeSet) - { - - - case CODE_CODE_A: - if (code < 64) - { - result.Append((char) (' ' + code)); - } - else if (code < 96) - { - result.Append((char) (code - 64)); - } - else - { - // Don't let CODE_STOP, which always appears, affect whether whether we think the last - // code was printable or not. - if (code != CODE_STOP) - { - lastCharacterWasPrintable = false; - } - switch (code) - { - - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_A: - // do nothing? - break; - - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_B; - break; - - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - - case CODE_STOP: - done = true; - break; - } - } - break; - - case CODE_CODE_B: - if (code < 96) - { - result.Append((char) (' ' + code)); - } - else - { - if (code != CODE_STOP) - { - lastCharacterWasPrintable = false; - } - switch (code) - { - - case CODE_FNC_1: - case CODE_FNC_2: - case CODE_FNC_3: - case CODE_FNC_4_B: - // do nothing? - break; - - case CODE_SHIFT: - isNextShifted = true; - codeSet = CODE_CODE_C; - break; - - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - - case CODE_CODE_C: - codeSet = CODE_CODE_C; - break; - - case CODE_STOP: - done = true; - break; - } - } - break; - - case CODE_CODE_C: - if (code < 100) - { - if (code < 10) - { - result.Append('0'); - } - result.Append(code); - } - else - { - if (code != CODE_STOP) - { - lastCharacterWasPrintable = false; - } - switch (code) - { - - case CODE_FNC_1: - // do nothing? - break; - - case CODE_CODE_A: - codeSet = CODE_CODE_A; - break; - - case CODE_CODE_B: - codeSet = CODE_CODE_B; - break; - - case CODE_STOP: - done = true; - break; - } - } - break; - } - - // Unshift back to another code set if we were shifted - if (unshift) - { - switch (codeSet) - { - - case CODE_CODE_A: - codeSet = CODE_CODE_C; - break; - - case CODE_CODE_B: - codeSet = CODE_CODE_A; - break; - - case CODE_CODE_C: - codeSet = CODE_CODE_B; - break; - } + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_A: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_B; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; } - } - - // Check for ample whitespace following pattern, but, to do this we first need to remember that - // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left - // to read off. Would be slightly better to properly read. Here we just skip it: - int width = row.Size; - while (nextStart < width && row.get_Renamed(nextStart)) - { - nextStart++; - } - if (!row.isRange(nextStart, System.Math.Min(width, nextStart + (nextStart - lastStart) / 2), false)) - { - throw ReaderException.Instance; - } - - // Pull out from sum the value of the penultimate check code - checksumTotal -= multiplier * lastCode; - // lastCode is the checksum then: - if (checksumTotal % 103 != lastCode) - { - throw ReaderException.Instance; - } - - // Need to pull out the check digits from string - int resultLength = result.Length; - // Only bother if the result had at least one character, and if the checksum digit happened to - // be a printable character. If it was just interpreted as a control code, nothing to remove. - if (resultLength > 0 && lastCharacterWasPrintable) - { - if (codeSet == CODE_CODE_C) + } + break; + case CODE_CODE_B: + if (code < 96) + { + result.Append((char)(' ' + code)); + } + else + { + if (code != CODE_STOP) { - result.Remove(resultLength - 2, resultLength - (resultLength - 2)); + lastCharacterWasPrintable = false; } - else + switch (code) { - result.Remove(resultLength - 1, resultLength - (resultLength - 1)); + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_B: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_A; + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; } - } - - System.String resultString = result.ToString(); - - if (resultString.Length == 0) - { - // Almost surely a false positive - throw ReaderException.Instance; - } - - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float right = (float) (nextStart + lastStart) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_128); + } + break; + case CODE_CODE_C: + if (code < 100) + { + if (code < 10) + { + result.Append('0'); + } + result.Append(code); + } + else + { + if (code != CODE_STOP) + { + lastCharacterWasPrintable = false; + } + switch (code) + { + case CODE_FNC_1: + // do nothing? + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) + { + codeSet = codeSet == CODE_CODE_A ? CODE_CODE_B : CODE_CODE_A; + } + } + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + nextStart = row.getNextUnset(nextStart); + if (!row.isRange(nextStart, Math.Min(row.Size, nextStart + (nextStart - lastStart) / 2), false)) + { + throw NotFoundException.NotFoundInstance; + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) + { + throw ChecksumException.ChecksumInstance; + } + + // Need to pull out the check digits from string + int resultLength = result.Length; + if (resultLength == 0) + { + // false positive + throw NotFoundException.NotFoundInstance; + } + + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) + { + if (codeSet == CODE_CODE_C) + { + result.Remove(resultLength - 2, 2); + } + else + { + result.Remove(resultLength - 1, 1); + } + } + + float left = (float)(startPatternInfo[1] + startPatternInfo[0]) / 2.0f; + float right = (float)(nextStart + lastStart) / 2.0f; + + int rawCodesSize = rawCodes.Count; + sbyte[] rawBytes = new sbyte[rawCodesSize]; + for (int i = 0; i < rawCodesSize; i++) + { + rawBytes[i] = rawCodes[i]; + } + + return new Result(result.ToString(), rawBytes, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_128); + + } + } + } \ No newline at end of file diff --git a/csharp/oned/Code39Reader.cs b/csharp/oned/Code39Reader.cs index 3e1fc99f5..62d9bae30 100755 --- a/csharp/oned/Code39Reader.cs +++ b/csharp/oned/Code39Reader.cs @@ -1,392 +1,379 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using BitArray = com.google.zxing.common.BitArray; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - ///

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Result = com.google.zxing.Result; + using ResultPoint = com.google.zxing.ResultPoint; + using BitArray = com.google.zxing.common.BitArray; + using com.google.zxing.common; + + + /// + ///

Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet.

/// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class Code39Reader:OneDReader + /// @author Sean Owen
+ /// + public sealed class Code39Reader : OneDReader { - - internal const System.String ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; - //UPGRADE_NOTE: Final was removed from the declaration of 'ALPHABET '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] ALPHABET = ALPHABET_STRING.ToCharArray(); - - /// These represent the encodings of characters, as patterns of wide and narrow bars. - /// The 9 least-significant bits of each int correspond to the pattern of wide and narrow, - /// with 1s representing "wide" and 0s representing narrow. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'CHARACTER_ENCODINGS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] CHARACTER_ENCODINGS = new int[]{0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'ASTERISK_ENCODING '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int ASTERISK_ENCODING = CHARACTER_ENCODINGS[39]; - - //UPGRADE_NOTE: Final was removed from the declaration of 'usingCheckDigit '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private bool usingCheckDigit; - //UPGRADE_NOTE: Final was removed from the declaration of 'extendedMode '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private bool extendedMode; - - /// Creates a reader that assumes all encoded data is data, and does not treat the final - /// character as a check digit. It will not decoded "extended Code 39" sequences. - /// - public Code39Reader() + + internal const string ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; + private static readonly char[] ALPHABET = ALPHABET_STRING.ToCharArray(); + + /// + /// These represent the encodings of characters, as patterns of wide and narrow bars. + /// The 9 least-significant bits of each int correspond to the pattern of wide and narrow, + /// with 1s representing "wide" and 0s representing narrow. + /// + internal static readonly int[] CHARACTER_ENCODINGS = {0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A}; + + private static readonly int ASTERISK_ENCODING = CHARACTER_ENCODINGS[39]; + + private readonly bool usingCheckDigit; + private readonly bool extendedMode; + private readonly StringBuilder decodeRowResult; + private readonly int[] counters; + + /// + /// Creates a reader that assumes all encoded data is data, and does not treat the final + /// character as a check digit. It will not decoded "extended Code 39" sequences. + /// + public Code39Reader() : this(false) + { + } + + /// + /// Creates a reader that can be configured to check the last character as a check digit. + /// It will not decoded "extended Code 39" sequences. + /// + /// if true, treat the last data character as a check digit, not + /// data, and verify that the checksum passes. + public Code39Reader(bool usingCheckDigit) : this(usingCheckDigit, false) + { + } + + /// + /// Creates a reader that can be configured to check the last character as a check digit, + /// or optionally attempt to decode "extended Code 39" sequences that are used to encode + /// the full ASCII character set. + /// + /// if true, treat the last data character as a check digit, not + /// data, and verify that the checksum passes. + /// if true, will attempt to decode extended Code 39 sequences in the + /// text. + public Code39Reader(bool usingCheckDigit, bool extendedMode) + { + this.usingCheckDigit = usingCheckDigit; + this.extendedMode = extendedMode; + decodeRowResult = new StringBuilder(20); + counters = new int[9]; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + + int[] theCounters = counters; + theCounters.Fill(0); + StringBuilder result = decodeRowResult; + result.Length = 0; + + int[] start = findAsteriskPattern(row, theCounters); + // Read off white space + int nextStart = row.getNextSet(start[1]); + int end = row.Size; + + char decodedChar; + int lastStart; + do { - usingCheckDigit = false; - extendedMode = false; + recordPattern(row, nextStart, theCounters); + int pattern = toNarrowWidePattern(theCounters); + if (pattern < 0) + { + throw NotFoundException.NotFoundInstance; + } + decodedChar = patternToChar(pattern); + result.Append(decodedChar); + lastStart = nextStart; + foreach (int counter in theCounters) + { + nextStart += counter; + } + // Read off white space + nextStart = row.getNextSet(nextStart); + } while (decodedChar != '*'); + result.Length = result.Length - 1; // remove asterisk + + // Look for whitespace after pattern: + int lastPatternSize = 0; + foreach (int counter in theCounters) + { + lastPatternSize += counter; } - - /// Creates a reader that can be configured to check the last character as a check digit. - /// It will not decoded "extended Code 39" sequences. - /// - /// - /// if true, treat the last data character as a check digit, not - /// data, and verify that the checksum passes. - /// - public Code39Reader(bool usingCheckDigit) + int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; + // If 50% of last pattern size, following last pattern, is not whitespace, fail + // (but if it's whitespace to the very end of the image, that's OK) + if (nextStart != end && (whiteSpaceAfterEnd >> 1) < lastPatternSize) { - this.usingCheckDigit = usingCheckDigit; - this.extendedMode = false; + throw NotFoundException.NotFoundInstance; } - - /// Creates a reader that can be configured to check the last character as a check digit, - /// or optionally attempt to decode "extended Code 39" sequences that are used to encode - /// the full ASCII character set. - /// - /// - /// if true, treat the last data character as a check digit, not - /// data, and verify that the checksum passes. - /// - /// if true, will attempt to decode extended Code 39 sequences in the - /// text. - /// - public Code39Reader(bool usingCheckDigit, bool extendedMode) + + if (usingCheckDigit) { - this.usingCheckDigit = usingCheckDigit; - this.extendedMode = extendedMode; + int max = result.Length - 1; + int total = 0; + for (int i = 0; i < max; i++) + { + total += ALPHABET_STRING.IndexOf(decodeRowResult[i]); + } + if (result[max] != ALPHABET[total % 43]) + { + throw ChecksumException.ChecksumInstance; + } + result.Length = max; } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + + if (result.Length == 0) { - - int[] start = findAsteriskPattern(row); - int nextStart = start[1]; - int end = row.Size; - - // Read off white space - while (nextStart < end && !row.get_Renamed(nextStart)) - { - nextStart++; - } - - System.Text.StringBuilder result = new System.Text.StringBuilder(20); - int[] counters = new int[9]; - char decodedChar; - int lastStart; - do - { - recordPattern(row, nextStart, counters); - int pattern = toNarrowWidePattern(counters); - if (pattern < 0) - { - throw ReaderException.Instance; - } - decodedChar = patternToChar(pattern); - result.Append(decodedChar); - lastStart = nextStart; - for (int i = 0; i < counters.Length; i++) - { - nextStart += counters[i]; - } - // Read off white space - while (nextStart < end && !row.get_Renamed(nextStart)) - { - nextStart++; - } - } - while (decodedChar != '*'); - result.Remove(result.Length - 1, 1); // remove asterisk - - // Look for whitespace after pattern: - int lastPatternSize = 0; - for (int i = 0; i < counters.Length; i++) - { - lastPatternSize += counters[i]; - } - int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; - // If 50% of last pattern size, following last pattern, is not whitespace, fail - // (but if it's whitespace to the very end of the image, that's OK) - if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) - { - throw ReaderException.Instance; - } - - if (usingCheckDigit) - { - int max = result.Length - 1; - int total = 0; - for (int i = 0; i < max; i++) - { - total += ALPHABET_STRING.IndexOf((System.Char) result[i]); - } - if (total % 43 != ALPHABET_STRING.IndexOf((System.Char) result[max])) - { - throw ReaderException.Instance; - } - result.Remove(max, 1); - } - - System.String resultString = result.ToString(); - if (extendedMode) - { - resultString = decodeExtended(resultString); - } - - if (resultString.Length == 0) - { - // Almost surely a false positive - throw ReaderException.Instance; - } - - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float left = (float) (start[1] + start[0]) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float right = (float) (nextStart + lastStart) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_39); + // false positive + throw NotFoundException.NotFoundInstance; } - - private static int[] findAsteriskPattern(BitArray row) + + string resultString; + if (extendedMode) { - int width = row.Size; - int rowOffset = 0; - while (rowOffset < width) + resultString = decodeExtended(result.ToString()); + } + else + { + resultString = result.ToString(); + } + + float left = (float)(start[1] + start[0]) / 2.0f; + float right = (float)(nextStart + lastStart) / 2.0f; + return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat.CODE_39); + + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int[] findAsteriskPattern(com.google.zxing.common.BitArray row, int[] counters) throws com.google.zxing.NotFoundException + private static int[] findAsteriskPattern(BitArray row, int[] counters) + { + int width = row.Size; + int rowOffset = row.getNextSet(0); + + int counterPosition = 0; + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = counters.Length; + + for (int i = rowOffset; i < width; i++) + { + if (row.get(i) ^ isWhite) + { + counters[counterPosition]++; + } + else + { + if (counterPosition == patternLength - 1) { - if (row.get_Renamed(rowOffset)) - { - break; - } - rowOffset++; + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (toNarrowWidePattern(counters) == ASTERISK_ENCODING && row.isRange(Math.Max(0, patternStart - ((i - patternStart) >> 1)), patternStart, false)) + { + return new int[]{patternStart, i}; + } + patternStart += counters[0] + counters[1]; + Array.Copy(counters, 2, counters, 0, patternLength - 2); + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } - - int counterPosition = 0; - int[] counters = new int[9]; - int patternStart = rowOffset; - bool isWhite = false; - int patternLength = counters.Length; - - for (int i = rowOffset; i < width; i++) + else { - bool pixel = row.get_Renamed(i); - if (pixel ^ isWhite) + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw NotFoundException.NotFoundInstance; + } + + // For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions + // per image when using some of our blackbox images. + private static int toNarrowWidePattern(int[] counters) + { + int numCounters = counters.Length; + int maxNarrowCounter = 0; + int wideCounters; + do + { + int minCounter = int.MaxValue; + foreach (int counter in counters) + { + if (counter < minCounter && counter > maxNarrowCounter) + { + minCounter = counter; + } + } + maxNarrowCounter = minCounter; + wideCounters = 0; + int totalWideCountersWidth = 0; + int pattern = 0; + for (int i = 0; i < numCounters; i++) + { + int counter = counters[i]; + if (counter > maxNarrowCounter) + { + pattern |= 1 << (numCounters - 1 - i); + wideCounters++; + totalWideCountersWidth += counter; + } + } + if (wideCounters == 3) + { + // Found 3 wide counters, but are they close enough in width? + // We can perform a cheap, conservative check to see if any individual + // counter is more than 1.5 times the average: + for (int i = 0; i < numCounters && wideCounters > 0; i++) + { + int counter = counters[i]; + if (counter > maxNarrowCounter) + { + wideCounters--; + // totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average + if ((counter << 1) >= totalWideCountersWidth) { - counters[counterPosition]++; + return -1; + } + } + } + return pattern; + } + } while (wideCounters > 3); + return -1; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static char patternToChar(int pattern) throws com.google.zxing.NotFoundException + private static char patternToChar(int pattern) + { + for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) + { + if (CHARACTER_ENCODINGS[i] == pattern) + { + return ALPHABET[i]; + } + } + throw NotFoundException.NotFoundInstance; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static String decodeExtended(CharSequence encoded) throws com.google.zxing.FormatException + private static string decodeExtended(string encoded) + { + int length = encoded.Length; + StringBuilder decoded = new StringBuilder(length); + for (int i = 0; i < length; i++) + { + char c = encoded[i]; + if (c == '+' || c == '$' || c == '%' || c == '/') + { + char next = encoded[i + 1]; + char decodedChar = '\0'; + switch (c) + { + case '+': + // +A to +Z map to a to z + if (next >= 'A' && next <= 'Z') + { + decodedChar = (char)(next + 32); } else { - if (counterPosition == patternLength - 1) - { - if (toNarrowWidePattern(counters) == ASTERISK_ENCODING) - { - // Look for whitespace before start pattern, >= 50% of width of start pattern - if (row.isRange(System.Math.Max(0, patternStart - (i - patternStart) / 2), patternStart, false)) - { - return new int[]{patternStart, i}; - } - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) - { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; + throw FormatException.FormatInstance; } - } - throw ReaderException.Instance; - } - - // For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions - // per image when using some of our blackbox images. - private static int toNarrowWidePattern(int[] counters) - { - int numCounters = counters.Length; - int maxNarrowCounter = 0; - int wideCounters; - do - { - int minCounter = System.Int32.MaxValue; - for (int i = 0; i < numCounters; i++) + break; + case '$': + // $A to $Z map to control codes SH to SB + if (next >= 'A' && next <= 'Z') { - int counter = counters[i]; - if (counter < minCounter && counter > maxNarrowCounter) - { - minCounter = counter; - } - } - maxNarrowCounter = minCounter; - wideCounters = 0; - int totalWideCountersWidth = 0; - int pattern = 0; - for (int i = 0; i < numCounters; i++) - { - int counter = counters[i]; - if (counters[i] > maxNarrowCounter) - { - pattern |= 1 << (numCounters - 1 - i); - wideCounters++; - totalWideCountersWidth += counter; - } - } - if (wideCounters == 3) - { - // Found 3 wide counters, but are they close enough in width? - // We can perform a cheap, conservative check to see if any individual - // counter is more than 1.5 times the average: - for (int i = 0; i < numCounters && wideCounters > 0; i++) - { - int counter = counters[i]; - if (counters[i] > maxNarrowCounter) - { - wideCounters--; - // totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average - if ((counter << 1) >= totalWideCountersWidth) - { - return - 1; - } - } - } - return pattern; - } - } - while (wideCounters > 3); - return - 1; - } - - private static char patternToChar(int pattern) - { - for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) - { - if (CHARACTER_ENCODINGS[i] == pattern) - { - return ALPHABET[i]; - } - } - throw ReaderException.Instance; - } - - private static System.String decodeExtended(System.String encoded) - { - int length = encoded.Length; - System.Text.StringBuilder decoded = new System.Text.StringBuilder(length); - for (int i = 0; i < length; i++) - { - char c = encoded[i]; - if (c == '+' || c == '$' || c == '%' || c == '/') - { - char next = encoded[i + 1]; - char decodedChar = '\x0000'; - switch (c) - { - - case '+': - // +A to +Z map to a to z - if (next >= 'A' && next <= 'Z') - { - decodedChar = (char) (next + 32); - } - else - { - throw ReaderException.Instance; - } - break; - - case '$': - // $A to $Z map to control codes SH to SB - if (next >= 'A' && next <= 'Z') - { - decodedChar = (char) (next - 64); - } - else - { - throw ReaderException.Instance; - } - break; - - case '%': - // %A to %E map to control codes ESC to US - if (next >= 'A' && next <= 'E') - { - decodedChar = (char) (next - 38); - } - else if (next >= 'F' && next <= 'W') - { - decodedChar = (char) (next - 11); - } - else - { - throw ReaderException.Instance; - } - break; - - case '/': - // /A to /O map to ! to , and /Z maps to : - if (next >= 'A' && next <= 'O') - { - decodedChar = (char) (next - 32); - } - else if (next == 'Z') - { - decodedChar = ':'; - } - else - { - throw ReaderException.Instance; - } - break; - } - decoded.Append(decodedChar); - // bump up i again since we read two characters - i++; + decodedChar = (char)(next - 64); } else { - decoded.Append(c); + throw FormatException.FormatInstance; } + break; + case '%': + // %A to %E map to control codes ESC to US + if (next >= 'A' && next <= 'E') + { + decodedChar = (char)(next - 38); + } + else if (next >= 'F' && next <= 'W') + { + decodedChar = (char)(next - 11); + } + else + { + throw FormatException.FormatInstance; + } + break; + case '/': + // /A to /O map to ! to , and /Z maps to : + if (next >= 'A' && next <= 'O') + { + decodedChar = (char)(next - 32); + } + else if (next == 'Z') + { + decodedChar = ':'; + } + else + { + throw FormatException.FormatInstance; + } + break; } - return decoded.ToString(); + decoded.Append(decodedChar); + // bump up i again since we read two characters + i++; + } + else + { + decoded.Append(c); + } } + return decoded.ToString(); + } + } -} + +} \ No newline at end of file diff --git a/csharp/oned/Code39Writer.cs b/csharp/oned/Code39Writer.cs index 478033490..01dec3db2 100644 --- a/csharp/oned/Code39Writer.cs +++ b/csharp/oned/Code39Writer.cs @@ -1,80 +1,94 @@ -/* - * Copyright 2011 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -using System; -using System.Collections; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -namespace com.google.zxing.oned -{ - ///

Implements decoding of the EAN-13 format.

- /// - ///
- /// erik.barbara@gmail.com (Erik Barbara) - /// - /// em@nerd.ocracy.org (Emanuele Aina) - Ported from ZXING Java Source - /// - public sealed class Code39Writer:UPCEANWriter - { - public override ByteMatrix encode(string contents, BarcodeFormat format, int width, int height, Hashtable hints) { - if (format != BarcodeFormat.CODE_39) { - throw new ArgumentException("Can only encode CODE_39, but got " + format); - } - return base.encode(contents, format, width, height, hints); - } - - public override sbyte[] encode(string contents) { - int length = contents.Length; - if (length > 80) { - throw new ArgumentException("Requested contents should be less than 80 digits long, but got " + length); - } - - int[] widths = new int[9]; - int codeWidth = 24 + 1 + length; - for (int i = 0; i < length; i++) { - int indexInString = Code39Reader.ALPHABET_STRING.IndexOf(contents[i]); - toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); - for(int j = 0; j < widths.Length; j++) { - codeWidth += widths[j]; - } - } - sbyte[] result = new sbyte[codeWidth]; - toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); - int pos = appendPattern(result, 0, widths, 1); - int[] narrowWhite = {1}; - pos += appendPattern(result, pos, narrowWhite, 0); - //append next character to bytematrix - for(int i = length-1; i >= 0; i--) { - int indexInString = Code39Reader.ALPHABET_STRING.IndexOf(contents[i]); - toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); - pos += appendPattern(result, pos, widths, 1); - pos += appendPattern(result, pos, narrowWhite, 0); - } - toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); - pos += appendPattern(result, pos, widths, 1); - return result; - } - - private static void toIntArray(int a, int[] toReturn) { - for (int i = 0; i < 9; i++) { - int temp = a & (1 << i); - toReturn[i] = (temp == 0) ? 1 : 2; - } - } - } -} +using System.Collections.Generic; + +/* + * Copyright 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace com.google.zxing.oned +{ + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using EncodeHintType = com.google.zxing.EncodeHintType; + using WriterException = com.google.zxing.WriterException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + + /// + /// This object renders a CODE39 code as a . + /// + /// @author erik.barbara@gmail.com (Erik Barbara) + /// + public sealed class Code39Writer : OneDimensionalCodeWriter + { + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, com.google.zxing.BarcodeFormat format, int width, int height, java.util.Map hints) throws com.google.zxing.WriterException + public override BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints) + { + if (format != BarcodeFormat.CODE_39) + { + throw new System.ArgumentException("Can only encode CODE_39, but got " + format); + } + return base.encode(contents, format, width, height, hints); + } + + public override bool[] encode(string contents) + { + int length = contents.Length; + if (length > 80) + { + throw new System.ArgumentException("Requested contents should be less than 80 digits long, but got " + length); + } + + int[] widths = new int[9]; + int codeWidth = 24 + 1 + length; + for (int i = 0; i < length; i++) + { + int indexInString = Code39Reader.ALPHABET_STRING.IndexOf(contents[i]); + toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); + foreach (int width in widths) + { + codeWidth += width; + } + } + bool[] result = new bool[codeWidth]; + toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); + int pos = appendPattern(result, 0, widths, true); + int[] narrowWhite = {1}; + pos += appendPattern(result, pos, narrowWhite, false); + //append next character to bytematrix + for (int i = length - 1; i >= 0; i--) + { + int indexInString = Code39Reader.ALPHABET_STRING.IndexOf(contents[i]); + toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); + pos += appendPattern(result, pos, widths, true); + pos += appendPattern(result, pos, narrowWhite, false); + } + toIntArray(Code39Reader.CHARACTER_ENCODINGS[39], widths); + pos += appendPattern(result, pos, widths, true); + return result; + } + + private static void toIntArray(int a, int[] toReturn) + { + for (int i = 0; i < 9; i++) + { + int temp = a & (1 << i); + toReturn[i] = temp == 0 ? 1 : 2; + } + } + + } +} \ No newline at end of file diff --git a/csharp/oned/EAN13Reader.cs b/csharp/oned/EAN13Reader.cs index b8c2df49d..4b42278c5 100755 --- a/csharp/oned/EAN13Reader.cs +++ b/csharp/oned/EAN13Reader.cs @@ -1,153 +1,155 @@ +using System.Collections; +using System.Text; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - ///

Implements decoding of the EAN-13 format.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using NotFoundException = com.google.zxing.NotFoundException; + using BitArray = com.google.zxing.common.BitArray; + + /// + ///

Implements decoding of the EAN-13 format.

/// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen + /// @author alasdair@google.com (Alasdair Mackintosh) ///
- /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// alasdair@google.com (Alasdair Mackintosh) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EAN13Reader:UPCEANReader + public sealed class EAN13Reader : UPCEANReader { - override internal BarcodeFormat BarcodeFormat + + // For an EAN-13 barcode, the first digit is represented by the parities used + // to encode the next six digits, according to the table below. For example, + // if the barcode is 5 123456 789012 then the value of the first digit is + // signified by using odd for '1', even for '2', even for '3', odd for '4', + // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13 + // + // Parity of next 6 digits + // Digit 0 1 2 3 4 5 + // 0 Odd Odd Odd Odd Odd Odd + // 1 Odd Odd Even Odd Even Even + // 2 Odd Odd Even Even Odd Even + // 3 Odd Odd Even Even Even Odd + // 4 Odd Even Odd Odd Even Even + // 5 Odd Even Even Odd Odd Even + // 6 Odd Even Even Even Odd Odd + // 7 Odd Even Odd Even Odd Even + // 8 Odd Even Odd Even Even Odd + // 9 Odd Even Even Odd Even Odd + // + // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence + // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. + // + // The encoding is represented by the following array, which is a bit pattern + // using Odd = 0 and Even = 1. For example, 5 is represented by: + // + // Odd Even Even Odd Odd Even + // in binary: + // 0 1 1 0 0 1 == 0x19 + // + internal static readonly int[] FIRST_DIGIT_ENCODINGS = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}; + + private readonly int[] decodeMiddleCounters; + + public EAN13Reader() + { + decodeMiddleCounters = new int[4]; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected int decodeMiddle(com.google.zxing.common.BitArray row, int[] startRange, StringBuilder resultString) throws com.google.zxing.NotFoundException + protected internal override int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString) + { + int[] counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + int end = row.Size; + int rowOffset = startRange[1]; + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { - get - { - return BarcodeFormat.EAN_13; - } - + int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); + resultString.Append((char)('0' + bestMatch % 10)); + foreach (int counter in counters) + { + rowOffset += counter; + } + if (bestMatch >= 10) + { + lgPatternFound |= 1 << (5 - x); + } } - - // For an EAN-13 barcode, the first digit is represented by the parities used - // to encode the next six digits, according to the table below. For example, - // if the barcode is 5 123456 789012 then the value of the first digit is - // signified by using odd for '1', even for '2', even for '3', odd for '4', - // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13 - // - // Parity of next 6 digits - // Digit 0 1 2 3 4 5 - // 0 Odd Odd Odd Odd Odd Odd - // 1 Odd Odd Even Odd Even Even - // 2 Odd Odd Even Even Odd Even - // 3 Odd Odd Even Even Even Odd - // 4 Odd Even Odd Odd Even Even - // 5 Odd Even Even Odd Odd Even - // 6 Odd Even Even Even Odd Odd - // 7 Odd Even Odd Even Odd Even - // 8 Odd Even Odd Even Even Odd - // 9 Odd Even Even Odd Even Odd - // - // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence - // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. - // - // The encoding is represented by the following array, which is a bit pattern - // using Odd = 0 and Even = 1. For example, 5 is represented by: - // - // Odd Even Even Odd Odd Even - // in binary: - // 0 1 1 0 0 1 == 0x19 - // - //UPGRADE_NOTE: Final was removed from the declaration of 'FIRST_DIGIT_ENCODINGS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] FIRST_DIGIT_ENCODINGS = new int[]{0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decodeMiddleCounters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] decodeMiddleCounters; - - public EAN13Reader() + + determineFirstDigit(resultString, lgPatternFound); + + int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); + rowOffset = middleRange[1]; + + for (int x = 0; x < 6 && rowOffset < end; x++) { - decodeMiddleCounters = new int[4]; + int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); + resultString.Append((char)('0' + bestMatch)); + foreach (int counter in counters) + { + rowOffset += counter; + } } - - protected internal override int decodeMiddle(BitArray row, int[] startRange, System.Text.StringBuilder resultString) + + return rowOffset; + } + + internal override BarcodeFormat BarcodeFormat + { + get + { + return BarcodeFormat.EAN_13; + } + } + + /// + /// Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded + /// digits in a barcode, determines the implicitly encoded first digit and adds it to the + /// result string. + /// + /// string to insert decoded first digit into + /// int whose bits indicates the pattern of odd/even L/G patterns used to + /// encode digits + /// if first digit cannot be determined +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void determineFirstDigit(StringBuilder resultString, int lgPatternFound) throws com.google.zxing.NotFoundException + private static void determineFirstDigit(StringBuilder resultString, int lgPatternFound) + { + for (int d = 0; d < 10; d++) { - int[] counters = decodeMiddleCounters; - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - int end = row.Size; - int rowOffset = startRange[1]; - - int lgPatternFound = 0; - - for (int x = 0; x < 6 && rowOffset < end; x++) - { - int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); - resultString.Append((char) ('0' + bestMatch % 10)); - for (int i = 0; i < counters.Length; i++) - { - rowOffset += counters[i]; - } - if (bestMatch >= 10) - { - lgPatternFound |= 1 << (5 - x); - } - } - - determineFirstDigit(resultString, lgPatternFound); - - int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); - rowOffset = middleRange[1]; - - for (int x = 0; x < 6 && rowOffset < end; x++) - { - int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); - resultString.Append((char) ('0' + bestMatch)); - for (int i = 0; i < counters.Length; i++) - { - rowOffset += counters[i]; - } - } - - return rowOffset; - } - - /// Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded - /// digits in a barcode, determines the implicitly encoded first digit and adds it to the - /// result string. - /// - /// - /// string to insert decoded first digit into - /// - /// int whose bits indicates the pattern of odd/even L/G patterns used to - /// encode digits - /// - /// ReaderException if first digit cannot be determined - private static void determineFirstDigit(System.Text.StringBuilder resultString, int lgPatternFound) - { - for (int d = 0; d < 10; d++) - { - if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) - { - resultString.Insert(0, (char) ('0' + d)); - return ; - } - } - throw ReaderException.Instance; + if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) + { + resultString.Insert(0, (char)('0' + d)); + return; + } } + throw NotFoundException.NotFoundInstance; + } + } + } \ No newline at end of file diff --git a/csharp/oned/EAN13Writer.cs b/csharp/oned/EAN13Writer.cs index cc2c406c3..dca5c75f2 100755 --- a/csharp/oned/EAN13Writer.cs +++ b/csharp/oned/EAN13Writer.cs @@ -1,84 +1,102 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using WriterException = com.google.zxing.WriterException; -using ByteMatrix = com.google.zxing.common.ByteMatrix; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - - /// This object renders an EAN13 code as a ByteMatrix 2D array of greyscale - /// values. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using EncodeHintType = com.google.zxing.EncodeHintType; + using FormatException = com.google.zxing.FormatException; + using WriterException = com.google.zxing.WriterException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + + /// + /// This object renders an EAN13 code as a . /// + /// @author aripollak@gmail.com (Ari Pollak) /// - /// aripollak@gmail.com (Ari Pollak) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EAN13Writer:UPCEANWriter + public sealed class EAN13Writer : UPCEANWriter { - - private const int codeWidth = 3 + (7 * 6) + 5 + (7 * 6) + 3; // end guard - - public override ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints) + + private const int CODE_WIDTH = 3 + (7 * 6) + 5 + (7 * 6) + 3; // end guard - right bars - middle guard - left bars - start guard + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, com.google.zxing.BarcodeFormat format, int width, int height, java.util.Map hints) throws com.google.zxing.WriterException + public override BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints) + { + if (format != BarcodeFormat.EAN_13) { - if (format != BarcodeFormat.EAN_13) - { - throw new System.ArgumentException("Can only encode EAN_13, but got " + format); - } - - return base.encode(contents, format, width, height, hints); + throw new System.ArgumentException("Can only encode EAN_13, but got " + format); } - - public override sbyte[] encode(System.String contents) + + return base.encode(contents, format, width, height, hints); + } + + public override bool[] encode(string contents) + { + if (contents.Length != 13) { - if (contents.Length != 13) - { - throw new System.ArgumentException("Requested contents should be 13 digits long, but got " + contents.Length); - } - - int firstDigit = System.Int32.Parse(contents.Substring(0, (1) - (0))); - int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit]; - sbyte[] result = new sbyte[codeWidth]; - int pos = 0; - - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); - - // See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded - for (int i = 1; i <= 6; i++) - { - int digit = System.Int32.Parse(contents.Substring(i, (i + 1) - (i))); - if ((parities >> (6 - i) & 1) == 1) - { - digit += 10; - } - pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], 0); - } - - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0); - - for (int i = 7; i <= 12; i++) - { - int digit = System.Int32.Parse(contents.Substring(i, (i + 1) - (i))); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 1); - } - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); - - return result; + throw new System.ArgumentException("Requested contents should be 13 digits long, but got " + contents.Length); } + try + { + if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) + { + throw new System.ArgumentException("Contents do not pass checksum"); + } + } + catch (FormatException fe) + { + throw new System.ArgumentException("Illegal contents"); + } + + int firstDigit = Convert.ToInt32(contents.Substring(0, 1)); + int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit]; + bool[] result = new bool[CODE_WIDTH]; + int pos = 0; + + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); + + // See {@link #EAN13Reader} for a description of how the first digit & left bars are encoded + for (int i = 1; i <= 6; i++) + { + int digit = Convert.ToInt32(contents.Substring(i, 1)); + if ((parities >> (6 - i) & 1) == 1) + { + digit += 10; + } + pos += appendPattern(result, pos, UPCEANReader.L_AND_G_PATTERNS[digit], false); + } + + pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); + + for (int i = 7; i <= 12; i++) + { + int digit = Convert.ToInt32(contents.Substring(i, 1)); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); + } + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); + + return result; + } + } + } \ No newline at end of file diff --git a/csharp/oned/EAN8Reader.cs b/csharp/oned/EAN8Reader.cs index 7fc8c0bcb..87892b3ee 100755 --- a/csharp/oned/EAN8Reader.cs +++ b/csharp/oned/EAN8Reader.cs @@ -1,85 +1,90 @@ +using System.Collections; +using System.Text; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - ///

Implements decoding of the EAN-8 format.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using NotFoundException = com.google.zxing.NotFoundException; + using BitArray = com.google.zxing.common.BitArray; + + /// + ///

Implements decoding of the EAN-8 format.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EAN8Reader:UPCEANReader + public sealed class EAN8Reader : UPCEANReader { - override internal BarcodeFormat BarcodeFormat + + private readonly int[] decodeMiddleCounters; + + public EAN8Reader() + { + decodeMiddleCounters = new int[4]; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected int decodeMiddle(com.google.zxing.common.BitArray row, int[] startRange, StringBuilder result) throws com.google.zxing.NotFoundException + protected internal override int decodeMiddle(BitArray row, int[] startRange, StringBuilder result) + { + int[] counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + int end = row.Size; + int rowOffset = startRange[1]; + + for (int x = 0; x < 4 && rowOffset < end; x++) { - get - { - return BarcodeFormat.EAN_8; - } - + int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); + result.Append((char)('0' + bestMatch)); + foreach (int counter in counters) + { + rowOffset += counter; + } } - - //UPGRADE_NOTE: Final was removed from the declaration of 'decodeMiddleCounters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] decodeMiddleCounters; - - public EAN8Reader() + + int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); + rowOffset = middleRange[1]; + + for (int x = 0; x < 4 && rowOffset < end; x++) { - decodeMiddleCounters = new int[4]; - } - - protected internal override int decodeMiddle(BitArray row, int[] startRange, System.Text.StringBuilder result) - { - int[] counters = decodeMiddleCounters; - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - int end = row.Size; - int rowOffset = startRange[1]; - - for (int x = 0; x < 4 && rowOffset < end; x++) - { - int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); - result.Append((char) ('0' + bestMatch)); - for (int i = 0; i < counters.Length; i++) - { - rowOffset += counters[i]; - } - } - - int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); - rowOffset = middleRange[1]; - - for (int x = 0; x < 4 && rowOffset < end; x++) - { - int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); - result.Append((char) ('0' + bestMatch)); - for (int i = 0; i < counters.Length; i++) - { - rowOffset += counters[i]; - } - } - - return rowOffset; + int bestMatch = decodeDigit(row, counters, rowOffset, L_PATTERNS); + result.Append((char)('0' + bestMatch)); + foreach (int counter in counters) + { + rowOffset += counter; + } } + + return rowOffset; + } + + internal override BarcodeFormat BarcodeFormat + { + get + { + return BarcodeFormat.EAN_8; + } + } + } + } \ No newline at end of file diff --git a/csharp/oned/EAN8Writer.cs b/csharp/oned/EAN8Writer.cs index 8f9b0a646..513f4ca0d 100755 --- a/csharp/oned/EAN8Writer.cs +++ b/csharp/oned/EAN8Writer.cs @@ -1,78 +1,84 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using WriterException = com.google.zxing.WriterException; -using ByteMatrix = com.google.zxing.common.ByteMatrix; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - /// This object renders an EAN8 code as a ByteMatrix 2D array of greyscale - /// values. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using EncodeHintType = com.google.zxing.EncodeHintType; + using WriterException = com.google.zxing.WriterException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + + /// + /// This object renders an EAN8 code as a . /// + /// @author aripollak@gmail.com (Ari Pollak) /// - /// aripollak@gmail.com (Ari Pollak) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class EAN8Writer:UPCEANWriter + public sealed class EAN8Writer : UPCEANWriter { - - private const int codeWidth = 3 + (7 * 4) + 5 + (7 * 4) + 3; // end guard - - public override ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints) + + private const int CODE_WIDTH = 3 + (7 * 4) + 5 + (7 * 4) + 3; // end guard - right bars - middle guard - left bars - start guard + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, com.google.zxing.BarcodeFormat format, int width, int height, java.util.Map hints) throws com.google.zxing.WriterException + public override BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints) + { + if (format != BarcodeFormat.EAN_8) { - if (format != BarcodeFormat.EAN_8) - { - throw new System.ArgumentException("Can only encode EAN_8, but got " + format); - } - - return base.encode(contents, format, width, height, hints); + throw new System.ArgumentException("Can only encode EAN_8, but got " + format); } - - /// a byte array of horizontal pixels (0 = white, 1 = black) - /// - public override sbyte[] encode(System.String contents) + + return base.encode(contents, format, width, height, hints); + } + + /// a byte array of horizontal pixels (false = white, true = black) + public override bool[] encode(string contents) + { + if (contents.Length != 8) { - if (contents.Length != 8) - { - throw new System.ArgumentException("Requested contents should be 8 digits long, but got " + contents.Length); - } - - sbyte[] result = new sbyte[codeWidth]; - int pos = 0; - - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); - - for (int i = 0; i <= 3; i++) - { - int digit = System.Int32.Parse(contents.Substring(i, (i + 1) - (i))); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 0); - } - - pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, 0); - - for (int i = 4; i <= 7; i++) - { - int digit = System.Int32.Parse(contents.Substring(i, (i + 1) - (i))); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], 1); - } - pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, 1); - - return result; + throw new System.ArgumentException("Requested contents should be 8 digits long, but got " + contents.Length); } + + bool[] result = new bool[CODE_WIDTH]; + int pos = 0; + + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); + + for (int i = 0; i <= 3; i++) + { + int digit = Convert.ToInt32(contents.Substring(i, 1)); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], false); + } + + pos += appendPattern(result, pos, UPCEANReader.MIDDLE_PATTERN, false); + + for (int i = 4; i <= 7; i++) + { + int digit = Convert.ToInt32(contents.Substring(i, 1)); + pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); + } + pos += appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); + + return result; + } + } + } \ No newline at end of file diff --git a/csharp/oned/ITFReader.cs b/csharp/oned/ITFReader.cs index 2a5700962..de2b000dd 100755 --- a/csharp/oned/ITFReader.cs +++ b/csharp/oned/ITFReader.cs @@ -1,382 +1,375 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using BitArray = com.google.zxing.common.BitArray; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - ///

Implements decoding of the ITF format.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Result = com.google.zxing.Result; + using ResultPoint = com.google.zxing.ResultPoint; + using BitArray = com.google.zxing.common.BitArray; + + + /// + ///

Implements decoding of the ITF format, or Interleaved Two of Five.

/// - ///

"ITF" stands for Interleaved Two of Five. This Reader will scan ITF barcode with 6, 10 or 14 - /// digits. The checksum is optional and is not applied by this Reader. The consumer of the decoded + ///

This Reader will scan ITF barcodes of certain lengths only. + /// At the moment it reads length 6, 10, 12, 14, 16, 24, and 44 as these have appeared "in the wild". Not all + /// lengths are scanned, especially shorter ones, to avoid false positives. This in turn is due to a lack of + /// required checksum function.

+ /// + ///

The checksum is optional and is not applied by this Reader. The consumer of the decoded /// value will have to apply a checksum if required.

/// ///

http://en.wikipedia.org/wiki/Interleaved_2_of_5 /// is a great reference for Interleaved 2 of 5 information.

/// + /// @author kevin.osullivan@sita.aero, SITA Lab. ///
- /// kevin.osullivan@sita.aero, SITA Lab. - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class ITFReader:OneDReader + public sealed class ITFReader : OneDReader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_AVG_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_INDIVIDUAL_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f); - - private const int W = 3; // Pixel width of a wide line - private const int N = 1; // Pixed width of a narrow line - - //UPGRADE_NOTE: Final was removed from the declaration of 'DEFAULT_ALLOWED_LENGTHS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] DEFAULT_ALLOWED_LENGTHS = new int[]{6, 10, 14, 44}; - - // Stores the actual narrow line width of the image being decoded. - private int narrowLineWidth = - 1; - - /// Start/end guard pattern. - /// - /// Note: The end pattern is reversed because the row is reversed before - /// searching for the END_PATTERN - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'START_PATTERN '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] START_PATTERN = new int[]{N, N, N, N}; - //UPGRADE_NOTE: Final was removed from the declaration of 'END_PATTERN_REVERSED '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] END_PATTERN_REVERSED = new int[]{N, N, W}; - - /// Patterns of Wide / Narrow lines to indicate each digit - //UPGRADE_NOTE: Final was removed from the declaration of 'PATTERNS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] PATTERNS = new int[][]{new int[]{N, N, W, W, N}, new int[]{W, N, N, N, W}, new int[]{N, W, N, N, W}, new int[]{W, W, N, N, N}, new int[]{N, N, W, N, W}, new int[]{W, N, W, N, N}, new int[]{N, W, W, N, N}, new int[]{N, N, N, W, W}, new int[]{W, N, N, W, N}, new int[]{N, W, N, W, N}}; - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + + private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); + private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f); + + private const int W = 3; // Pixel width of a wide line + private const int N = 1; // Pixed width of a narrow line + + private static readonly int[] DEFAULT_ALLOWED_LENGTHS = {44, 24, 20, 18, 16, 14, 12, 10, 8, 6}; + + // Stores the actual narrow line width of the image being decoded. + private int narrowLineWidth = -1; + + /// + /// Start/end guard pattern. + /// + /// Note: The end pattern is reversed because the row is reversed before + /// searching for the END_PATTERN + /// + private static readonly int[] START_PATTERN = {N, N, N, N}; + private static readonly int[] END_PATTERN_REVERSED = {N, N, W}; + + /// + /// Patterns of Wide / Narrow lines to indicate each digit + /// + internal static readonly int[][] PATTERNS = {new int[] {N, N, W, W, N}, new int[] {W, N, N, N, W}, new int[] {N, W, N, N, W}, new int[] {W, W, N, N, N}, new int[] {N, N, W, N, W}, new int[] {W, N, W, N, N}, new int[] {N, W, W, N, N}, new int[] {N, N, N, W, W}, new int[] {W, N, N, W, N}, new int[] {N, W, N, W, N}}; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.FormatException, com.google.zxing.NotFoundException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + + // Find out where the Middle section (payload) starts & ends + int[] startRange = decodeStart(row); + int[] endRange = decodeEnd(row); + + StringBuilder result = new StringBuilder(20); + decodeMiddle(row, startRange[1], endRange[0], result); + string resultString = result.ToString(); + + int[] allowedLengths = null; + if (hints != null && hints.ContainsKey(DecodeHintType.ALLOWED_LENGTHS)) { - - // Find out where the Middle section (payload) starts & ends - int[] startRange = decodeStart(row); - int[] endRange = decodeEnd(row); - - System.Text.StringBuilder result = new System.Text.StringBuilder(20); - decodeMiddle(row, startRange[1], endRange[0], result); - System.String resultString = result.ToString(); - - int[] allowedLengths = null; - if (hints != null) - { - allowedLengths = (int[]) hints[DecodeHintType.ALLOWED_LENGTHS]; - } - if (allowedLengths == null) - { - allowedLengths = DEFAULT_ALLOWED_LENGTHS; - } - - // To avoid false positives with 2D barcodes (and other patterns), make - // an assumption that the decoded string must be 6, 10 or 14 digits. - int length = resultString.Length; - bool lengthOK = false; - for (int i = 0; i < allowedLengths.Length; i++) - { - if (length == allowedLengths[i]) - { - lengthOK = true; - break; - } - } - if (!lengthOK) - { - throw ReaderException.Instance; - } - - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return new Result(resultString, null, new ResultPoint[]{new ResultPoint(startRange[1], (float) rowNumber), new ResultPoint(endRange[0], (float) rowNumber)}, BarcodeFormat.ITF); + allowedLengths = (int[]) hints[DecodeHintType.ALLOWED_LENGTHS]; + } - - /// row of black/white values to search - /// - /// offset of start pattern - /// - /// {@link StringBuffer} to append decoded chars to - /// - /// ReaderException if decoding could not complete successfully - private static void decodeMiddle(BitArray row, int payloadStart, int payloadEnd, System.Text.StringBuilder resultString) + if (allowedLengths == null) { - - // Digits are interleaved in pairs - 5 black lines for one digit, and the - // 5 - // interleaved white lines for the second digit. - // Therefore, need to scan 10 lines and then - // split these into two arrays - int[] counterDigitPair = new int[10]; - int[] counterBlack = new int[5]; - int[] counterWhite = new int[5]; - - while (payloadStart < payloadEnd) - { - - // Get 10 runs of black/white. - recordPattern(row, payloadStart, counterDigitPair); - // Split them into each array - for (int k = 0; k < 5; k++) - { - int twoK = k << 1; - counterBlack[k] = counterDigitPair[twoK]; - counterWhite[k] = counterDigitPair[twoK + 1]; - } - - int bestMatch = decodeDigit(counterBlack); - resultString.Append((char) ('0' + bestMatch)); - bestMatch = decodeDigit(counterWhite); - resultString.Append((char) ('0' + bestMatch)); - - for (int i = 0; i < counterDigitPair.Length; i++) - { - payloadStart += counterDigitPair[i]; - } - } + allowedLengths = DEFAULT_ALLOWED_LENGTHS; } - - /// Identify where the start of the middle / payload section starts. - /// - /// - /// row of black/white values to search - /// - /// Array, containing index of start of 'start block' and end of - /// 'start block' - /// - /// ReaderException - internal int[] decodeStart(BitArray row) + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be 6, 10 or 14 digits. + int length = resultString.Length; + bool lengthOK = false; + foreach (int allowedLength in allowedLengths) { - int endStart = skipWhiteSpace(row); - int[] startPattern = findGuardPattern(row, endStart, START_PATTERN); - - // Determine the width of a narrow line in pixels. We can do this by - // getting the width of the start pattern and dividing by 4 because its - // made up of 4 narrow lines. - this.narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; - - validateQuietZone(row, startPattern[0]); - - return startPattern; + if (length == allowedLength) + { + lengthOK = true; + break; + } } - - /// The start & end patterns must be pre/post fixed by a quiet zone. This - /// zone must be at least 10 times the width of a narrow line. Scan back until - /// we either get to the start of the barcode or match the necessary number of - /// quiet zone pixels. - /// - /// Note: Its assumed the row is reversed when using this method to find - /// quiet zone after the end pattern. - /// - /// ref: http://www.barcode-1.net/i25code.html - /// - /// - /// bit array representing the scanned barcode. - /// - /// index into row of the start or end pattern. - /// - /// ReaderException if the quiet zone cannot be found, a ReaderException is thrown. - private void validateQuietZone(BitArray row, int startPattern) + if (!lengthOK) { - - int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone - - for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) - { - if (row.get_Renamed(i)) - { - break; - } - quietCount--; - } - if (quietCount != 0) - { - // Unable to find the necessary number of quiet zone pixels. - throw ReaderException.Instance; - } + throw FormatException.FormatInstance; } - - /// Skip all whitespace until we get to the first black line. - /// - /// - /// row of black/white values to search - /// - /// index of the first black line. - /// - /// ReaderException Throws exception if no black lines are found in the row - private static int skipWhiteSpace(BitArray row) + + return new Result(resultString, null, new ResultPoint[] {new ResultPoint(startRange[1], (float) rowNumber), new ResultPoint(endRange[0], (float) rowNumber)}, BarcodeFormat.ITF); // no natural byte representation for these barcodes + } + + /// row of black/white values to search + /// offset of start pattern + /// to append decoded chars to + /// if decoding could not complete successfully +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeMiddle(com.google.zxing.common.BitArray row, int payloadStart, int payloadEnd, StringBuilder resultString) throws com.google.zxing.NotFoundException + private static void decodeMiddle(BitArray row, int payloadStart, int payloadEnd, StringBuilder resultString) + { + + // Digits are interleaved in pairs - 5 black lines for one digit, and the + // 5 + // interleaved white lines for the second digit. + // Therefore, need to scan 10 lines and then + // split these into two arrays + int[] counterDigitPair = new int[10]; + int[] counterBlack = new int[5]; + int[] counterWhite = new int[5]; + + while (payloadStart < payloadEnd) { - int width = row.Size; - int endStart = 0; - while (endStart < width) - { - if (row.get_Renamed(endStart)) - { - break; - } - endStart++; - } - if (endStart == width) - { - throw ReaderException.Instance; - } - - return endStart; + + // Get 10 runs of black/white. + recordPattern(row, payloadStart, counterDigitPair); + // Split them into each array + for (int k = 0; k < 5; k++) + { + int twoK = k << 1; + counterBlack[k] = counterDigitPair[twoK]; + counterWhite[k] = counterDigitPair[twoK + 1]; + } + + int bestMatch = decodeDigit(counterBlack); + resultString.Append((char)('0' + bestMatch)); + bestMatch = decodeDigit(counterWhite); + resultString.Append((char)('0' + bestMatch)); + + foreach (int counterDigit in counterDigitPair) + { + payloadStart += counterDigit; + } } - - /// Identify where the end of the middle / payload section ends. - /// - /// - /// row of black/white values to search - /// - /// Array, containing index of start of 'end block' and end of 'end - /// block' - /// - /// ReaderException - - internal int[] decodeEnd(BitArray row) + } + + /// + /// Identify where the start of the middle / payload section starts. + /// + /// row of black/white values to search + /// Array, containing index of start of 'start block' and end of + /// 'start block' + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: int[] decodeStart(com.google.zxing.common.BitArray row) throws com.google.zxing.NotFoundException + internal int[] decodeStart(BitArray row) + { + int endStart = skipWhiteSpace(row); + int[] startPattern = findGuardPattern(row, endStart, START_PATTERN); + + // Determine the width of a narrow line in pixels. We can do this by + // getting the width of the start pattern and dividing by 4 because its + // made up of 4 narrow lines. + this.narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; + + validateQuietZone(row, startPattern[0]); + + return startPattern; + } + + /// + /// The start & end patterns must be pre/post fixed by a quiet zone. This + /// zone must be at least 10 times the width of a narrow line. Scan back until + /// we either get to the start of the barcode or match the necessary number of + /// quiet zone pixels. + /// + /// Note: Its assumed the row is reversed when using this method to find + /// quiet zone after the end pattern. + /// + /// ref: http://www.barcode-1.net/i25code.html + /// + /// bit array representing the scanned barcode. + /// index into row of the start or end pattern. + /// if the quiet zone cannot be found, a ReaderException is thrown. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private void validateQuietZone(com.google.zxing.common.BitArray row, int startPattern) throws com.google.zxing.NotFoundException + private void validateQuietZone(BitArray row, int startPattern) + { + + int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone + + for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { - - // For convenience, reverse the row and then - // search from 'the start' for the end block - row.reverse(); - try - { - int endStart = skipWhiteSpace(row); - int[] endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED); - - // The start & end patterns must be pre/post fixed by a quiet zone. This - // zone must be at least 10 times the width of a narrow line. - // ref: http://www.barcode-1.net/i25code.html - validateQuietZone(row, endPattern[0]); - - // Now recalculate the indices of where the 'endblock' starts & stops to - // accommodate - // the reversed nature of the search - int temp = endPattern[0]; - endPattern[0] = row.Size - endPattern[1]; - endPattern[1] = row.Size - temp; - - return endPattern; - } - finally - { - // Put the row back the right way. - row.reverse(); - } + if (row.get(i)) + { + break; + } + quietCount--; } - - /// row of black/white values to search - /// - /// position to start search - /// - /// pattern of counts of number of black and white pixels that are - /// being searched for as a pattern - /// - /// start/end horizontal offset of guard pattern, as an array of two - /// ints - /// - /// ReaderException if pattern is not found - private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) + if (quietCount != 0) { - - // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be - // merged to a single method. - int patternLength = pattern.Length; - int[] counters = new int[patternLength]; - int width = row.Size; - bool isWhite = false; - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) - { - bool pixel = row.get_Renamed(x); - if (pixel ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) - { - return new int[]{patternStart, x}; - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) - { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - throw ReaderException.Instance; + // Unable to find the necessary number of quiet zone pixels. + throw NotFoundException.NotFoundInstance; } - - /// Attempts to decode a sequence of ITF black/white lines into single - /// digit. - /// - /// - /// the counts of runs of observed black/white/black/... values - /// - /// The decoded digit - /// - /// ReaderException if digit cannot be decoded - private static int decodeDigit(int[] counters) + } + + /// + /// Skip all whitespace until we get to the first black line. + /// + /// row of black/white values to search + /// index of the first black line. + /// Throws exception if no black lines are found in the row +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int skipWhiteSpace(com.google.zxing.common.BitArray row) throws com.google.zxing.NotFoundException + private static int skipWhiteSpace(BitArray row) + { + int width = row.Size; + int endStart = row.getNextSet(0); + if (endStart == width) { - - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - int bestMatch = - 1; - int max = PATTERNS.Length; - for (int i = 0; i < max; i++) + throw NotFoundException.NotFoundInstance; + } + + return endStart; + } + + /// + /// Identify where the end of the middle / payload section ends. + /// + /// row of black/white values to search + /// Array, containing index of start of 'end block' and end of 'end + /// block' + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: int[] decodeEnd(com.google.zxing.common.BitArray row) throws com.google.zxing.NotFoundException + internal int[] decodeEnd(BitArray row) + { + + // For convenience, reverse the row and then + // search from 'the start' for the end block + row.reverse(); + try + { + int endStart = skipWhiteSpace(row); + int[] endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED); + + // The start & end patterns must be pre/post fixed by a quiet zone. This + // zone must be at least 10 times the width of a narrow line. + // ref: http://www.barcode-1.net/i25code.html + validateQuietZone(row, endPattern[0]); + + // Now recalculate the indices of where the 'endblock' starts & stops to + // accommodate + // the reversed nature of the search + int temp = endPattern[0]; + endPattern[0] = row.Size - endPattern[1]; + endPattern[1] = row.Size - temp; + + return endPattern; + } + finally + { + // Put the row back the right way. + row.reverse(); + } + } + + /// row of black/white values to search + /// position to start search + /// pattern of counts of number of black and white pixels that are + /// being searched for as a pattern + /// start/end horizontal offset of guard pattern, as an array of two + /// ints + /// if pattern is not found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int[] findGuardPattern(com.google.zxing.common.BitArray row, int rowOffset, int[] pattern) throws com.google.zxing.NotFoundException + private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern) + { + + // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be + // merged to a single method. + int patternLength = pattern.Length; + int[] counters = new int[patternLength]; + int width = row.Size; + bool isWhite = false; + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) + { + if (row.get(x) ^ isWhite) + { + counters[counterPosition]++; + } + else + { + if (counterPosition == patternLength - 1) { - int[] pattern = PATTERNS[i]; - int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) - { - bestVariance = variance; - bestMatch = i; - } - } - if (bestMatch >= 0) - { - return bestMatch; + if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) + { + return new int[]{patternStart, x}; + } + patternStart += counters[0] + counters[1]; + Array.Copy(counters, 2, counters, 0, patternLength - 2); + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } else { - throw ReaderException.Instance; + counterPosition++; } + counters[counterPosition] = 1; + isWhite = !isWhite; + } } + throw NotFoundException.NotFoundInstance; + } + + /// + /// Attempts to decode a sequence of ITF black/white lines into single + /// digit. + /// + /// the counts of runs of observed black/white/black/... values + /// The decoded digit + /// if digit cannot be decoded +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int decodeDigit(int[] counters) throws com.google.zxing.NotFoundException + private static int decodeDigit(int[] counters) + { + + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = PATTERNS.Length; + for (int i = 0; i < max; i++) + { + int[] pattern = PATTERNS[i]; + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) + { + bestVariance = variance; + bestMatch = i; + } + } + if (bestMatch >= 0) + { + return bestMatch; + } + else + { + throw NotFoundException.NotFoundInstance; + } + } + } + } \ No newline at end of file diff --git a/csharp/oned/MultiFormatOneDReader.cs b/csharp/oned/MultiFormatOneDReader.cs index e058354de..f698f0bb6 100755 --- a/csharp/oned/MultiFormatOneDReader.cs +++ b/csharp/oned/MultiFormatOneDReader.cs @@ -1,89 +1,133 @@ +using System.Collections; +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class MultiFormatOneDReader:OneDReader + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using BitArray = com.google.zxing.common.BitArray; + using RSS14Reader = com.google.zxing.oned.rss.RSS14Reader; + using RSSExpandedReader = com.google.zxing.oned.rss.expanded.RSSExpandedReader; + + + /// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen + /// + public sealed class MultiFormatOneDReader : OneDReader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'readers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList readers; - - public MultiFormatOneDReader(System.Collections.Hashtable hints) + + private readonly OneDReader[] readers; + + public MultiFormatOneDReader(IDictionary hints) + { + //ICollection possibleFormats = hints == null ? null : (ICollection) hints[DecodeHintType.POSSIBLE_FORMATS]; + ICollection possibleFormats = null; + if (hints !=null && hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS)) + { + possibleFormats = (ICollection)hints[DecodeHintType.POSSIBLE_FORMATS]; + } + + //bool useCode39CheckDigit = hints != null && hints[DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT] != null; + bool useCode39CheckDigit = hints != null && hints.ContainsKey(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT); + List readers = new List(); + if (possibleFormats != null) { - System.Collections.ArrayList possibleFormats = hints == null?null:(System.Collections.ArrayList) hints[DecodeHintType.POSSIBLE_FORMATS]; - bool useCode39CheckDigit = hints != null && hints[DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT] != null; - readers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - if (possibleFormats != null) - { - if (possibleFormats.Contains(BarcodeFormat.EAN_13) || possibleFormats.Contains(BarcodeFormat.UPC_A) || possibleFormats.Contains(BarcodeFormat.EAN_8) || possibleFormats.Contains(BarcodeFormat.UPC_E)) - { - readers.Add(new MultiFormatUPCEANReader(hints)); - } - if (possibleFormats.Contains(BarcodeFormat.CODE_39)) - { - readers.Add(new Code39Reader(useCode39CheckDigit)); - } - if (possibleFormats.Contains(BarcodeFormat.CODE_128)) - { - readers.Add(new Code128Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.ITF)) - { - readers.Add(new ITFReader()); - } - } - if ((readers.Count == 0)) - { - readers.Add(new MultiFormatUPCEANReader(hints)); - readers.Add(new Code39Reader()); - readers.Add(new Code128Reader()); - readers.Add(new ITFReader()); - } + if (possibleFormats.Contains(BarcodeFormat.EAN_13) || possibleFormats.Contains(BarcodeFormat.UPC_A) || possibleFormats.Contains(BarcodeFormat.EAN_8) || possibleFormats.Contains(BarcodeFormat.UPC_E)) + { + readers.Add(new MultiFormatUPCEANReader(hints)); + } + if (possibleFormats.Contains(BarcodeFormat.CODE_39)) + { + readers.Add(new Code39Reader(useCode39CheckDigit)); + } + if (possibleFormats.Contains(BarcodeFormat.CODE_93)) + { + readers.Add(new Code93Reader()); + } + if (possibleFormats.Contains(BarcodeFormat.CODE_128)) + { + readers.Add(new Code128Reader()); + } + if (possibleFormats.Contains(BarcodeFormat.ITF)) + { + readers.Add(new ITFReader()); + } + if (possibleFormats.Contains(BarcodeFormat.CODABAR)) + { + readers.Add(new CodaBarReader()); + } + if (possibleFormats.Contains(BarcodeFormat.RSS_14)) + { + readers.Add(new RSS14Reader()); + } + if (possibleFormats.Contains(BarcodeFormat.RSS_EXPANDED)) + { + readers.Add(new RSSExpandedReader()); + } } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + if (readers.Count == 0) { - int size = readers.Count; - for (int i = 0; i < size; i++) - { - OneDReader reader = (OneDReader) readers[i]; - try - { - return reader.decodeRow(rowNumber, row, hints); - } - catch (ReaderException) - { - // continue - } - } - - throw ReaderException.Instance; + readers.Add(new MultiFormatUPCEANReader(hints)); + readers.Add(new Code39Reader()); + readers.Add(new CodaBarReader()); + readers.Add(new Code93Reader()); + readers.Add(new Code128Reader()); + readers.Add(new ITFReader()); + readers.Add(new RSS14Reader()); + readers.Add(new RSSExpandedReader()); } + this.readers = readers.ToArray(/*new OneDReader[readers.Count]*/); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + foreach (OneDReader reader in readers) + { + try + { + return reader.decodeRow(rowNumber, row, hints); + } + catch (ReaderException re) + { + // continue + } + } + + throw NotFoundException.NotFoundInstance; + } + + public override void reset() + { + foreach (Reader reader in readers) + { + reader.reset(); + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/oned/MultiFormatUPCEANReader.cs b/csharp/oned/MultiFormatUPCEANReader.cs index fa12ac51b..e0e435be4 100755 --- a/csharp/oned/MultiFormatUPCEANReader.cs +++ b/csharp/oned/MultiFormatUPCEANReader.cs @@ -1,109 +1,144 @@ +using System.Collections; +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - ///

A reader that can read all available UPC/EAN formats. If a caller wants to try to + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using BitArray = com.google.zxing.common.BitArray; + + + ///

+ ///

A reader that can read all available UPC/EAN formats. If a caller wants to try to /// read all such formats, it is most efficient to use this implementation rather than invoke /// individual readers.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class MultiFormatUPCEANReader:OneDReader + public sealed class MultiFormatUPCEANReader : OneDReader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'readers '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList readers; - - public MultiFormatUPCEANReader(System.Collections.Hashtable hints) + + private readonly UPCEANReader[] readers; + + public MultiFormatUPCEANReader(IDictionary hints) + { + //ICollection possibleFormats = hints == null ? null : (ICollection) hints[DecodeHintType.POSSIBLE_FORMATS]; + ICollection possibleFormats = null; + if (hints != null && hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS)) + { + possibleFormats = (ICollection)hints[DecodeHintType.POSSIBLE_FORMATS]; + } + List readers = new List(); + if (possibleFormats != null) { - System.Collections.ArrayList possibleFormats = hints == null?null:(System.Collections.ArrayList) hints[DecodeHintType.POSSIBLE_FORMATS]; - readers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - if (possibleFormats != null) - { - if (possibleFormats.Contains(BarcodeFormat.EAN_13)) - { - readers.Add(new EAN13Reader()); - } - else if (possibleFormats.Contains(BarcodeFormat.UPC_A)) - { - readers.Add(new UPCAReader()); - } - if (possibleFormats.Contains(BarcodeFormat.EAN_8)) - { - readers.Add(new EAN8Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.UPC_E)) - { - readers.Add(new UPCEReader()); - } - } - if ((readers.Count == 0)) - { - readers.Add(new EAN13Reader()); - // UPC-A is covered by EAN-13 - readers.Add(new EAN8Reader()); - readers.Add(new UPCEReader()); - } + if (possibleFormats.Contains(BarcodeFormat.EAN_13)) + { + readers.Add(new EAN13Reader()); + } + else if (possibleFormats.Contains(BarcodeFormat.UPC_A)) + { + readers.Add(new UPCAReader()); + } + if (possibleFormats.Contains(BarcodeFormat.EAN_8)) + { + readers.Add(new EAN8Reader()); + } + if (possibleFormats.Contains(BarcodeFormat.UPC_E)) + { + readers.Add(new UPCEReader()); + } } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + if (readers.Count == 0) { - // Compute this location once and reuse it on multiple implementations - int[] startGuardPattern = UPCEANReader.findStartGuardPattern(row); - int size = readers.Count; - for (int i = 0; i < size; i++) - { - UPCEANReader reader = (UPCEANReader) readers[i]; - Result result; - try - { - result = reader.decodeRow(rowNumber, row, startGuardPattern, hints); - } - catch (ReaderException) - { - continue; - } - // Special case: a 12-digit code encoded in UPC-A is identical to a "0" - // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, - // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". - // Individually these are correct and their readers will both read such a code - // and correctly call it EAN-13, or UPC-A, respectively. - // - // In this case, if we've been looking for both types, we'd like to call it - // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read - // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A - // result if appropriate. - if (result.BarcodeFormat.Equals(BarcodeFormat.EAN_13) && result.Text[0] == '0') - { - return new Result(result.Text.Substring(1), null, result.ResultPoints, BarcodeFormat.UPC_A); - } - return result; - } - - throw ReaderException.Instance; + readers.Add(new EAN13Reader()); + // UPC-A is covered by EAN-13 + readers.Add(new EAN8Reader()); + readers.Add(new UPCEReader()); } + this.readers = readers.ToArray(/*new UPCEANReader[readers.Count]*/); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + // Compute this location once and reuse it on multiple implementations + int[] startGuardPattern = UPCEANReader.findStartGuardPattern(row); + foreach (UPCEANReader reader in readers) + { + Result result; + try + { + result = reader.decodeRow(rowNumber, row, startGuardPattern, hints); + } + catch (ReaderException re) + { + continue; + } + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" + // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, + // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". + // Individually these are correct and their readers will both read such a code + // and correctly call it EAN-13, or UPC-A, respectively. + // + // In this case, if we've been looking for both types, we'd like to call it + // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read + // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A + // result if appropriate. + // + // But, don't return UPC-A if UPC-A was not a requested format! + bool ean13MayBeUPCA = result.BarcodeFormat == BarcodeFormat.EAN_13 && result.Text[0] == '0'; + //ICollection possibleFormats = hints == null ? null : (ICollection) hints[DecodeHintType.POSSIBLE_FORMATS]; + ICollection possibleFormats = null; + if (hints != null && hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS)) + { + possibleFormats = (ICollection)hints[DecodeHintType.POSSIBLE_FORMATS]; + } + + bool canReturnUPCA = possibleFormats == null || possibleFormats.Contains(BarcodeFormat.UPC_A); + + if (ean13MayBeUPCA && canReturnUPCA) + { + // Transfer the metdata across + Result resultUPCA = new Result(result.Text.Substring(1), result.RawBytes, result.ResultPoints, BarcodeFormat.UPC_A); + resultUPCA.putAllMetadata(result.ResultMetadata); + return resultUPCA; + } + return result; + } + + throw NotFoundException.NotFoundInstance; + } + + public override void reset() + { + foreach (Reader reader in readers) + { + reader.reset(); + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/oned/OneDReader.cs b/csharp/oned/OneDReader.cs index a3d6ccee1..c33d7f63e 100755 --- a/csharp/oned/OneDReader.cs +++ b/csharp/oned/OneDReader.cs @@ -1,332 +1,368 @@ -/* -* 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. -*/ using System; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using DecodeHintType = com.google.zxing.DecodeHintType; -using Reader = com.google.zxing.Reader; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultMetadataType = com.google.zxing.ResultMetadataType; -using ResultPoint = com.google.zxing.ResultPoint; -using BitArray = com.google.zxing.common.BitArray; +using System.Collections; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - /// Encapsulates functionality and implementation that is common to all families + + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using ResultMetadataType = com.google.zxing.ResultMetadataType; + using ResultPoint = com.google.zxing.ResultPoint; + using BitArray = com.google.zxing.common.BitArray; + + + /// + /// Encapsulates functionality and implementation that is common to all families /// of one-dimensional barcodes. /// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public abstract class OneDReader : Reader + public abstract class OneDReader : com.google.zxing.Reader { - - private const int INTEGER_MATH_SHIFT = 8; - //UPGRADE_NOTE: Final was removed from the declaration of 'PATTERN_MATCH_RESULT_SCALE_FACTOR '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; - - public virtual Result decode(BinaryBitmap image) + + protected internal const int INTEGER_MATH_SHIFT = 8; + protected internal static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public virtual Result decode(BinaryBitmap image) + { + return decode(image, null); + } + + // Note that we don't try rotation without the try harder flag, even if rotation was supported. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public virtual Result decode(BinaryBitmap image, IDictionary hints) + { + try { - return decode(image, null); + return doDecode(image, hints); } - - // Note that we don't try rotation without the try harder flag, even if rotation was supported. - public virtual Result decode(BinaryBitmap image, System.Collections.Hashtable hints) + catch (NotFoundException nfe) { + bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); + if (tryHarder && image.RotateSupported) + { + BinaryBitmap rotatedImage = image.rotateCounterClockwise(); + Result result = doDecode(rotatedImage, hints); + // Record that we found it rotated 90 degrees CCW / 270 degrees CW +//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET: +//ORIGINAL LINE: java.util.Map metadata = result.getResultMetadata(); + IDictionary metadata = result.ResultMetadata; + int orientation = 270; + if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) + { + // But if we found it reversed in doDecode(), add in that result here: + orientation = (orientation + (int) metadata[ResultMetadataType.ORIENTATION]) % 360; + } + result.putMetadata(ResultMetadataType.ORIENTATION, orientation); + // Update result points + ResultPoint[] points = result.ResultPoints; + if (points != null) + { + int height = rotatedImage.Height; + for (int i = 0; i < points.Length; i++) + { + points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); + } + } + return result; + } + else + { + throw nfe; + } + } + } + + public virtual void reset() + { + // do nothing + } + + /// + /// We're going to examine rows from the middle outward, searching alternately above and below the + /// middle, and farther out each time. rowStep is the number of rows between each successive + /// attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then + /// middle + rowStep, then middle - (2 * rowStep), etc. + /// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily + /// decided that moving up and down by about 1/16 of the image is pretty good; we try more of the + /// image if "trying harder". + /// + /// The image to decode + /// Any hints that were requested + /// The contents of the decoded barcode + /// Any spontaneous errors which occur +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private com.google.zxing.Result doDecode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException + private Result doDecode(BinaryBitmap image, IDictionary hints) + { + int width = image.Width; + int height = image.Height; + BitArray row = new BitArray(width); + + int middle = height >> 1; + bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); + int rowStep = Math.Max(1, height >> (tryHarder ? 8 : 5)); + int maxLines; + if (tryHarder) + { + maxLines = height; // Look at the whole image, not just the center + } + else + { + maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image + } + + for (int x = 0; x < maxLines; x++) + { + + // Scanning from the middle out. Determine which row we're looking at next: + int rowStepsAboveOrBelow = (x + 1) >> 1; + bool isAbove = (x & 0x01) == 0; // i.e. is x even? + int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + if (rowNumber < 0 || rowNumber >= height) + { + // Oops, if we run off the top or bottom, stop + break; + } + + // Estimate black point for this row and load it: + try + { + row = image.getBlackRow(rowNumber, row); + } + catch (NotFoundException nfe) + { + continue; + } + + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to + // handle decoding upside down barcodes. + for (int attempt = 0; attempt < 2; attempt++) + { + if (attempt == 1) // trying again? + { + row.reverse(); // reverse the row and continue + // This means we will only ever draw result points *once* in the life of this method + // since we want to avoid drawing the wrong points after flipping the row, and, + // don't want to clutter with noise from every single row scan -- just the scans + // that start on the center line. + if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) + { + //IDictionary newHints = new EnumMap(typeof(DecodeHintType)); + Dictionary newHints = new Dictionary(); +//JAVA TO C# CONVERTER TODO TASK: There is no .NET Dictionary equivalent to the Java 'putAll' method: + //newHints.putAll(hints); + //foreach (DecodeHintType dht in Enum.GetValues(typeof(DecodeHintType))) + //{ + // newHints.Add(dht,dht); + //} + foreach (KeyValuePair kvp in hints) + { + newHints.Add(kvp.Key,kvp.Value); + } + + if (newHints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) + { + newHints.Remove(DecodeHintType.NEED_RESULT_POINT_CALLBACK); + } + hints = newHints; + } + } try { - return doDecode(image, hints); + // Look for a barcode + Result result = decodeRow(rowNumber, row, hints); + // We found our barcode + if (attempt == 1) + { + // But it was upside down, so note that + result.putMetadata(ResultMetadataType.ORIENTATION, 180); + // And remember to flip the result points horizontally. + ResultPoint[] points = result.ResultPoints; + if (points != null) + { + points[0] = new ResultPoint(width - points[0].X - 1, points[0].Y); + points[1] = new ResultPoint(width - points[1].X - 1, points[1].Y); + } + } + return result; } catch (ReaderException re) { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - if (tryHarder && image.RotateSupported) - { - BinaryBitmap rotatedImage = image.rotateCounterClockwise(); - Result result = doDecode(rotatedImage, hints); - // Record that we found it rotated 90 degrees CCW / 270 degrees CW - System.Collections.Hashtable metadata = result.ResultMetadata; - int orientation = 270; - if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) - { - // But if we found it reversed in doDecode(), add in that result here: - orientation = (orientation + ((System.Int32) metadata[ResultMetadataType.ORIENTATION])) % 360; - } - result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) orientation); - // Update result points - ResultPoint[] points = result.ResultPoints; - int height = rotatedImage.Height; - for (int i = 0; i < points.Length; i++) - { - points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); - } - return result; - } - else - { - throw re; - } + // continue -- just couldn't decode this row } + } } - - /// We're going to examine rows from the middle outward, searching alternately above and below the - /// middle, and farther out each time. rowStep is the number of rows between each successive - /// attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then - /// middle + rowStep, then middle - (2 * rowStep), etc. - /// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily - /// decided that moving up and down by about 1/16 of the image is pretty good; we try more of the - /// image if "trying harder". - /// - /// - /// The image to decode - /// - /// Any hints that were requested - /// - /// The contents of the decoded barcode - /// - /// ReaderException Any spontaneous errors which occur - private Result doDecode(BinaryBitmap image, System.Collections.Hashtable hints) + + throw NotFoundException.NotFoundInstance; + } + + /// + /// Records the size of successive runs of white and black pixels in a row, starting at a given point. + /// The values are recorded in the given array, and the number of runs recorded is equal to the size + /// of the array. If the row starts on a white pixel at the given start point, then the first count + /// recorded is the run of white pixels starting from that point; likewise it is the count of a run + /// of black pixels if the row begin on a black pixels at that point. + /// + /// row to count from + /// offset into row to start at + /// array into which to record counts + /// if counters cannot be filled entirely from row before running out + /// of pixels +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected static void recordPattern(com.google.zxing.common.BitArray row, int start, int[] counters) throws com.google.zxing.NotFoundException + protected internal static void recordPattern(BitArray row, int start, int[] counters) + { + int numCounters = counters.Length; + //Arrays.fill(counters, 0, numCounters, 0); + counters.Fill(0); + int end = row.Size; + if (start >= end) { - int width = image.Width; - int height = image.Height; - BitArray row = new BitArray(width); - - int middle = height >> 1; - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - int rowStep = System.Math.Max(1, height >> (tryHarder?7:4)); - int maxLines; - if (tryHarder) + throw NotFoundException.NotFoundInstance; + } + bool isWhite = !row.get(start); + int counterPosition = 0; + int i = start; + while (i < end) + { + if (row.get(i) ^ isWhite) // that is, exactly one is true + { + counters[counterPosition]++; + } + else + { + counterPosition++; + if (counterPosition == numCounters) { - maxLines = height; // Look at the whole image, not just the center + break; } else { - maxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image + counters[counterPosition] = 1; + isWhite = !isWhite; } - - for (int x = 0; x < maxLines; x++) - { - - // Scanning from the middle out. Determine which row we're looking at next: - int rowStepsAboveOrBelow = (x + 1) >> 1; - bool isAbove = (x & 0x01) == 0; // i.e. is x even? - int rowNumber = middle + rowStep * (isAbove?rowStepsAboveOrBelow:- rowStepsAboveOrBelow); - if (rowNumber < 0 || rowNumber >= height) - { - // Oops, if we run off the top or bottom, stop - break; - } - - // Estimate black point for this row and load it: - try - { - row = image.getBlackRow(rowNumber, row); - } - catch (ReaderException) - { - continue; - } - - // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to - // handle decoding upside down barcodes. - for (int attempt = 0; attempt < 2; attempt++) - { - if (attempt == 1) - { - // trying again? - row.reverse(); // reverse the row and continue - // This means we will only ever draw result points *once* in the life of this method - // since we want to avoid drawing the wrong points after flipping the row, and, - // don't want to clutter with noise from every single row scan -- just the scans - // that start on the center line. - if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) - { - System.Collections.Hashtable newHints = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); // Can't use clone() in J2ME - System.Collections.IEnumerator hintEnum = hints.Keys.GetEnumerator(); - //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'" - while (hintEnum.MoveNext()) - { - //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'" - System.Object key = hintEnum.Current; - if (!key.Equals(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) - { - newHints[key] = hints[key]; - } - } - hints = newHints; - } - } - try - { - // Look for a barcode - Result result = decodeRow(rowNumber, row, hints); - // We found our barcode - if (attempt == 1) - { - // But it was upside down, so note that - result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) 180); - // And remember to flip the result points horizontally. - ResultPoint[] points = result.ResultPoints; - points[0] = new ResultPoint(width - points[0].X - 1, points[0].Y); - points[1] = new ResultPoint(width - points[1].X - 1, points[1].Y); - } - return result; - } - catch (ReaderException) - { - // continue -- just couldn't decode this row - } - } - } - - throw ReaderException.Instance; + } + i++; } - - /// Records the size of successive runs of white and black pixels in a row, starting at a given point. - /// The values are recorded in the given array, and the number of runs recorded is equal to the size - /// of the array. If the row starts on a white pixel at the given start point, then the first count - /// recorded is the run of white pixels starting from that point; likewise it is the count of a run - /// of black pixels if the row begin on a black pixels at that point. - /// - /// - /// row to count from - /// - /// offset into row to start at - /// - /// array into which to record counts - /// - /// ReaderException if counters cannot be filled entirely from row before running out - /// of pixels - /// - internal static void recordPattern(BitArray row, int start, int[] counters) + // If we read fully the last section of pixels and filled up our counters -- or filled + // the last counter but ran off the side of the image, OK. Otherwise, a problem. + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { - int numCounters = counters.Length; - for (int i = 0; i < numCounters; i++) - { - counters[i] = 0; - } - int end = row.Size; - if (start >= end) - { - throw ReaderException.Instance; - } - bool isWhite = !row.get_Renamed(start); - int counterPosition = 0; - int i2 = start; - while (i2 < end) - { - bool pixel = row.get_Renamed(i2); - if (pixel ^ isWhite) - { - // that is, exactly one is true - counters[counterPosition]++; - } - else - { - counterPosition++; - if (counterPosition == numCounters) - { - break; - } - else - { - counters[counterPosition] = 1; - isWhite ^= true; // isWhite = !isWhite; - } - } - i2++; - } - // If we read fully the last section of pixels and filled up our counters -- or filled - // the last counter but ran off the side of the image, OK. Otherwise, a problem. - if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i2 == end))) - { - throw ReaderException.Instance; - } + throw NotFoundException.NotFoundInstance; } - - /// Determines how closely a set of observed counts of runs of black/white values matches a given - /// target pattern. This is reported as the ratio of the total variance from the expected pattern - /// proportions across all pattern elements, to the length of the pattern. - /// - /// - /// observed counters - /// - /// expected pattern - /// - /// The most any counter can differ before we give up - /// - /// ratio of total variance between counters and pattern compared to total pattern size, - /// where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means - /// the total variance between counters and patterns equals the pattern length, higher values mean - /// even more variance - /// - internal static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected static void recordPatternInReverse(com.google.zxing.common.BitArray row, int start, int[] counters) throws com.google.zxing.NotFoundException + protected internal static void recordPatternInReverse(BitArray row, int start, int[] counters) + { + // This could be more efficient I guess + int numTransitionsLeft = counters.Length; + bool last = row.get(start); + while (start > 0 && numTransitionsLeft >= 0) { - int numCounters = counters.Length; - int total = 0; - int patternLength = 0; - for (int i = 0; i < numCounters; i++) - { - total += counters[i]; - patternLength += pattern[i]; - } - if (total < patternLength) - { - // If we don't even have one pixel per unit of bar width, assume this is too small - // to reliably match, so fail: - return System.Int32.MaxValue; - } - // We're going to fake floating-point math in integers. We just need to use more bits. - // Scale up patternLength so that intermediate values below like scaledCounter will have - // more "significant digits" - int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; - maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; - - int totalVariance = 0; - for (int x = 0; x < numCounters; x++) - { - int counter = counters[x] << INTEGER_MATH_SHIFT; - int scaledPattern = pattern[x] * unitBarWidth; - int variance = counter > scaledPattern?counter - scaledPattern:scaledPattern - counter; - if (variance > maxIndividualVariance) - { - return System.Int32.MaxValue; - } - totalVariance += variance; - } - return totalVariance / total; + if (row.get(--start) != last) + { + numTransitionsLeft--; + last = !last; + } } - - ///

Attempts to decode a one-dimensional barcode format given a single row of - /// an image.

- /// - ///
- /// row number from top of the row - /// - /// the black/white pixel data of the row - /// - /// decode hints - /// - /// {@link Result} containing encoded string and start/end of barcode - /// - /// ReaderException if an error occurs or barcode cannot be found - public abstract Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints); + if (numTransitionsLeft >= 0) + { + throw NotFoundException.NotFoundInstance; + } + recordPattern(row, start + 1, counters); + } + + /// + /// Determines how closely a set of observed counts of runs of black/white values matches a given + /// target pattern. This is reported as the ratio of the total variance from the expected pattern + /// proportions across all pattern elements, to the length of the pattern. + /// + /// observed counters + /// expected pattern + /// The most any counter can differ before we give up + /// ratio of total variance between counters and pattern compared to total pattern size, + /// where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means + /// the total variance between counters and patterns equals the pattern length, higher values mean + /// even more variance + protected internal static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) + { + int numCounters = counters.Length; + int total = 0; + int patternLength = 0; + for (int i = 0; i < numCounters; i++) + { + total += counters[i]; + patternLength += pattern[i]; + } + if (total < patternLength) + { + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + return int.MaxValue; + } + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits" + int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; + maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; + + int totalVariance = 0; + for (int x = 0; x < numCounters; x++) + { + int counter = counters[x] << INTEGER_MATH_SHIFT; + int scaledPattern = pattern[x] * unitBarWidth; + int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) + { + return int.MaxValue; + } + totalVariance += variance; + } + return totalVariance / total; + } + + /// + ///

Attempts to decode a one-dimensional barcode format given a single row of + /// an image.

+ ///
+ /// row number from top of the row + /// the black/white pixel data of the row + /// decode hints + /// containing encoded string and start/end of barcode + /// if an error occurs or barcode cannot be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public abstract com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException; + public abstract Result decodeRow(int rowNumber, BitArray row, IDictionary hints); } -} + +} \ No newline at end of file diff --git a/csharp/oned/UPCAReader.cs b/csharp/oned/UPCAReader.cs index 660e011e5..384ddf5c2 100755 --- a/csharp/oned/UPCAReader.cs +++ b/csharp/oned/UPCAReader.cs @@ -1,86 +1,105 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - ///

Implements decoding of the UPC-A format.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Result = com.google.zxing.Result; + using BitArray = com.google.zxing.common.BitArray; + + + /// + ///

Implements decoding of the UPC-A format.

/// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen ///
- /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class UPCAReader:UPCEANReader + public sealed class UPCAReader : UPCEANReader { - override internal BarcodeFormat BarcodeFormat + + private readonly UPCEANReader ean13Reader = new EAN13Reader(); + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, int[] startGuardRange, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException + public override Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, IDictionary hints) + { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange, hints)); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, hints)); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public override Result decode(BinaryBitmap image) + { + return maybeReturnResult(ean13Reader.decode(image)); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public override Result decode(BinaryBitmap image, IDictionary hints) + { + return maybeReturnResult(ean13Reader.decode(image, hints)); + } + + internal override BarcodeFormat BarcodeFormat + { + get + { + return BarcodeFormat.UPC_A; + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected int decodeMiddle(com.google.zxing.common.BitArray row, int[] startRange, StringBuilder resultString) throws com.google.zxing.NotFoundException + protected internal override int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString) + { + return ean13Reader.decodeMiddle(row, startRange, resultString); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.Result maybeReturnResult(com.google.zxing.Result result) throws com.google.zxing.FormatException + private static Result maybeReturnResult(Result result) + { + string text = result.Text; + if (text[0] == '0') { - get - { - return BarcodeFormat.UPC_A; - } - + return new Result(text.Substring(1), null, result.ResultPoints, BarcodeFormat.UPC_A); } - - //UPGRADE_NOTE: Final was removed from the declaration of 'ean13Reader '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private UPCEANReader ean13Reader = new EAN13Reader(); - - public override Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, System.Collections.Hashtable hints) + else { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange, hints)); - } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) - { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, hints)); - } - - public override Result decode(BinaryBitmap image) - { - return maybeReturnResult(ean13Reader.decode(image)); - } - - public override Result decode(BinaryBitmap image, System.Collections.Hashtable hints) - { - return maybeReturnResult(ean13Reader.decode(image, hints)); - } - - protected internal override int decodeMiddle(BitArray row, int[] startRange, System.Text.StringBuilder resultString) - { - return ean13Reader.decodeMiddle(row, startRange, resultString); - } - - private static Result maybeReturnResult(Result result) - { - System.String text = result.Text; - if (text[0] == '0') - { - return new Result(text.Substring(1), null, result.ResultPoints, BarcodeFormat.UPC_A); - } - else - { - throw ReaderException.Instance; - } + throw FormatException.FormatInstance; } + } + } + } \ No newline at end of file diff --git a/csharp/oned/UPCEANReader.cs b/csharp/oned/UPCEANReader.cs index b0a031e51..94486fe92 100755 --- a/csharp/oned/UPCEANReader.cs +++ b/csharp/oned/UPCEANReader.cs @@ -1,359 +1,403 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPointCallback = com.google.zxing.ResultPointCallback; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ResultPoint = com.google.zxing.ResultPoint; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using BitArray = com.google.zxing.common.BitArray; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.oned { - - ///

Encapsulates functionality and implementation that is common to UPC and EAN families + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using ReaderException = com.google.zxing.ReaderException; + using Result = com.google.zxing.Result; + using ResultMetadataType = com.google.zxing.ResultMetadataType; + using ResultPoint = com.google.zxing.ResultPoint; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitArray = com.google.zxing.common.BitArray; + using com.google.zxing.common; + + public static class ArrayExtensions + { + public static void Fill(this int[] arr,int value) + { + for (int i = 0; i < arr.Length;i++ ) + { + arr.SetValue(value,i); + } + } + } + + + ///

+ ///

Encapsulates functionality and implementation that is common to UPC and EAN families /// of one-dimensional barcodes.

/// + /// @author dswitkin@google.com (Daniel Switkin) + /// @author Sean Owen + /// @author alasdair@google.com (Alasdair Mackintosh) ///
- /// dswitkin@google.com (Daniel Switkin) - /// - /// Sean Owen - /// - /// alasdair@google.com (Alasdair Mackintosh) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public abstract class UPCEANReader:OneDReader + public abstract class UPCEANReader : OneDReader { - /// Get the format of this decoder. - /// - /// - /// The 1D format. - /// - internal abstract BarcodeFormat BarcodeFormat{get;} - - // These two values are critical for determining how permissive the decoding will be. - // We've arrived at these values through a lot of trial and error. Setting them any higher - // lets false positives creep in quickly. - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_AVG_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); - //UPGRADE_NOTE: Final was removed from the declaration of 'MAX_INDIVIDUAL_VARIANCE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static readonly int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); - - /// Start/end guard pattern. - //UPGRADE_NOTE: Final was removed from the declaration of 'START_END_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] START_END_PATTERN = new int[]{1, 1, 1}; - - /// Pattern marking the middle of a UPC/EAN pattern, separating the two halves. - //UPGRADE_NOTE: Final was removed from the declaration of 'MIDDLE_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[] MIDDLE_PATTERN = new int[]{1, 1, 1, 1, 1}; - - /// "Odd", or "L" patterns used to encode UPC/EAN digits. - //UPGRADE_NOTE: Final was removed from the declaration of 'L_PATTERNS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - internal static readonly int[][] L_PATTERNS = new int[][]{new int[]{3, 2, 1, 1}, new int[]{2, 2, 2, 1}, new int[]{2, 1, 2, 2}, new int[]{1, 4, 1, 1}, new int[]{1, 1, 3, 2}, new int[]{1, 2, 3, 1}, new int[]{1, 1, 1, 4}, new int[]{1, 3, 1, 2}, new int[]{1, 2, 1, 3}, new int[]{3, 1, 1, 2}}; - - /// As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. - internal static int[][] L_AND_G_PATTERNS; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decodeRowStringBuffer '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Text.StringBuilder decodeRowStringBuffer; - - protected internal UPCEANReader() + + // These two values are critical for determining how permissive the decoding will be. + // We've arrived at these values through a lot of trial and error. Setting them any higher + // lets false positives creep in quickly. + private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48f); + private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); + + /// + /// Start/end guard pattern. + /// + internal static readonly int[] START_END_PATTERN = {1, 1, 1}; + + /// + /// Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + /// + internal static readonly int[] MIDDLE_PATTERN = {1, 1, 1, 1, 1}; + + /// + /// "Odd", or "L" patterns used to encode UPC/EAN digits. + /// + internal static readonly int[][] L_PATTERNS = {new int[] {3, 2, 1, 1}, new int[] {2, 2, 2, 1}, new int[] {2, 1, 2, 2}, new int[] {1, 4, 1, 1}, new int[] {1, 1, 3, 2}, new int[] {1, 2, 3, 1}, new int[] {1, 1, 1, 4}, new int[] {1, 3, 1, 2}, new int[] {1, 2, 1, 3}, new int[] {3, 1, 1, 2}}; + + /// + /// As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + /// + internal static readonly int[][] L_AND_G_PATTERNS; + + static UPCEANReader() + { + L_AND_G_PATTERNS = new int[20][]; + Array.Copy(L_PATTERNS, 0, L_AND_G_PATTERNS, 0, 10); + for (int i = 10; i < 20; i++) { - decodeRowStringBuffer = new System.Text.StringBuilder(20); + int[] widths = L_PATTERNS[i - 10]; + int[] reversedWidths = new int[widths.Length]; + for (int j = 0; j < widths.Length; j++) + { + reversedWidths[j] = widths[widths.Length - j - 1]; + } + L_AND_G_PATTERNS[i] = reversedWidths; } - - internal static int[] findStartGuardPattern(BitArray row) + } + + private readonly StringBuilder decodeRowStringBuffer; + private readonly UPCEANExtensionSupport extensionReader; + private readonly EANManufacturerOrgSupport eanManSupport; + + protected internal UPCEANReader() + { + decodeRowStringBuffer = new StringBuilder(20); + extensionReader = new UPCEANExtensionSupport(); + eanManSupport = new EANManufacturerOrgSupport(); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static int[] findStartGuardPattern(com.google.zxing.common.BitArray row) throws com.google.zxing.NotFoundException + internal static int[] findStartGuardPattern(BitArray row) + { + bool foundStart = false; + int[] startRange = null; + int nextStart = 0; + int[] counters = new int[START_END_PATTERN.Length]; + while (!foundStart) { - bool foundStart = false; - int[] startRange = null; - int nextStart = 0; - while (!foundStart) - { - startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN); - int start = startRange[0]; - nextStart = startRange[1]; - // Make sure there is a quiet zone at least as big as the start pattern before the barcode. - // If this check would run off the left edge of the image, do not accept this barcode, - // as it is very likely to be a false positive. - int quietStart = start - (nextStart - start); - if (quietStart >= 0) - { - foundStart = row.isRange(quietStart, start, false); - } - } - return startRange; + //Arrays.fill(counters, 0, START_END_PATTERN.Length, 0); + counters.Fill(0); + startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, counters); + int start = startRange[0]; + nextStart = startRange[1]; + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + int quietStart = start - (nextStart - start); + if (quietStart >= 0) + { + foundStart = row.isRange(quietStart, start, false); + } } - - public override Result decodeRow(int rowNumber, BitArray row, System.Collections.Hashtable hints) + return startRange; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) + { + return decodeRow(rowNumber, row, findStartGuardPattern(row), hints); + } + + /// + ///

Like , but + /// allows caller to inform method about where the UPC/EAN start pattern is + /// found. This allows this to be computed once and reused across many implementations.

+ ///
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decodeRow(int rowNumber, com.google.zxing.common.BitArray row, int[] startGuardRange, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public virtual Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, IDictionary hints) + { + + //ResultPointCallback resultPointCallback = hints == null ? null : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + ResultPointCallback resultPointCallback = null; + if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) + { + resultPointCallback = (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + } + + if (resultPointCallback != null) { - return decodeRow(rowNumber, row, findStartGuardPattern(row), hints); + resultPointCallback.foundPossibleResultPoint(new ResultPoint((startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber)); } - - ///

Like {@link #decodeRow(int, BitArray, java.util.Hashtable)}, but - /// allows caller to inform method about where the UPC/EAN start pattern is - /// found. This allows this to be computed once and reused across many implementations.

- ///
- public virtual Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange, System.Collections.Hashtable hints) + + StringBuilder result = decodeRowStringBuffer; + result.Length = 0; + int endStart = decodeMiddle(row, startGuardRange, result); + + if (resultPointCallback != null) { - - ResultPointCallback resultPointCallback = hints == null?null:(ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - - if (resultPointCallback != null) - { - resultPointCallback.foundPossibleResultPoint(new ResultPoint((startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber)); - } - - System.Text.StringBuilder result = decodeRowStringBuffer; - result.Length = 0; - int endStart = decodeMiddle(row, startGuardRange, result); - - if (resultPointCallback != null) - { - resultPointCallback.foundPossibleResultPoint(new ResultPoint(endStart, rowNumber)); - } - - int[] endRange = decodeEnd(row, endStart); - - if (resultPointCallback != null) - { - resultPointCallback.foundPossibleResultPoint(new ResultPoint((endRange[0] + endRange[1]) / 2.0f, rowNumber)); - } - - - // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The - // spec might want more whitespace, but in practice this is the maximum we can count on. - int end = endRange[1]; - int quietEnd = end + (end - endRange[0]); - if (quietEnd >= row.Size || !row.isRange(end, quietEnd, false)) - { - throw ReaderException.Instance; - } - - System.String resultString = result.ToString(); - if (!checkChecksum(resultString)) - { - throw ReaderException.Instance; - } - - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float right = (float) (endRange[1] + endRange[0]) / 2.0f; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, BarcodeFormat); + resultPointCallback.foundPossibleResultPoint(new ResultPoint(endStart, rowNumber)); } - - /// {@link #checkStandardUPCEANChecksum(String)} - /// - //UPGRADE_NOTE: Access modifiers of method 'checkChecksum' were changed to 'protected'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1204'" - protected internal virtual bool checkChecksum(System.String s) + + int[] endRange = decodeEnd(row, endStart); + + if (resultPointCallback != null) { - return checkStandardUPCEANChecksum(s); + resultPointCallback.foundPossibleResultPoint(new ResultPoint((endRange[0] + endRange[1]) / 2.0f, rowNumber)); } - - /// Computes the UPC/EAN checksum on a string of digits, and reports - /// whether the checksum is correct or not. - /// - /// - /// string of digits to check - /// - /// true iff string of digits passes the UPC/EAN checksum algorithm - /// - /// ReaderException if the string does not contain only digits - private static bool checkStandardUPCEANChecksum(System.String s) + + + // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The + // spec might want more whitespace, but in practice this is the maximum we can count on. + int end = endRange[1]; + int quietEnd = end + (end - endRange[0]); + if (quietEnd >= row.Size || !row.isRange(end, quietEnd, false)) { - int length = s.Length; - if (length == 0) - { - return false; - } - - int sum = 0; - for (int i = length - 2; i >= 0; i -= 2) - { - int digit = (int) s[i] - (int) '0'; - if (digit < 0 || digit > 9) - { - throw ReaderException.Instance; - } - sum += digit; - } - sum *= 3; - for (int i = length - 1; i >= 0; i -= 2) - { - int digit = (int) s[i] - (int) '0'; - if (digit < 0 || digit > 9) - { - throw ReaderException.Instance; - } - sum += digit; - } - return sum % 10 == 0; + throw NotFoundException.NotFoundInstance; } - - //UPGRADE_NOTE: Access modifiers of method 'decodeEnd' were changed to 'protected'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1204'" - protected internal virtual int[] decodeEnd(BitArray row, int endStart) + + string resultString = result.ToString(); + if (!checkChecksum(resultString)) { - return findGuardPattern(row, endStart, false, START_END_PATTERN); + throw ChecksumException.ChecksumInstance; } - - /// row of black/white values to search - /// - /// position to start search - /// - /// if true, indicates that the pattern specifies white/black/white/... - /// pixel counts, otherwise, it is interpreted as black/white/black/... - /// - /// pattern of counts of number of black and white pixels that are being - /// searched for as a pattern - /// - /// start/end horizontal offset of guard pattern, as an array of two ints - /// - /// ReaderException if pattern is not found - internal static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern) + + float left = (float)(startGuardRange[1] + startGuardRange[0]) / 2.0f; + float right = (float)(endRange[1] + endRange[0]) / 2.0f; + BarcodeFormat format = BarcodeFormat; + Result decodeResult = new Result(resultString, null, new ResultPoint[]{new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber)}, format); // no natural byte representation for these barcodes + + try { - int patternLength = pattern.Length; - int[] counters = new int[patternLength]; - int width = row.Size; - bool isWhite = false; - while (rowOffset < width) - { - isWhite = !row.get_Renamed(rowOffset); - if (whiteFirst == isWhite) - { - break; - } - rowOffset++; - } - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) - { - bool pixel = row.get_Renamed(x); - if (pixel ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) - { - return new int[]{patternStart, x}; - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) - { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - throw ReaderException.Instance; + Result extensionResult = extensionReader.decodeRow(rowNumber, row, endRange[1]); + decodeResult.putMetadata(ResultMetadataType.UPC_EAN_EXTENSION, extensionResult.Text); + decodeResult.putAllMetadata(extensionResult.ResultMetadata); + decodeResult.addResultPoints(extensionResult.ResultPoints); } - - /// Attempts to decode a single UPC/EAN-encoded digit. - /// - /// - /// row of black/white values to decode - /// - /// the counts of runs of observed black/white/black/... values - /// - /// horizontal offset to start decoding from - /// - /// the set of patterns to use to decode -- sometimes different encodings - /// for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should - /// be used - /// - /// horizontal offset of first pixel beyond the decoded digit - /// - /// ReaderException if digit cannot be decoded - internal static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns) + catch (ReaderException re) { - recordPattern(row, rowOffset, counters); - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - int bestMatch = - 1; - int max = patterns.Length; - for (int i = 0; i < max; i++) + // continue + } + + if (format == BarcodeFormat.EAN_13 || format == BarcodeFormat.UPC_A) + { + string countryID = eanManSupport.lookupCountryIdentifier(resultString); + if (countryID != null) + { + decodeResult.putMetadata(ResultMetadataType.POSSIBLE_COUNTRY, countryID); + } + } + + return decodeResult; + } + + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: boolean checkChecksum(String s) throws com.google.zxing.ChecksumException, com.google.zxing.FormatException + protected internal virtual bool checkChecksum(string s) + { + return checkStandardUPCEANChecksum(s); + } + + /// + /// Computes the UPC/EAN checksum on a string of digits, and reports + /// whether the checksum is correct or not. + /// + /// string of digits to check + /// true iff string of digits passes the UPC/EAN checksum algorithm + /// if the string does not contain only digits +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static boolean checkStandardUPCEANChecksum(CharSequence s) throws com.google.zxing.FormatException + internal static bool checkStandardUPCEANChecksum(string s) + { + int length = s.Length; + if (length == 0) + { + return false; + } + + int sum = 0; + for (int i = length - 2; i >= 0; i -= 2) + { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) + { + throw FormatException.FormatInstance; + } + sum += digit; + } + sum *= 3; + for (int i = length - 1; i >= 0; i -= 2) + { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) + { + throw FormatException.FormatInstance; + } + sum += digit; + } + return sum % 10 == 0; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: int[] decodeEnd(com.google.zxing.common.BitArray row, int endStart) throws com.google.zxing.NotFoundException + protected internal virtual int[] decodeEnd(BitArray row, int endStart) + { + return findGuardPattern(row, endStart, false, START_END_PATTERN); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static int[] findGuardPattern(com.google.zxing.common.BitArray row, int rowOffset, boolean whiteFirst, int[] pattern) throws com.google.zxing.NotFoundException + internal static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern) + { + return findGuardPattern(row, rowOffset, whiteFirst, pattern, new int[pattern.Length]); + } + + /// row of black/white values to search + /// position to start search + /// if true, indicates that the pattern specifies white/black/white/... + /// pixel counts, otherwise, it is interpreted as black/white/black/... + /// pattern of counts of number of black and white pixels that are being + /// searched for as a pattern + /// array of counters, as long as pattern, to re-use + /// start/end horizontal offset of guard pattern, as an array of two ints + /// if pattern is not found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int[] findGuardPattern(com.google.zxing.common.BitArray row, int rowOffset, boolean whiteFirst, int[] pattern, int[] counters) throws com.google.zxing.NotFoundException + private static int[] findGuardPattern(BitArray row, int rowOffset, bool whiteFirst, int[] pattern, int[] counters) + { + int patternLength = pattern.Length; + int width = row.Size; + bool isWhite = whiteFirst; + rowOffset = whiteFirst ? row.getNextUnset(rowOffset) : row.getNextSet(rowOffset); + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) + { + if (row.get(x) ^ isWhite) + { + counters[counterPosition]++; + } + else + { + if (counterPosition == patternLength - 1) { - int[] pattern = patterns[i]; - int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) - { - bestVariance = variance; - bestMatch = i; - } - } - if (bestMatch >= 0) - { - return bestMatch; + if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) + { + return new int[]{patternStart, x}; + } + patternStart += counters[0] + counters[1]; + Array.Copy(counters, 2, counters, 0, patternLength - 2); + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } else { - throw ReaderException.Instance; + counterPosition++; } + counters[counterPosition] = 1; + isWhite = !isWhite; + } } - - /// Subclasses override this to decode the portion of a barcode between the start - /// and end guard patterns. - /// - /// - /// row of black/white values to search - /// - /// start/end offset of start guard pattern - /// - /// {@link StringBuffer} to append decoded chars to - /// - /// horizontal offset of first pixel after the "middle" that was decoded - /// - /// ReaderException if decoding could not complete successfully - protected internal abstract int decodeMiddle(BitArray row, int[] startRange, System.Text.StringBuilder resultString); - static UPCEANReader() + throw NotFoundException.NotFoundInstance; + } + + /// + /// Attempts to decode a single UPC/EAN-encoded digit. + /// + /// row of black/white values to decode + /// the counts of runs of observed black/white/black/... values + /// horizontal offset to start decoding from + /// the set of patterns to use to decode -- sometimes different encodings + /// for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should + /// be used + /// horizontal offset of first pixel beyond the decoded digit + /// if digit cannot be decoded +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static int decodeDigit(com.google.zxing.common.BitArray row, int[] counters, int rowOffset, int[][] patterns) throws com.google.zxing.NotFoundException + internal static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns) + { + recordPattern(row, rowOffset, counters); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = patterns.Length; + for (int i = 0; i < max; i++) { - { - L_AND_G_PATTERNS = new int[20][]; - for (int i = 0; i < 10; i++) - { - L_AND_G_PATTERNS[i] = L_PATTERNS[i]; - } - for (int i = 10; i < 20; i++) - { - int[] widths = L_PATTERNS[i - 10]; - int[] reversedWidths = new int[widths.Length]; - for (int j = 0; j < widths.Length; j++) - { - reversedWidths[j] = widths[widths.Length - j - 1]; - } - L_AND_G_PATTERNS[i] = reversedWidths; - } - } + int[] pattern = patterns[i]; + int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) + { + bestVariance = variance; + bestMatch = i; + } } + if (bestMatch >= 0) + { + return bestMatch; + } + else + { + throw NotFoundException.NotFoundInstance; + } + } + + /// + /// Get the format of this decoder. + /// + /// The 1D format. + internal abstract BarcodeFormat BarcodeFormat {get;} + + /// + /// Subclasses override this to decode the portion of a barcode between the start + /// and end guard patterns. + /// + /// row of black/white values to search + /// start/end offset of start guard pattern + /// to append decoded chars to + /// horizontal offset of first pixel after the "middle" that was decoded + /// if decoding could not complete successfully +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected abstract int decodeMiddle(com.google.zxing.common.BitArray row, int[] startRange, StringBuilder resultString) throws com.google.zxing.NotFoundException; + protected internal abstract int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString); + } + } \ No newline at end of file diff --git a/csharp/oned/UPCEANWriter.cs b/csharp/oned/UPCEANWriter.cs index 6368db180..b3b10ebcf 100755 --- a/csharp/oned/UPCEANWriter.cs +++ b/csharp/oned/UPCEANWriter.cs @@ -1,145 +1,41 @@ /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using Writer = com.google.zxing.Writer; -using WriterException = com.google.zxing.WriterException; -using ByteMatrix = com.google.zxing.common.ByteMatrix; + * 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. + */ + namespace com.google.zxing.oned { - - ///

Encapsulates functionality and implementation that is common to UPC and EAN families + + ///

+ ///

Encapsulates functionality and implementation that is common to UPC and EAN families /// of one-dimensional barcodes.

/// + /// @author aripollak@gmail.com (Ari Pollak) + /// @author dsbnatut@gmail.com (Kazuki Nishiura) ///
- /// aripollak@gmail.com (Ari Pollak) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public abstract class UPCEANWriter : Writer + public abstract class UPCEANWriter : OneDimensionalCodeWriter { - - public virtual ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height) - { - return encode(contents, format, width, height, null); - } - - public virtual ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints) - { - if (contents == null || contents.Length == 0) - { - throw new System.ArgumentException("Found empty contents"); - } - - if (width < 0 || height < 0) - { - throw new System.ArgumentException("Requested dimensions are too small: " + width + 'x' + height); - } - - sbyte[] code = encode(contents); - return renderResult(code, width, height); - } - - /// a byte array of horizontal pixels (0 = white, 1 = black) - /// - private static ByteMatrix renderResult(sbyte[] code, int width, int height) - { - int inputWidth = code.Length; - // Add quiet zone on both sides - int fullWidth = inputWidth + (UPCEANReader.START_END_PATTERN.Length << 1); - int outputWidth = System.Math.Max(width, fullWidth); - int outputHeight = System.Math.Max(1, height); - - int multiple = outputWidth / fullWidth; - int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; - - ByteMatrix output = new ByteMatrix(outputWidth, outputHeight); - sbyte[][] outputArray = output.Array; - - sbyte[] row = new sbyte[outputWidth]; - - // a. Write the white pixels at the left of each row - for (int x = 0; x < leftPadding; x++) - { - row[x] = (sbyte) SupportClass.Identity(255); - } - - // b. Write the contents of this row of the barcode - int offset = leftPadding; - for (int x = 0; x < inputWidth; x++) - { - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // type cased 0 with sbyte - sbyte value_Renamed = (code[x] == 1) ? (sbyte)0 : (sbyte)SupportClass.Identity(255); - for (int z = 0; z < multiple; z++) - { - row[offset + z] = value_Renamed; - } - offset += multiple; - } - - // c. Write the white pixels at the right of each row - offset = leftPadding + (inputWidth * multiple); - for (int x = offset; x < outputWidth; x++) - { - row[x] = (sbyte) SupportClass.Identity(255); - } - - // d. Write the completed row multiple times - for (int z = 0; z < outputHeight; z++) - { - Array.Copy(row, 0, outputArray[z], 0, outputWidth); - } - - return output; - } - - - /// Appends the given pattern to the target array starting at pos. - /// - /// - /// starting color - 0 for white, 1 for black - /// - /// the number of elements added to target. - /// - protected internal static int appendPattern(sbyte[] target, int pos, int[] pattern, int startColor) - { - if (startColor != 0 && startColor != 1) - { - throw new System.ArgumentException("startColor must be either 0 or 1, but got: " + startColor); - } - - sbyte color = (sbyte) startColor; - int numAdded = 0; - for (int i = 0; i < pattern.Length; i++) - { - for (int j = 0; j < pattern[i]; j++) - { - target[pos] = color; - pos += 1; - numAdded += 1; - } - color ^= 1; // flip color after each segment - } - return numAdded; - } - - /// a byte array of horizontal pixels (0 = white, 1 = black) - /// - public abstract sbyte[] encode(System.String contents); + + public override int DefaultMargin + { + get + { + // Use a different default more appropriate for UPC/EAN + return UPCEANReader.START_END_PATTERN.Length; + } + } + } + } \ No newline at end of file diff --git a/csharp/oned/UPCEReader.cs b/csharp/oned/UPCEReader.cs index 5c0f8530c..ef6238701 100755 --- a/csharp/oned/UPCEReader.cs +++ b/csharp/oned/UPCEReader.cs @@ -1,173 +1,179 @@ +using System.Collections; +using System.Text; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using ReaderException = com.google.zxing.ReaderException; -using BitArray = com.google.zxing.common.BitArray; + * 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. + */ + namespace com.google.zxing.oned { - - ///

Implements decoding of the UPC-E format.

+ + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using ChecksumException = com.google.zxing.ChecksumException; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using BitArray = com.google.zxing.common.BitArray; + + /// + ///

Implements decoding of the UPC-E format.

///

///

This is a great reference for /// UPC-E information.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class UPCEReader:UPCEANReader + public sealed class UPCEReader : UPCEANReader { - override internal BarcodeFormat BarcodeFormat + + /// + /// The pattern that marks the middle, and end, of a UPC-E pattern. + /// There is no "second half" to a UPC-E barcode. + /// + private static readonly int[] MIDDLE_END_PATTERN = {1, 1, 1, 1, 1, 1}; + + /// + /// See ; these values similarly represent patterns of + /// even-odd parity encodings of digits that imply both the number system (0 or 1) + /// used, and the check digit. + /// + private static readonly int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = {new int[] {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, new int[] {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}}; + + private readonly int[] decodeMiddleCounters; + + public UPCEReader() + { + decodeMiddleCounters = new int[4]; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected int decodeMiddle(com.google.zxing.common.BitArray row, int[] startRange, StringBuilder result) throws com.google.zxing.NotFoundException + protected internal override int decodeMiddle(BitArray row, int[] startRange, StringBuilder result) + { + int[] counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + int end = row.Size; + int rowOffset = startRange[1]; + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { - get + int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); + result.Append((char)('0' + bestMatch % 10)); + foreach (int counter in counters) + { + rowOffset += counter; + } + if (bestMatch >= 10) + { + lgPatternFound |= 1 << (5 - x); + } + } + + determineNumSysAndCheckDigit(result, lgPatternFound); + + return rowOffset; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected int[] decodeEnd(com.google.zxing.common.BitArray row, int endStart) throws com.google.zxing.NotFoundException + protected internal override int[] decodeEnd(BitArray row, int endStart) + { + return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected boolean checkChecksum(String s) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + protected internal override bool checkChecksum(string s) + { + return base.checkChecksum(convertUPCEtoUPCA(s)); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void determineNumSysAndCheckDigit(StringBuilder resultString, int lgPatternFound) throws com.google.zxing.NotFoundException + private static void determineNumSysAndCheckDigit(StringBuilder resultString, int lgPatternFound) + { + + for (int numSys = 0; numSys <= 1; numSys++) + { + for (int d = 0; d < 10; d++) + { + if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { - return BarcodeFormat.UPC_E; + resultString.Insert(0, (char)('0' + numSys)); + resultString.Append((char)('0' + d)); + return; } - + } } - - /// The pattern that marks the middle, and end, of a UPC-E pattern. - /// There is no "second half" to a UPC-E barcode. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'MIDDLE_END_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] MIDDLE_END_PATTERN = new int[]{1, 1, 1, 1, 1, 1}; - - /// See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of - /// even-odd parity encodings of digits that imply both the number system (0 or 1) - /// used, and the check digit. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'NUMSYS_AND_CHECK_DIGIT_PATTERNS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = new int[][]{new int[]{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, new int[]{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decodeMiddleCounters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] decodeMiddleCounters; - - public UPCEReader() + throw NotFoundException.NotFoundInstance; + } + + internal override BarcodeFormat BarcodeFormat + { + get + { + return BarcodeFormat.UPC_E; + } + } + + /// + /// Expands a UPC-E value back into its full, equivalent UPC-A code value. + /// + /// UPC-E code as string of digits + /// equivalent UPC-A code as string of digits + public static string convertUPCEtoUPCA(string upce) + { + char[] upceChars = new char[6]; + upce.CopyTo(1, upceChars, 0, 6); + StringBuilder result = new StringBuilder(12); + result.Append(upce[0]); + char lastChar = upceChars[5]; + switch (lastChar) { - decodeMiddleCounters = new int[4]; - } - - protected internal override int decodeMiddle(BitArray row, int[] startRange, System.Text.StringBuilder result) - { - int[] counters = decodeMiddleCounters; - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - int end = row.Size; - int rowOffset = startRange[1]; - - int lgPatternFound = 0; - - for (int x = 0; x < 6 && rowOffset < end; x++) - { - int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS); - result.Append((char) ('0' + bestMatch % 10)); - for (int i = 0; i < counters.Length; i++) - { - rowOffset += counters[i]; - } - if (bestMatch >= 10) - { - lgPatternFound |= 1 << (5 - x); - } - } - - determineNumSysAndCheckDigit(result, lgPatternFound); - - return rowOffset; - } - - protected internal override int[] decodeEnd(BitArray row, int endStart) - { - return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); - } - - protected internal override bool checkChecksum(System.String s) - { - return base.checkChecksum(convertUPCEtoUPCA(s)); - } - - private static void determineNumSysAndCheckDigit(System.Text.StringBuilder resultString, int lgPatternFound) - { - - for (int numSys = 0; numSys <= 1; numSys++) - { - for (int d = 0; d < 10; d++) - { - if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) - { - resultString.Insert(0, (char) ('0' + numSys)); - resultString.Append((char) ('0' + d)); - return ; - } - } - } - throw ReaderException.Instance; - } - - /// Expands a UPC-E value back into its full, equivalent UPC-A code value. - /// - /// - /// UPC-E code as string of digits - /// - /// equivalent UPC-A code as string of digits - /// - public static System.String convertUPCEtoUPCA(System.String upce) - { - char[] upceChars = new char[6]; - SupportClass.GetCharsFromString(upce, 1, 7, upceChars, 0); - System.Text.StringBuilder result = new System.Text.StringBuilder(12); - result.Append(upce[0]); - char lastChar = upceChars[5]; - switch (lastChar) - { - - case '0': - case '1': - case '2': - result.Append(upceChars, 0, 2); - result.Append(lastChar); - result.Append("0000"); - result.Append(upceChars, 2, 3); - break; - - case '3': - result.Append(upceChars, 0, 3); - result.Append("00000"); - result.Append(upceChars, 3, 2); - break; - - case '4': - result.Append(upceChars, 0, 4); - result.Append("00000"); - result.Append(upceChars[4]); - break; - - default: - result.Append(upceChars, 0, 5); - result.Append("0000"); - result.Append(lastChar); - break; - - } - result.Append(upce[7]); - return result.ToString(); + case '0': + case '1': + case '2': + result.Append(upceChars, 0, 2); + result.Append(lastChar); + result.Append("0000"); + result.Append(upceChars, 2, 3); + break; + case '3': + result.Append(upceChars, 0, 3); + result.Append("00000"); + result.Append(upceChars, 3, 2); + break; + case '4': + result.Append(upceChars, 0, 4); + result.Append("00000"); + result.Append(upceChars[4]); + break; + default: + result.Append(upceChars, 0, 5); + result.Append("0000"); + result.Append(lastChar); + break; } + result.Append(upce[7]); + return result.ToString(); + } + } + } \ No newline at end of file diff --git a/csharp/pdf417/PDF417Reader.cs b/csharp/pdf417/PDF417Reader.cs index 765d78969..efdd4235e 100755 --- a/csharp/pdf417/PDF417Reader.cs +++ b/csharp/pdf417/PDF417Reader.cs @@ -1,161 +1,229 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using DecodeHintType = com.google.zxing.DecodeHintType; -using Reader = com.google.zxing.Reader; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; -using DetectorResult = com.google.zxing.common.DetectorResult; -using Decoder = com.google.zxing.pdf417.decoder.Decoder; -using Detector = com.google.zxing.pdf417.detector.Detector; + * 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. + */ + namespace com.google.zxing.pdf417 { - - /// This implementation can detect and decode PDF417 codes in an image. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using Result = com.google.zxing.Result; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using DetectorResult = com.google.zxing.common.DetectorResult; + using Decoder = com.google.zxing.pdf417.decoder.Decoder; + using Detector = com.google.zxing.pdf417.detector.Detector; + + + /// + /// This implementation can detect and decode PDF417 codes in an image. /// + /// @author SITA Lab (kevin.osullivan@sita.aero) /// - /// SITA Lab (kevin.osullivan@sita.aero) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class PDF417Reader : Reader + public sealed class PDF417Reader : com.google.zxing.Reader { - - //UPGRADE_NOTE: Final was removed from the declaration of 'NO_POINTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Decoder decoder = new Decoder(); - - /// Locates and decodes a PDF417 code in an image. - /// - /// - /// a String representing the content encoded by the PDF417 code - /// - /// ReaderException if a PDF417 code cannot be found, or cannot be decoded - public Result decode(BinaryBitmap image) + + private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; + + private readonly Decoder decoder = new Decoder(); + + /// + /// Locates and decodes a PDF417 code in an image. + /// + /// a String representing the content encoded by the PDF417 code + /// if a PDF417 code cannot be found, + /// if a PDF417 cannot be decoded +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException + public Result decode(BinaryBitmap image) + { + return decode(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException, com.google.zxing.ChecksumException + public Result decode(BinaryBitmap image, IDictionary hints) + { + DecoderResult decoderResult; + ResultPoint[] points; + if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) { - return decode(image, null); + BitMatrix bits = extractPureBits(image.BlackMatrix); + decoderResult = decoder.decode(bits); + points = NO_POINTS; } - - public Result decode(BinaryBitmap image, System.Collections.Hashtable hints) + else { - DecoderResult decoderResult; - ResultPoint[] points; - if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) - { - BitMatrix bits = extractPureBits(image); - decoderResult = decoder.decode(bits); - points = NO_POINTS; - } - else - { - DetectorResult detectorResult = new Detector(image).detect(); - decoderResult = decoder.decode(detectorResult.Bits); - points = detectorResult.Points; - } - return new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF417); + DetectorResult detectorResult = (new Detector(image)).detect(); + decoderResult = decoder.decode(detectorResult.Bits); + points = detectorResult.Points; } - - /// This method detects a barcode in a "pure" image -- that is, pure monochrome image - /// which contains only an unrotated, unskewed, image of a barcode, with some white border - /// around it. This is a specialized method that works exceptionally fast in this special - /// case. - /// - private static BitMatrix extractPureBits(BinaryBitmap image) + return new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF_417); + } + + public void reset() + { + // do nothing + } + + /// + /// This method detects a code in a "pure" image -- that is, pure monochrome image + /// which contains only an unrotated, unskewed, image of a code, with some white border + /// around it. This is a specialized method that works exceptionally fast in this special + /// case. + /// + /// + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix extractPureBits(com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static BitMatrix extractPureBits(BitMatrix image) + { + + int[] leftTopBlack = image.TopLeftOnBit; + int[] rightBottomBlack = image.BottomRightOnBit; + if (leftTopBlack == null || rightBottomBlack == null) { - // Now need to determine module size in pixels - BitMatrix matrix = image.BlackMatrix; - int height = matrix.Height; - int width = matrix.Width; - int minDimension = System.Math.Min(height, width); - - // First, skip white border by tracking diagonally from the top left down and to the right: - int borderWidth = 0; - while (borderWidth < minDimension && !matrix.get_Renamed(borderWidth, borderWidth)) - { - borderWidth++; - } - if (borderWidth == minDimension) - { - throw ReaderException.Instance; - } - - // And then keep tracking across the top-left black module to determine module size - int moduleEnd = borderWidth; - while (moduleEnd < minDimension && matrix.get_Renamed(moduleEnd, moduleEnd)) - { - moduleEnd++; - } - if (moduleEnd == minDimension) - { - throw ReaderException.Instance; - } - - int moduleSize = moduleEnd - borderWidth; - - // And now find where the rightmost black module on the first row ends - int rowEndOfSymbol = width - 1; - while (rowEndOfSymbol >= 0 && !matrix.get_Renamed(rowEndOfSymbol, borderWidth)) - { - rowEndOfSymbol--; - } - if (rowEndOfSymbol < 0) - { - throw ReaderException.Instance; - } - rowEndOfSymbol++; - - // Make sure width of barcode is a multiple of module size - if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) - { - throw ReaderException.Instance; - } - int dimension = (rowEndOfSymbol - borderWidth) / moduleSize; - - // Push in the "border" by half the module width so that we start - // sampling in the middle of the module. Just in case the image is a - // little off, this will help recover. - borderWidth += (moduleSize >> 1); - - int sampleDimension = borderWidth + (dimension - 1) * moduleSize; - if (sampleDimension >= width || sampleDimension >= height) - { - throw ReaderException.Instance; - } - - // Now just read off the bits - BitMatrix bits = new BitMatrix(dimension); - for (int y = 0; y < dimension; y++) - { - int iOffset = borderWidth + y * moduleSize; - for (int x = 0; x < dimension; x++) - { - if (matrix.get_Renamed(borderWidth + x * moduleSize, iOffset)) - { - bits.set_Renamed(x, y); - } - } - } - return bits; + throw NotFoundException.NotFoundInstance; } + + int moduleSize = getModuleSize(leftTopBlack, image); + + int top = leftTopBlack[1]; + int bottom = rightBottomBlack[1]; + int left = findPatternStart(leftTopBlack[0], top, image); + int right = findPatternEnd(leftTopBlack[0], top, image); + + int matrixWidth = (right - left + 1) / moduleSize; + int matrixHeight = (bottom - top + 1) / moduleSize; + if (matrixWidth <= 0 || matrixHeight <= 0) + { + throw NotFoundException.NotFoundInstance; + } + + // 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. + int nudge = moduleSize >> 1; + top += nudge; + left += nudge; + + // Now just read off the bits + BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight); + for (int y = 0; y < matrixHeight; y++) + { + int iOffset = top + y * moduleSize; + for (int x = 0; x < matrixWidth; x++) + { + if (image.get(left + x * moduleSize, iOffset)) + { + bits.set(x, y); + } + } + } + return bits; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int moduleSize(int[] leftTopBlack, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static int getModuleSize(int[] leftTopBlack, BitMatrix image) + { + int x = leftTopBlack[0]; + int y = leftTopBlack[1]; + int width = image.Width; + while (x < width && image.get(x, y)) + { + x++; + } + if (x == width) + { + throw NotFoundException.NotFoundInstance; + } + + int moduleSize = (int)((uint)(x - leftTopBlack[0]) >> 3); // We've crossed left first bar, which is 8x + if (moduleSize == 0) + { + throw NotFoundException.NotFoundInstance; + } + + return moduleSize; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int findPatternStart(int x, int y, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static int findPatternStart(int x, int y, BitMatrix image) + { + int width = image.Width; + int start = x; + // start should be on black + int transitions = 0; + bool black = true; + while (start < width - 1 && transitions < 8) + { + start++; + bool newBlack = image.get(start, y); + if (black != newBlack) + { + transitions++; + } + black = newBlack; + } + if (start == width - 1) + { + throw NotFoundException.NotFoundInstance; + } + return start; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int findPatternEnd(int x, int y, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static int findPatternEnd(int x, int y, BitMatrix image) + { + int width = image.Width; + int end = width - 1; + // end should be on black + while (end > x && !image.get(end, y)) + { + end--; + } + int transitions = 0; + bool black = true; + while (end > x && transitions < 9) + { + end--; + bool newBlack = image.get(end, y); + if (black != newBlack) + { + transitions++; + } + black = newBlack; + } + if (end == x) + { + throw NotFoundException.NotFoundInstance; + } + return end; + } + } + } \ No newline at end of file diff --git a/csharp/pdf417/decoder/BitMatrixParser.cs b/csharp/pdf417/decoder/BitMatrixParser.cs index 2b78f6977..ee28812cf 100755 --- a/csharp/pdf417/decoder/BitMatrixParser.cs +++ b/csharp/pdf417/decoder/BitMatrixParser.cs @@ -1,630 +1,360 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; + +/* + * 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. + */ + namespace com.google.zxing.pdf417.decoder { - - ///

+ + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + ///

+ ///

/// This class parses the BitMatrix image into codewords. ///

/// + /// @author SITA Lab (kevin.osullivan@sita.aero) ///
- /// SITA Lab (kevin.osullivan@sita.aero) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class BitMatrixParser + internal sealed class BitMatrixParser { - /// Returns an array of locations representing the erasures. - public int[] Erasures + + private static readonly int[] NO_ERRORS = new int[0]; + + private const int MAX_ROW_DIFFERENCE = 6; + private const int MAX_ROWS = 90; + //private static final int MAX_COLUMNS = 30; + // Maximum Codewords (Data + Error) + private const int MAX_CW_CAPACITY = 929; + private const int MODULES_IN_SYMBOL = 17; + + private readonly BitMatrix bitMatrix; + private int rows = 0; + //private int columns = 0; + + private int leftColumnECData = 0; + private int rightColumnECData = 0; + private int eraseCount = 0; + private int[] erasures; + private int ecLevel = -1; + + internal BitMatrixParser(BitMatrix bitMatrix) + { + this.bitMatrix = bitMatrix; + } + + /// + /// To ensure separability of rows, codewords of consecutive rows belong to + /// different subsets of all possible codewords. This routine scans the + /// symbols in the barcode. When it finds a number of consecutive rows which + /// are the same, it assumes that this is a row of codewords and processes + /// them into a codeword array. + /// + /// an array of codewords. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: int[] readCodewords() throws com.google.zxing.FormatException + internal int[] readCodewords() + { + int width = bitMatrix.Width; + int height = bitMatrix.Height; + + erasures = new int[MAX_CW_CAPACITY]; + + // Get the number of pixels in a module across the X dimension + //float moduleWidth = bitMatrix.getModuleWidth(); + float moduleWidth = 1.0f; // Image has been sampled and reduced + + int[] rowCounters = new int[width]; + int[] codewords = new int[MAX_CW_CAPACITY]; + int next = 0; + int matchingConsecutiveScans = 0; + bool rowInProgress = false; + int rowNumber = 0; + int rowHeight = 0; + for (int i = 1; i < height; i++) { - get + if (rowNumber >= MAX_ROWS) + { + // Something is wrong, since we have exceeded + // the maximum rows in the specification. + throw FormatException.FormatInstance; + } + int rowDifference = 0; + // Scan a line of modules and check the + // difference between this and the previous line + for (int j = 0; j < width; j++) + { + // Accumulate differences between this line and the + // previous line. + if (bitMatrix.get(j, i) != bitMatrix.get(j, i - 1)) { - return erasures; + rowDifference++; } - - } - public int ECLevel - { - get + } + if (rowDifference <= moduleWidth * MAX_ROW_DIFFERENCE) + { + for (int j = 0; j < width; j++) { - return ecLevel; + // Accumulate the black pixels on this line + if (bitMatrix.get(j, i)) + { + rowCounters[j]++; + } } - - } - - private const int MAX_ROW_DIFFERENCE = 6; - private const int MAX_ROWS = 90; - //private static final int MAX_COLUMNS = 30; - // Maximum Codewords (Data + Error) - private const int MAX_CW_CAPACITY = 929; - private const int MODULES_IN_SYMBOL = 17; - - //UPGRADE_NOTE: Final was removed from the declaration of 'bitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix bitMatrix; - private int rows = 0; - //private int columns = 0; - - private int leftColumnECData = 0; - private int rightColumnECData = 0; - private int eraseCount = 0; - private int[] erasures = null; - private int ecLevel = - 1; - - internal BitMatrixParser(BitMatrix bitMatrix) - { - this.bitMatrix = bitMatrix; - } - - /// To ensure separability of rows, codewords of consecutive rows belong to - /// different subsets of all possible codewords. This routine scans the - /// symbols in the barcode. When it finds a number of consecutive rows which - /// are the same, it assumes that this is a row of codewords and processes - /// them into a codeword array. - /// - /// - /// an array of codewords. - /// - internal int[] readCodewords() - { - int width = bitMatrix.Dimension; - // TODO should be a rectangular matrix - int height = width; - - erasures = new int[MAX_CW_CAPACITY]; - - // Get the number of pixels in a module across the X dimension - //float moduleWidth = bitMatrix.getModuleWidth(); - float moduleWidth = 1.0f; // Image has been sampled and reduced - - int[] rowCounters = new int[width]; - int[] codewords = new int[MAX_CW_CAPACITY]; - int next = 0; - int matchingConsecutiveScans = 0; - bool rowInProgress = false; - int rowNumber = 0; - int rowHeight = 0; - for (int i = 1; i < height; i++) + // Increment the number of consecutive rows of pixels + // that are more or less the same + matchingConsecutiveScans++; + // Height of a row is a multiple of the module size in pixels + // It's supposed to be >= 3x module width, but, accept anything >= 2x + if ((matchingConsecutiveScans + 1) >= 2.0f * moduleWidth) { - if (rowNumber >= MAX_ROWS) - { - // Something is wrong, since we have exceeded - // the maximum rows in the specification. - // TODO Maybe return error code - return null; - } - int rowDifference = 0; - // Scan a line of modules and check the - // difference between this and the previous line - for (int j = 0; j < width; j++) - { - // Accumulate differences between this line and the - // previous line. - if (bitMatrix.get_Renamed(j, i) != bitMatrix.get_Renamed(j, i - 1)) - { - rowDifference++; - } - } - if (rowDifference <= moduleWidth * MAX_ROW_DIFFERENCE) - { - for (int j = 0; j < width; j++) - { - // Accumulate the black pixels on this line - if (bitMatrix.get_Renamed(j, i)) - { - rowCounters[j]++; - } - } - // Increment the number of consecutive rows of pixels - // that are more or less the same - matchingConsecutiveScans++; - // Height of a row is a multiple of the module size in pixels - // Usually at least 3 times the module size - if (matchingConsecutiveScans >= moduleWidth * 2) - { - // MGMG - // We have some previous matches as well as a match here - // Set processing a unique row. - rowInProgress = true; - } - } - else - { - if (rowInProgress) - { - // Process Row - next = processRow(rowCounters, rowNumber, rowHeight, codewords, next); - if (next == - 1) - { - // Something is wrong, since we have exceeded - // the maximum columns in the specification. - // TODO Maybe return error code - return null; - } - // Reinitialize the row counters. - for (int j = 0; j < rowCounters.Length; j++) - { - rowCounters[j] = 0; - } - rowNumber++; - rowHeight = 0; - } - matchingConsecutiveScans = 0; - rowInProgress = false; - } - rowHeight++; + // We have some previous matches as well as a match here + // Set processing a unique row. + rowInProgress = true; } - // Check for a row that was in progress before we exited above. + } + else + { if (rowInProgress) { - // Process Row - if (rowNumber >= MAX_ROWS) - { - // Something is wrong, since we have exceeded - // the maximum rows in the specification. - // TODO Maybe return error code - return null; - } - next = processRow(rowCounters, rowNumber, rowHeight, codewords, next); - rowNumber++; - rows = rowNumber; + // Process Row + next = processRow(rowCounters, rowNumber, rowHeight, codewords, next); + if (next == -1) + { + // Something is wrong, since we have exceeded + // the maximum columns in the specification. + throw FormatException.FormatInstance; + } + // Reinitialize the row counters. + for (int j = 0; j < rowCounters.Length; j++) + { + rowCounters[j] = 0; + } + rowNumber++; + rowHeight = 0; } - erasures = trimArray(erasures, eraseCount); - return trimArray(codewords, next); + matchingConsecutiveScans = 0; + rowInProgress = false; + } + rowHeight++; } - - /// Trim the array to the required size. - /// - /// - /// the array - /// - /// the size to trim it to - /// - /// the new trimmed array - /// - private static int[] trimArray(int[] array, int size) + // Check for a row that was in progress before we exited above. + if (rowInProgress) { - if (size > 0) - { - int[] a = new int[size]; - for (int i = 0; i < size; i++) - { - a[i] = array[i]; - } - return a; - } - else - { - return null; - } + // Process Row + if (rowNumber >= MAX_ROWS) + { + // Something is wrong, since we have exceeded + // the maximum rows in the specification. + throw FormatException.FormatInstance; + } + next = processRow(rowCounters, rowNumber, rowHeight, codewords, next); + rowNumber++; + rows = rowNumber; } - - /// Convert the symbols in the row to codewords. - /// Each PDF417 symbol character consists of four bar elements and four space - /// elements, each of which can be one to six modules wide. The four bar and - /// four space elements shall measure 17 modules in total. - /// - /// - /// an array containing the counts of black pixels for each column - /// in the row. - /// - /// the current row number of codewords. - /// - /// the height of this row in pixels. - /// - /// the codeword array to save codewords into. - /// - /// the next available index into the codewords array. - /// - /// the next available index into the codeword array after processing - /// this row. - /// - internal int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next) + erasures = trimArray(erasures, eraseCount); + return trimArray(codewords, next); + } + + /// + /// Trim the array to the required size. + /// + /// the array + /// the size to trim it to + /// the new trimmed array + private static int[] trimArray(int[] array, int size) + { + if (size < 0) { - int width = bitMatrix.Dimension; - int columnNumber = 0; - long symbol = 0; - for (int i = 0; i < width; i += MODULES_IN_SYMBOL) - { - for (int mask = MODULES_IN_SYMBOL - 1; mask >= 0; mask--) - { - if (rowCounters[i + (MODULES_IN_SYMBOL - 1 - mask)] >= SupportClass.URShift(rowHeight, 1)) - { - symbol |= 1L << mask; - } - } - if (columnNumber > 0) - { - int cw = getCodeword(symbol); - // if (debug) System.out.println(" " + Long.toBinaryString(symbol) + - // " cw=" +cw + " ColumnNumber=" +columnNumber + "i=" +i); - if (cw < 0 && i < width - MODULES_IN_SYMBOL) - { - // Skip errors on the Right row indicator column - erasures[eraseCount] = next; - next++; - eraseCount++; - } - else - { - codewords[next++] = cw; - } - } - else - { - // Left row indicator column - int cw = getCodeword(symbol); - // if (debug) System.out.println(" " + Long.toBinaryString(symbol) + - // " cw=" +cw + " ColumnNumber=" +columnNumber + "i=" +i); - if (ecLevel < 0) - { - switch (rowNumber % 3) - { - - case 0: - break; - - case 1: - leftColumnECData = cw; - break; - - case 2: - break; - } - } - } - symbol = 0; - //columns = columnNumber; - columnNumber++; - } - if (columnNumber > 1) - { - // Right row indicator column is in codeword[next] - //columns--; - // Overwrite the last codeword i.e. Right Row Indicator - --next; - if (ecLevel < 0) - { - switch (rowNumber % 3) - { - - case 0: - break; - - case 1: - break; - - case 2: - rightColumnECData = codewords[next]; - if (rightColumnECData == leftColumnECData && leftColumnECData != 0) - { - ecLevel = ((rightColumnECData % 30) - rows % 3) / 3; - } - break; - } - } - codewords[next] = 0; - } - return next; + throw new System.ArgumentException(); } - - /// Build a symbol from the pixels. - /// Each symbol character is defined by an 8-digit bar-space sequence which - /// represents the module widths of the eight elements of that symbol - /// character. - /// - /// - /// array of pixel counter corresponding to each Bar/Space pattern. - /// - /// the symbol - /// - /* - private static long getSymbol(int[] counters, float moduleWidth) { - int pixelsInSymbol = 0; - for (int j = 0; j < counters.length; j++) { - pixelsInSymbol += counters[j]; - } - float avgModuleWidth = (pixelsInSymbol / 17.0f); - boolean toggle = true; - int shift = 0; - int symbol = 0; - for (int j = 0; j < counters.length; j++) { - if (counters[j] < moduleWidth && counters[j] > 0) { - // Give a very narrow bar/space a chance - counters[j] = (int) moduleWidth; - } - // Calculate number of modules in the symbol. - // int modules = (int)(counters[j]/moduleWidth); - // int modules = round(counters[j]/moduleWidth); - int modules = round(counters[j] / avgModuleWidth); - if (modules > 6) { - // Maximum size is 6 modules - modules = 6; - } else if (modules < 1) { - modules = 1; - } - if (toggle) { - for (int k = 0; k < modules; k++) { - symbol |= 1 << (16 - k - shift); - } - toggle = false; - } else { - toggle = true; - } - shift += modules; - } - return symbol; - } - */ - - /// Translate the symbol into a codeword. - /// - /// - /// - /// - /// the codeword corresponding to the symbol. - /// - private static int getCodeword(long symbol) + if (size == 0) { - long sym = symbol; - sym &= 0x3ffff; - int i = findCodewordIndex(sym); - if (i == - 1) - { - return - 1; - } - else - { - long cw = CODEWORD_TABLE[i] - 1; - cw %= 929; - return (int) cw; - } + return NO_ERRORS; } - - /// Use a binary search to find the index of the codeword corresponding to - /// this symbol. - /// - /// - /// the symbol from the barcode. - /// - /// the index into the codeword table. - /// - private static int findCodewordIndex(long symbol) - { - int first = 0; - int upto = SYMBOL_TABLE.Length; - while (first < upto) - { - int mid = SupportClass.URShift((first + upto), 1); // Compute mid point. - if (symbol < SYMBOL_TABLE[mid]) - { - upto = mid; // repeat search in bottom half. - } - else if (symbol > SYMBOL_TABLE[mid]) - { - first = mid + 1; // Repeat search in top half. - } - else - { - return mid; // Found it. return position - } - } - return - 1; - // if (debug) System.out.println("Failed to find codeword for Symbol=" + - // symbol); - } - - /// Ends up being a bit faster than Math.round(). This merely rounds its - /// argument to the nearest int, where x.5 rounds up. - /// - /* - private static int round(float d) { - return (int) (d + 0.5f); - } - */ - - /// Convert the symbols in the row to codewords. - /// Each PDF417 symbol character consists of four bar elements and four space - /// elements, each of which can be one to six modules wide. The four bar and - /// four space elements shall measure 17 modules in total. - /// - /// - /// an array containing the counts of black pixels for each column - /// in the row. - /// - /// the current row number of codewords. - /// - /// the height of this row in pixels. - /// - /// the size of a module in pixels. - /// - /// the codeword array to save codewords into. - /// - /// the next available index into the codewords array. - /// - /// the next available index into the codeword array after processing - /// this row. - /// - /// ReaderException - /* - int processRow1(int[] rowCounters, int rowNumber, int rowHeight, - float moduleWidth, int[] codewords, int next) { - int width = bitMatrix.getDimension(); - int firstBlack = 0; - - for (firstBlack = 0; firstBlack < width; firstBlack++) { - // Step forward until we find the first black pixels - if (rowCounters[firstBlack] >= rowHeight >>> 1) { - break; - } - } - - int[] counters = new int[8]; - int state = 0; // In black pixels, looking for white, first or second time - long symbol = 0; + int[] a = new int[size]; + Array.Copy(array, 0, a, 0, size); + return a; + } + + /// + /// Convert the symbols in the row to codewords. + /// Each PDF417 symbol character consists of four bar elements and four space + /// elements, each of which can be one to six modules wide. The four bar and + /// four space elements shall measure 17 modules in total. + /// + /// an array containing the counts of black pixels for each column + /// in the row. + /// the current row number of codewords. + /// the height of this row in pixels. + /// the codeword array to save codewords into. + /// the next available index into the codewords array. + /// the next available index into the codeword array after processing + /// this row. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next) throws com.google.zxing.FormatException + internal int processRow(int[] rowCounters, int rowNumber, int rowHeight, int[] codewords, int next) + { + int width = bitMatrix.Width; int columnNumber = 0; - for (int i = firstBlack; i < width; i++) { - if (state == 1 || state == 3 || state == 5 || state == 7) { // In white - // pixels, - // looking - // for - // black - // If more than half the column is black - if (rowCounters[i] >= rowHeight >>> 1 || i == width - 1) { - if (i == width - 1) { - counters[state]++; + long symbol = 0; + for (int i = 0; i < width; i += MODULES_IN_SYMBOL) + { + // This happens in real life and is almost surely a rare misdecode + if (i + MODULES_IN_SYMBOL > rowCounters.Length) + { + throw FormatException.FormatInstance; + } + for (int mask = MODULES_IN_SYMBOL - 1; mask >= 0; mask--) + { + if (rowCounters[i + (MODULES_IN_SYMBOL - 1 - mask)] >= (int)((uint)rowHeight >> 1)) + { + symbol |= 1L << mask; + } + } + if (columnNumber > 0) + { + int cw = getCodeword(symbol); + if (cw < 0 && i < width - MODULES_IN_SYMBOL) + { + // Skip errors on the Right row indicator column + if (eraseCount >= erasures.Length) + { + throw FormatException.FormatInstance; + } + erasures[eraseCount] = next; + next++; + eraseCount++; + } + else + { + codewords[next++] = cw; + } + } + else + { + // Left row indicator column + int cw = getCodeword(symbol); + if (ecLevel < 0 && rowNumber % 3 == 1) + { + leftColumnECData = cw; + } + } + symbol = 0; + //columns = columnNumber; + columnNumber++; } - // In black pixels or the end of a row - state++; - if (state < 8) { - // Don't count the last one - counters[state]++; - } - } else { - counters[state]++; - } - } else { - if (rowCounters[i] < rowHeight >>> 1) { - // Found white pixels - state++; - if (state == 7 && i == width - 1) { - // Its found white pixels at the end of the row, - // give it a chance to exit gracefully - i--; - } else { - // Found white pixels - counters[state]++; - } - } else { - if (state < 8) { - // Still in black pixels - counters[state]++; - } - } - } - if (state == 8) { // Found black, white, black, white, black, white, - // black, white and stumbled back onto black; done - if (columnNumber >= MAX_COLUMNS) { - // Something is wrong, since we have exceeded - // the maximum columns in the specification. - // TODO Maybe return error code - return -1; - } - if (columnNumber > 0) { - symbol = getSymbol(counters, moduleWidth); - int cw = getCodeword(symbol); - // if (debug) System.out.println(" " + - // Long.toBinaryString(symbol) + " cw=" +cw + " ColumnNumber=" - // +columnNumber + "i=" +i); - if (cw < 0) { - erasures[eraseCount] = next; - next++; - eraseCount++; - } else { - codewords[next++] = cw; - } - } else { - // Left row indicator column - symbol = getSymbol(counters, moduleWidth); - int cw = getCodeword(symbol); - if (ecLevel < 0) { - switch (rowNumber % 3) { - case 0: - break; - case 1: - leftColumnECData = cw; - break; - case 2: - break; - } - } - } - // Step back so that this pixel can be examined during the next - // pass. - i--; - counters = new int[8]; - columns = columnNumber; - columnNumber++; - // Introduce some errors if (rowNumber == 0 && columnNumber == 4) - // { codewords[next-1] = 0; erasures[eraseCount] = next-1; - // eraseCount++; } if (rowNumber == 0 && columnNumber == 6) { - // codewords[next-1] = 10; erasures[eraseCount] = next-1; - // eraseCount++; } if (rowNumber == 0 && columnNumber == 8) { - // codewords[next-1] = 10; erasures[eraseCount] = next-1; - // eraseCount++; } - state = 0; - symbol = 0; - } - } - if (columnNumber > 1) { - // Right row indicator column is in codeword[next] - columns--; - // Overwrite the last codeword i.e. Right Row Indicator - --next; - if (ecLevel < 0) { - switch (rowNumber % 3) { - case 0: - break; - case 1: - break; - case 2: - rightColumnECData = codewords[next]; - if (rightColumnECData == leftColumnECData - && leftColumnECData != 0) { - ecLevel = ((rightColumnECData % 30) - rows % 3) / 3; - } - break; - } - } - codewords[next] = 0; + if (columnNumber > 1) + { + // Right row indicator column is in codeword[next] + //columns--; + // Overwrite the last codeword i.e. Right Row Indicator + --next; + if (ecLevel < 0 && rowNumber % 3 == 2) + { + rightColumnECData = codewords[next]; + if (rightColumnECData == leftColumnECData && leftColumnECData != 0) + { + ecLevel = ((rightColumnECData % 30) - rows % 3) / 3; + } + } + codewords[next] = 0; } return next; + } + + /// + /// Translate the symbol into a codeword. + /// + /// the codeword corresponding to the symbol. + private static int getCodeword(long symbol) + { + long sym = symbol & 0x3FFFF; + int i = findCodewordIndex(sym); + if (i == -1) + { + return -1; } - */ - - /// The sorted table of all possible symbols. Extracted from the PDF417 - /// specification. The index of a symbol in this table corresponds to the - /// index into the codeword table. - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'SYMBOL_TABLE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] SYMBOL_TABLE = new int[]{0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac, 0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482, 0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e, 0x10520, 0x1053c, 0x10540, 0x10578, 0x10586, 0x1058c, 0x10598, 0x105b0, 0x105be, 0x105ce, 0x105dc, 0x105e2, 0x105e4, 0x105e8, 0x105f6, 0x1062e, 0x1064e, 0x1065c, 0x1068e, 0x1069c, 0x106b8, 0x106de, 0x106fa, 0x10716, 0x10726, 0x1072c, 0x10746, 0x1074c, 0x10758, 0x1076e, 0x10792, 0x10794, 0x107a2, 0x107a4, 0x107a8, 0x107b6, 0x10822, 0x10828, 0x10842, 0x10848, 0x10850, 0x1085e, 0x10866, 0x1086c, 0x1087a, 0x10882, 0x10884, 0x10890, 0x1089e, 0x108a0, 0x108bc, 0x108c6, 0x108cc, 0x108d8, 0x108ee, 0x108f2, 0x108f4, 0x10902, 0x10908, 0x1091e, 0x10920, 0x1093c, 0x10940, 0x10978, 0x10986, 0x10998, 0x109b0, 0x109be, 0x109ce, 0x109dc, 0x109e2, 0x109e4, 0x109e8, 0x109f6, 0x10a08, 0x10a10, 0x10a1e, 0x10a20, 0x10a3c, 0x10a40, 0x10a78, 0x10af0, 0x10b06, 0x10b0c, 0x10b18, 0x10b30, 0x10b3e, 0x10b60, 0x10b7c, 0x10b8e, 0x10b9c, 0x10bb8, 0x10bc2, 0x10bc4, 0x10bc8, 0x10bd0, 0x10bde, 0x10be6, 0x10bec, 0x10c2e, 0x10c4e, 0x10c5c, 0x10c62, 0x10c64, 0x10c68, 0x10c76, 0x10c8e, 0x10c9c, 0x10cb8, 0x10cc2, 0x10cc4, 0x10cc8, 0x10cd0, 0x10cde, 0x10ce6, 0x10cec, 0x10cfa, 0x10d0e, 0x10d1c, 0x10d38, 0x10d70, 0x10d7e, 0x10d82, 0x10d84, 0x10d88, 0x10d90, 0x10d9e, 0x10da0, 0x10dbc, 0x10dc6, 0x10dcc, 0x10dd8, 0x10dee, 0x10df2, 0x10df4, 0x10e16, 0x10e26, 0x10e2c, 0x10e46, 0x10e58, 0x10e6e, 0x10e86, 0x10e8c, 0x10e98, 0x10eb0, 0x10ebe, 0x10ece, 0x10edc, 0x10f0a, 0x10f12, 0x10f14, 0x10f22, 0x10f28, 0x10f36, 0x10f42, 0x10f44, 0x10f48, 0x10f50, 0x10f5e, 0x10f66, 0x10f6c, 0x10fb2, 0x10fb4, 0x11022, 0x11028, 0x11042, 0x11048, 0x11050, 0x1105e, 0x1107a, 0x11082, 0x11084, 0x11090, 0x1109e, 0x110a0, 0x110bc, 0x110c6, 0x110cc, 0x110d8, 0x110ee, 0x110f2, 0x110f4, 0x11102, 0x1111e, - 0x11120, 0x1113c, 0x11140, 0x11178, 0x11186, 0x11198, 0x111b0, 0x111be, 0x111ce, 0x111dc, 0x111e2, 0x111e4, 0x111e8, 0x111f6, 0x11208, 0x1121e, 0x11220, 0x11278, 0x112f0, 0x1130c, 0x11330, 0x1133e, 0x11360, 0x1137c, 0x1138e, 0x1139c, 0x113b8, 0x113c2, 0x113c8, 0x113d0, 0x113de, 0x113e6, 0x113ec, 0x11408, 0x11410, 0x1141e, 0x11420, 0x1143c, 0x11440, 0x11478, 0x114f0, 0x115e0, 0x1160c, 0x11618, 0x11630, 0x1163e, 0x11660, 0x1167c, 0x116c0, 0x116f8, 0x1171c, 0x11738, 0x11770, 0x1177e, 0x11782, 0x11784, 0x11788, 0x11790, 0x1179e, 0x117a0, 0x117bc, 0x117c6, 0x117cc, 0x117d8, 0x117ee, 0x1182e, 0x11834, 0x1184e, 0x1185c, 0x11862, 0x11864, 0x11868, 0x11876, 0x1188e, 0x1189c, 0x118b8, 0x118c2, 0x118c8, 0x118d0, 0x118de, 0x118e6, 0x118ec, 0x118fa, 0x1190e, 0x1191c, 0x11938, 0x11970, 0x1197e, 0x11982, 0x11984, 0x11990, 0x1199e, 0x119a0, 0x119bc, 0x119c6, 0x119cc, 0x119d8, 0x119ee, 0x119f2, 0x119f4, 0x11a0e, 0x11a1c, 0x11a38, 0x11a70, 0x11a7e, 0x11ae0, 0x11afc, 0x11b08, 0x11b10, 0x11b1e, 0x11b20, 0x11b3c, 0x11b40, 0x11b78, 0x11b8c, 0x11b98, 0x11bb0, 0x11bbe, 0x11bce, 0x11bdc, 0x11be2, 0x11be4, 0x11be8, 0x11bf6, 0x11c16, 0x11c26, 0x11c2c, 0x11c46, 0x11c4c, 0x11c58, 0x11c6e, 0x11c86, 0x11c98, 0x11cb0, 0x11cbe, 0x11cce, 0x11cdc, 0x11ce2, 0x11ce4, 0x11ce8, 0x11cf6, 0x11d06, 0x11d0c, 0x11d18, 0x11d30, 0x11d3e, 0x11d60, 0x11d7c, 0x11d8e, 0x11d9c, 0x11db8, 0x11dc4, 0x11dc8, 0x11dd0, 0x11dde, 0x11de6, 0x11dec, 0x11dfa, 0x11e0a, 0x11e12, 0x11e14, 0x11e22, 0x11e24, 0x11e28, 0x11e36, 0x11e42, 0x11e44, 0x11e50, 0x11e5e, 0x11e66, 0x11e6c, 0x11e82, 0x11e84, 0x11e88, 0x11e90, 0x11e9e, 0x11ea0, 0x11ebc, 0x11ec6, 0x11ecc, 0x11ed8, 0x11eee, 0x11f1a, 0x11f2e, 0x11f32, 0x11f34, 0x11f4e, 0x11f5c, 0x11f62, 0x11f64, 0x11f68, 0x11f76, 0x12048, 0x1205e, 0x12082, 0x12084, 0x12090, 0x1209e, 0x120a0, 0x120bc, 0x120d8, 0x120f2, 0x120f4, 0x12108, 0x1211e, 0x12120, 0x1213c, 0x12140, 0x12178, 0x12186, 0x12198, 0x121b0, 0x121be, 0x121e2, 0x121e4, 0x121e8, 0x121f6, 0x12204, 0x12210, 0x1221e, 0x12220, 0x12278, 0x122f0, 0x12306, 0x1230c, - 0x12330, 0x1233e, 0x12360, 0x1237c, 0x1238e, 0x1239c, 0x123b8, 0x123c2, 0x123c8, 0x123d0, 0x123e6, 0x123ec, 0x1241e, 0x12420, 0x1243c, 0x124f0, 0x125e0, 0x12618, 0x1263e, 0x12660, 0x1267c, 0x126c0, 0x126f8, 0x12738, 0x12770, 0x1277e, 0x12782, 0x12784, 0x12790, 0x1279e, 0x127a0, 0x127bc, 0x127c6, 0x127cc, 0x127d8, 0x127ee, 0x12820, 0x1283c, 0x12840, 0x12878, 0x128f0, 0x129e0, 0x12bc0, 0x12c18, 0x12c30, 0x12c3e, 0x12c60, 0x12c7c, 0x12cc0, 0x12cf8, 0x12df0, 0x12e1c, 0x12e38, 0x12e70, 0x12e7e, 0x12ee0, 0x12efc, 0x12f04, 0x12f08, 0x12f10, 0x12f20, 0x12f3c, 0x12f40, 0x12f78, 0x12f86, 0x12f8c, 0x12f98, 0x12fb0, 0x12fbe, 0x12fce, 0x12fdc, 0x1302e, 0x1304e, 0x1305c, 0x13062, 0x13068, 0x1308e, 0x1309c, 0x130b8, 0x130c2, 0x130c8, 0x130d0, 0x130de, 0x130ec, 0x130fa, 0x1310e, 0x13138, 0x13170, 0x1317e, 0x13182, 0x13184, 0x13190, 0x1319e, 0x131a0, 0x131bc, 0x131c6, 0x131cc, 0x131d8, 0x131f2, 0x131f4, 0x1320e, 0x1321c, 0x13270, 0x1327e, 0x132e0, 0x132fc, 0x13308, 0x1331e, 0x13320, 0x1333c, 0x13340, 0x13378, 0x13386, 0x13398, 0x133b0, 0x133be, 0x133ce, 0x133dc, 0x133e2, 0x133e4, 0x133e8, 0x133f6, 0x1340e, 0x1341c, 0x13438, 0x13470, 0x1347e, 0x134e0, 0x134fc, 0x135c0, 0x135f8, 0x13608, 0x13610, 0x1361e, 0x13620, 0x1363c, 0x13640, 0x13678, 0x136f0, 0x1370c, 0x13718, 0x13730, 0x1373e, 0x13760, 0x1377c, 0x1379c, 0x137b8, 0x137c2, 0x137c4, 0x137c8, 0x137d0, 0x137de, 0x137e6, 0x137ec, 0x13816, 0x13826, 0x1382c, 0x13846, 0x1384c, 0x13858, 0x1386e, 0x13874, 0x13886, 0x13898, 0x138b0, 0x138be, 0x138ce, 0x138dc, 0x138e2, 0x138e4, 0x138e8, 0x13906, 0x1390c, 0x13930, 0x1393e, 0x13960, 0x1397c, 0x1398e, 0x1399c, 0x139b8, 0x139c8, 0x139d0, 0x139de, 0x139e6, 0x139ec, 0x139fa, 0x13a06, 0x13a0c, 0x13a18, 0x13a30, 0x13a3e, 0x13a60, 0x13a7c, 0x13ac0, 0x13af8, 0x13b0e, 0x13b1c, 0x13b38, 0x13b70, 0x13b7e, 0x13b88, 0x13b90, 0x13b9e, 0x13ba0, 0x13bbc, 0x13bcc, 0x13bd8, 0x13bee, 0x13bf2, 0x13bf4, 0x13c12, 0x13c14, 0x13c22, 0x13c24, 0x13c28, 0x13c36, 0x13c42, 0x13c48, 0x13c50, 0x13c5e, 0x13c66, 0x13c6c, 0x13c82, 0x13c84, 0x13c90, - 0x13c9e, 0x13ca0, 0x13cbc, 0x13cc6, 0x13ccc, 0x13cd8, 0x13cee, 0x13d02, 0x13d04, 0x13d08, 0x13d10, 0x13d1e, 0x13d20, 0x13d3c, 0x13d40, 0x13d78, 0x13d86, 0x13d8c, 0x13d98, 0x13db0, 0x13dbe, 0x13dce, 0x13ddc, 0x13de4, 0x13de8, 0x13df6, 0x13e1a, 0x13e2e, 0x13e32, 0x13e34, 0x13e4e, 0x13e5c, 0x13e62, 0x13e64, 0x13e68, 0x13e76, 0x13e8e, 0x13e9c, 0x13eb8, 0x13ec2, 0x13ec4, 0x13ec8, 0x13ed0, 0x13ede, 0x13ee6, 0x13eec, 0x13f26, 0x13f2c, 0x13f3a, 0x13f46, 0x13f4c, 0x13f58, 0x13f6e, 0x13f72, 0x13f74, 0x14082, 0x1409e, 0x140a0, 0x140bc, 0x14104, 0x14108, 0x14110, 0x1411e, 0x14120, 0x1413c, 0x14140, 0x14178, 0x1418c, 0x14198, 0x141b0, 0x141be, 0x141e2, 0x141e4, 0x141e8, 0x14208, 0x14210, 0x1421e, 0x14220, 0x1423c, 0x14240, 0x14278, 0x142f0, 0x14306, 0x1430c, 0x14318, 0x14330, 0x1433e, 0x14360, 0x1437c, 0x1438e, 0x143c2, 0x143c4, 0x143c8, 0x143d0, 0x143e6, 0x143ec, 0x14408, 0x14410, 0x1441e, 0x14420, 0x1443c, 0x14440, 0x14478, 0x144f0, 0x145e0, 0x1460c, 0x14618, 0x14630, 0x1463e, 0x14660, 0x1467c, 0x146c0, 0x146f8, 0x1471c, 0x14738, 0x14770, 0x1477e, 0x14782, 0x14784, 0x14788, 0x14790, 0x147a0, 0x147bc, 0x147c6, 0x147cc, 0x147d8, 0x147ee, 0x14810, 0x14820, 0x1483c, 0x14840, 0x14878, 0x148f0, 0x149e0, 0x14bc0, 0x14c30, 0x14c3e, 0x14c60, 0x14c7c, 0x14cc0, 0x14cf8, 0x14df0, 0x14e38, 0x14e70, 0x14e7e, 0x14ee0, 0x14efc, 0x14f04, 0x14f08, 0x14f10, 0x14f1e, 0x14f20, 0x14f3c, 0x14f40, 0x14f78, 0x14f86, 0x14f8c, 0x14f98, 0x14fb0, 0x14fce, 0x14fdc, 0x15020, 0x15040, 0x15078, 0x150f0, 0x151e0, 0x153c0, 0x15860, 0x1587c, 0x158c0, 0x158f8, 0x159f0, 0x15be0, 0x15c70, 0x15c7e, 0x15ce0, 0x15cfc, 0x15dc0, 0x15df8, 0x15e08, 0x15e10, 0x15e20, 0x15e40, 0x15e78, 0x15ef0, 0x15f0c, 0x15f18, 0x15f30, 0x15f60, 0x15f7c, 0x15f8e, 0x15f9c, 0x15fb8, 0x1604e, 0x1605c, 0x1608e, 0x1609c, 0x160b8, 0x160c2, 0x160c4, 0x160c8, 0x160de, 0x1610e, 0x1611c, 0x16138, 0x16170, 0x1617e, 0x16184, 0x16188, 0x16190, 0x1619e, 0x161a0, 0x161bc, 0x161c6, 0x161cc, 0x161d8, 0x161f2, 0x161f4, 0x1620e, 0x1621c, 0x16238, 0x16270, 0x1627e, 0x162e0, 0x162fc, - 0x16304, 0x16308, 0x16310, 0x1631e, 0x16320, 0x1633c, 0x16340, 0x16378, 0x16386, 0x1638c, 0x16398, 0x163b0, 0x163be, 0x163ce, 0x163dc, 0x163e2, 0x163e4, 0x163e8, 0x163f6, 0x1640e, 0x1641c, 0x16438, 0x16470, 0x1647e, 0x164e0, 0x164fc, 0x165c0, 0x165f8, 0x16610, 0x1661e, 0x16620, 0x1663c, 0x16640, 0x16678, 0x166f0, 0x16718, 0x16730, 0x1673e, 0x16760, 0x1677c, 0x1678e, 0x1679c, 0x167b8, 0x167c2, 0x167c4, 0x167c8, 0x167d0, 0x167de, 0x167e6, 0x167ec, 0x1681c, 0x16838, 0x16870, 0x168e0, 0x168fc, 0x169c0, 0x169f8, 0x16bf0, 0x16c10, 0x16c1e, 0x16c20, 0x16c3c, 0x16c40, 0x16c78, 0x16cf0, 0x16de0, 0x16e18, 0x16e30, 0x16e3e, 0x16e60, 0x16e7c, 0x16ec0, 0x16ef8, 0x16f1c, 0x16f38, 0x16f70, 0x16f7e, 0x16f84, 0x16f88, 0x16f90, 0x16f9e, 0x16fa0, 0x16fbc, 0x16fc6, 0x16fcc, 0x16fd8, 0x17026, 0x1702c, 0x17046, 0x1704c, 0x17058, 0x1706e, 0x17086, 0x1708c, 0x17098, 0x170b0, 0x170be, 0x170ce, 0x170dc, 0x170e8, 0x17106, 0x1710c, 0x17118, 0x17130, 0x1713e, 0x17160, 0x1717c, 0x1718e, 0x1719c, 0x171b8, 0x171c2, 0x171c4, 0x171c8, 0x171d0, 0x171de, 0x171e6, 0x171ec, 0x171fa, 0x17206, 0x1720c, 0x17218, 0x17230, 0x1723e, 0x17260, 0x1727c, 0x172c0, 0x172f8, 0x1730e, 0x1731c, 0x17338, 0x17370, 0x1737e, 0x17388, 0x17390, 0x1739e, 0x173a0, 0x173bc, 0x173cc, 0x173d8, 0x173ee, 0x173f2, 0x173f4, 0x1740c, 0x17418, 0x17430, 0x1743e, 0x17460, 0x1747c, 0x174c0, 0x174f8, 0x175f0, 0x1760e, 0x1761c, 0x17638, 0x17670, 0x1767e, 0x176e0, 0x176fc, 0x17708, 0x17710, 0x1771e, 0x17720, 0x1773c, 0x17740, 0x17778, 0x17798, 0x177b0, 0x177be, 0x177dc, 0x177e2, 0x177e4, 0x177e8, 0x17822, 0x17824, 0x17828, 0x17836, 0x17842, 0x17844, 0x17848, 0x17850, 0x1785e, 0x17866, 0x1786c, 0x17882, 0x17884, 0x17888, 0x17890, 0x1789e, 0x178a0, 0x178bc, 0x178c6, 0x178cc, 0x178d8, 0x178ee, 0x178f2, 0x178f4, 0x17902, 0x17904, 0x17908, 0x17910, 0x1791e, 0x17920, 0x1793c, 0x17940, 0x17978, 0x17986, 0x1798c, 0x17998, 0x179b0, 0x179be, 0x179ce, 0x179dc, 0x179e2, 0x179e4, 0x179e8, 0x179f6, 0x17a04, 0x17a08, 0x17a10, 0x17a1e, 0x17a20, 0x17a3c, 0x17a40, 0x17a78, 0x17af0, - 0x17b06, 0x17b0c, 0x17b18, 0x17b30, 0x17b3e, 0x17b60, 0x17b7c, 0x17b8e, 0x17b9c, 0x17bb8, 0x17bc4, 0x17bc8, 0x17bd0, 0x17bde, 0x17be6, 0x17bec, 0x17c2e, 0x17c32, 0x17c34, 0x17c4e, 0x17c5c, 0x17c62, 0x17c64, 0x17c68, 0x17c76, 0x17c8e, 0x17c9c, 0x17cb8, 0x17cc2, 0x17cc4, 0x17cc8, 0x17cd0, 0x17cde, 0x17ce6, 0x17cec, 0x17d0e, 0x17d1c, 0x17d38, 0x17d70, 0x17d82, 0x17d84, 0x17d88, 0x17d90, 0x17d9e, 0x17da0, 0x17dbc, 0x17dc6, 0x17dcc, 0x17dd8, 0x17dee, 0x17e26, 0x17e2c, 0x17e3a, 0x17e46, 0x17e4c, 0x17e58, 0x17e6e, 0x17e72, 0x17e74, 0x17e86, 0x17e8c, 0x17e98, 0x17eb0, 0x17ece, 0x17edc, 0x17ee2, 0x17ee4, 0x17ee8, 0x17ef6, 0x1813a, 0x18172, 0x18174, 0x18216, 0x18226, 0x1823a, 0x1824c, 0x18258, 0x1826e, 0x18272, 0x18274, 0x18298, 0x182be, 0x182e2, 0x182e4, 0x182e8, 0x182f6, 0x1835e, 0x1837a, 0x183ae, 0x183d6, 0x18416, 0x18426, 0x1842c, 0x1843a, 0x18446, 0x18458, 0x1846e, 0x18472, 0x18474, 0x18486, 0x184b0, 0x184be, 0x184ce, 0x184dc, 0x184e2, 0x184e4, 0x184e8, 0x184f6, 0x18506, 0x1850c, 0x18518, 0x18530, 0x1853e, 0x18560, 0x1857c, 0x1858e, 0x1859c, 0x185b8, 0x185c2, 0x185c4, 0x185c8, 0x185d0, 0x185de, 0x185e6, 0x185ec, 0x185fa, 0x18612, 0x18614, 0x18622, 0x18628, 0x18636, 0x18642, 0x18650, 0x1865e, 0x1867a, 0x18682, 0x18684, 0x18688, 0x18690, 0x1869e, 0x186a0, 0x186bc, 0x186c6, 0x186cc, 0x186d8, 0x186ee, 0x186f2, 0x186f4, 0x1872e, 0x1874e, 0x1875c, 0x18796, 0x187a6, 0x187ac, 0x187d2, 0x187d4, 0x18826, 0x1882c, 0x1883a, 0x18846, 0x1884c, 0x18858, 0x1886e, 0x18872, 0x18874, 0x18886, 0x18898, 0x188b0, 0x188be, 0x188ce, 0x188dc, 0x188e2, 0x188e4, 0x188e8, 0x188f6, 0x1890c, 0x18930, 0x1893e, 0x18960, 0x1897c, 0x1898e, 0x189b8, 0x189c2, 0x189c8, 0x189d0, 0x189de, 0x189e6, 0x189ec, 0x189fa, 0x18a18, 0x18a30, 0x18a3e, 0x18a60, 0x18a7c, 0x18ac0, 0x18af8, 0x18b1c, 0x18b38, 0x18b70, 0x18b7e, 0x18b82, 0x18b84, 0x18b88, 0x18b90, 0x18b9e, 0x18ba0, 0x18bbc, 0x18bc6, 0x18bcc, 0x18bd8, 0x18bee, 0x18bf2, 0x18bf4, 0x18c22, 0x18c24, 0x18c28, 0x18c36, 0x18c42, 0x18c48, 0x18c50, 0x18c5e, 0x18c66, 0x18c7a, 0x18c82, 0x18c84, - 0x18c90, 0x18c9e, 0x18ca0, 0x18cbc, 0x18ccc, 0x18cf2, 0x18cf4, 0x18d04, 0x18d08, 0x18d10, 0x18d1e, 0x18d20, 0x18d3c, 0x18d40, 0x18d78, 0x18d86, 0x18d98, 0x18dce, 0x18de2, 0x18de4, 0x18de8, 0x18e2e, 0x18e32, 0x18e34, 0x18e4e, 0x18e5c, 0x18e62, 0x18e64, 0x18e68, 0x18e8e, 0x18e9c, 0x18eb8, 0x18ec2, 0x18ec4, 0x18ec8, 0x18ed0, 0x18efa, 0x18f16, 0x18f26, 0x18f2c, 0x18f46, 0x18f4c, 0x18f58, 0x18f6e, 0x18f8a, 0x18f92, 0x18f94, 0x18fa2, 0x18fa4, 0x18fa8, 0x18fb6, 0x1902c, 0x1903a, 0x19046, 0x1904c, 0x19058, 0x19072, 0x19074, 0x19086, 0x19098, 0x190b0, 0x190be, 0x190ce, 0x190dc, 0x190e2, 0x190e8, 0x190f6, 0x19106, 0x1910c, 0x19130, 0x1913e, 0x19160, 0x1917c, 0x1918e, 0x1919c, 0x191b8, 0x191c2, 0x191c8, 0x191d0, 0x191de, 0x191e6, 0x191ec, 0x191fa, 0x19218, 0x1923e, 0x19260, 0x1927c, 0x192c0, 0x192f8, 0x19338, 0x19370, 0x1937e, 0x19382, 0x19384, 0x19390, 0x1939e, 0x193a0, 0x193bc, 0x193c6, 0x193cc, 0x193d8, 0x193ee, 0x193f2, 0x193f4, 0x19430, 0x1943e, 0x19460, 0x1947c, 0x194c0, 0x194f8, 0x195f0, 0x19638, 0x19670, 0x1967e, 0x196e0, 0x196fc, 0x19702, 0x19704, 0x19708, 0x19710, 0x19720, 0x1973c, 0x19740, 0x19778, 0x19786, 0x1978c, 0x19798, 0x197b0, 0x197be, 0x197ce, 0x197dc, 0x197e2, 0x197e4, 0x197e8, 0x19822, 0x19824, 0x19842, 0x19848, 0x19850, 0x1985e, 0x19866, 0x1987a, 0x19882, 0x19884, 0x19890, 0x1989e, 0x198a0, 0x198bc, 0x198cc, 0x198f2, 0x198f4, 0x19902, 0x19908, 0x1991e, 0x19920, 0x1993c, 0x19940, 0x19978, 0x19986, 0x19998, 0x199ce, 0x199e2, 0x199e4, 0x199e8, 0x19a08, 0x19a10, 0x19a1e, 0x19a20, 0x19a3c, 0x19a40, 0x19a78, 0x19af0, 0x19b18, 0x19b3e, 0x19b60, 0x19b9c, 0x19bc2, 0x19bc4, 0x19bc8, 0x19bd0, 0x19be6, 0x19c2e, 0x19c34, 0x19c4e, 0x19c5c, 0x19c62, 0x19c64, 0x19c68, 0x19c8e, 0x19c9c, 0x19cb8, 0x19cc2, 0x19cc8, 0x19cd0, 0x19ce6, 0x19cfa, 0x19d0e, 0x19d1c, 0x19d38, 0x19d70, 0x19d7e, 0x19d82, 0x19d84, 0x19d88, 0x19d90, 0x19da0, 0x19dcc, 0x19df2, 0x19df4, 0x19e16, 0x19e26, 0x19e2c, 0x19e46, 0x19e4c, 0x19e58, 0x19e74, 0x19e86, 0x19e8c, 0x19e98, 0x19eb0, 0x19ebe, 0x19ece, 0x19ee2, 0x19ee4, 0x19ee8, - 0x19f0a, 0x19f12, 0x19f14, 0x19f22, 0x19f24, 0x19f28, 0x19f42, 0x19f44, 0x19f48, 0x19f50, 0x19f5e, 0x19f6c, 0x19f9a, 0x19fae, 0x19fb2, 0x19fb4, 0x1a046, 0x1a04c, 0x1a072, 0x1a074, 0x1a086, 0x1a08c, 0x1a098, 0x1a0b0, 0x1a0be, 0x1a0e2, 0x1a0e4, 0x1a0e8, 0x1a0f6, 0x1a106, 0x1a10c, 0x1a118, 0x1a130, 0x1a13e, 0x1a160, 0x1a17c, 0x1a18e, 0x1a19c, 0x1a1b8, 0x1a1c2, 0x1a1c4, 0x1a1c8, 0x1a1d0, 0x1a1de, 0x1a1e6, 0x1a1ec, 0x1a218, 0x1a230, 0x1a23e, 0x1a260, 0x1a27c, 0x1a2c0, 0x1a2f8, 0x1a31c, 0x1a338, 0x1a370, 0x1a37e, 0x1a382, 0x1a384, 0x1a388, 0x1a390, 0x1a39e, 0x1a3a0, 0x1a3bc, 0x1a3c6, 0x1a3cc, 0x1a3d8, 0x1a3ee, 0x1a3f2, 0x1a3f4, 0x1a418, 0x1a430, 0x1a43e, 0x1a460, 0x1a47c, 0x1a4c0, 0x1a4f8, 0x1a5f0, 0x1a61c, 0x1a638, 0x1a670, 0x1a67e, 0x1a6e0, 0x1a6fc, 0x1a702, 0x1a704, 0x1a708, 0x1a710, 0x1a71e, 0x1a720, 0x1a73c, 0x1a740, 0x1a778, 0x1a786, 0x1a78c, 0x1a798, 0x1a7b0, 0x1a7be, 0x1a7ce, 0x1a7dc, 0x1a7e2, 0x1a7e4, 0x1a7e8, 0x1a830, 0x1a860, 0x1a87c, 0x1a8c0, 0x1a8f8, 0x1a9f0, 0x1abe0, 0x1ac70, 0x1ac7e, 0x1ace0, 0x1acfc, 0x1adc0, 0x1adf8, 0x1ae04, 0x1ae08, 0x1ae10, 0x1ae20, 0x1ae3c, 0x1ae40, 0x1ae78, 0x1aef0, 0x1af06, 0x1af0c, 0x1af18, 0x1af30, 0x1af3e, 0x1af60, 0x1af7c, 0x1af8e, 0x1af9c, 0x1afb8, 0x1afc4, 0x1afc8, 0x1afd0, 0x1afde, 0x1b042, 0x1b05e, 0x1b07a, 0x1b082, 0x1b084, 0x1b088, 0x1b090, 0x1b09e, 0x1b0a0, 0x1b0bc, 0x1b0cc, 0x1b0f2, 0x1b0f4, 0x1b102, 0x1b104, 0x1b108, 0x1b110, 0x1b11e, 0x1b120, 0x1b13c, 0x1b140, 0x1b178, 0x1b186, 0x1b198, 0x1b1ce, 0x1b1e2, 0x1b1e4, 0x1b1e8, 0x1b204, 0x1b208, 0x1b210, 0x1b21e, 0x1b220, 0x1b23c, 0x1b240, 0x1b278, 0x1b2f0, 0x1b30c, 0x1b33e, 0x1b360, 0x1b39c, 0x1b3c2, 0x1b3c4, 0x1b3c8, 0x1b3d0, 0x1b3e6, 0x1b410, 0x1b41e, 0x1b420, 0x1b43c, 0x1b440, 0x1b478, 0x1b4f0, 0x1b5e0, 0x1b618, 0x1b660, 0x1b67c, 0x1b6c0, 0x1b738, 0x1b782, 0x1b784, 0x1b788, 0x1b790, 0x1b79e, 0x1b7a0, 0x1b7cc, 0x1b82e, 0x1b84e, 0x1b85c, 0x1b88e, 0x1b89c, 0x1b8b8, 0x1b8c2, 0x1b8c4, 0x1b8c8, 0x1b8d0, 0x1b8e6, 0x1b8fa, 0x1b90e, 0x1b91c, 0x1b938, 0x1b970, 0x1b97e, 0x1b982, 0x1b984, 0x1b988, 0x1b990, - 0x1b99e, 0x1b9a0, 0x1b9cc, 0x1b9f2, 0x1b9f4, 0x1ba0e, 0x1ba1c, 0x1ba38, 0x1ba70, 0x1ba7e, 0x1bae0, 0x1bafc, 0x1bb08, 0x1bb10, 0x1bb20, 0x1bb3c, 0x1bb40, 0x1bb98, 0x1bbce, 0x1bbe2, 0x1bbe4, 0x1bbe8, 0x1bc16, 0x1bc26, 0x1bc2c, 0x1bc46, 0x1bc4c, 0x1bc58, 0x1bc72, 0x1bc74, 0x1bc86, 0x1bc8c, 0x1bc98, 0x1bcb0, 0x1bcbe, 0x1bcce, 0x1bce2, 0x1bce4, 0x1bce8, 0x1bd06, 0x1bd0c, 0x1bd18, 0x1bd30, 0x1bd3e, 0x1bd60, 0x1bd7c, 0x1bd9c, 0x1bdc2, 0x1bdc4, 0x1bdc8, 0x1bdd0, 0x1bde6, 0x1bdfa, 0x1be12, 0x1be14, 0x1be22, 0x1be24, 0x1be28, 0x1be42, 0x1be44, 0x1be48, 0x1be50, 0x1be5e, 0x1be66, 0x1be82, 0x1be84, 0x1be88, 0x1be90, 0x1be9e, 0x1bea0, 0x1bebc, 0x1becc, 0x1bef4, 0x1bf1a, 0x1bf2e, 0x1bf32, 0x1bf34, 0x1bf4e, 0x1bf5c, 0x1bf62, 0x1bf64, 0x1bf68, 0x1c09a, 0x1c0b2, 0x1c0b4, 0x1c11a, 0x1c132, 0x1c134, 0x1c162, 0x1c164, 0x1c168, 0x1c176, 0x1c1ba, 0x1c21a, 0x1c232, 0x1c234, 0x1c24e, 0x1c25c, 0x1c262, 0x1c264, 0x1c268, 0x1c276, 0x1c28e, 0x1c2c2, 0x1c2c4, 0x1c2c8, 0x1c2d0, 0x1c2de, 0x1c2e6, 0x1c2ec, 0x1c2fa, 0x1c316, 0x1c326, 0x1c33a, 0x1c346, 0x1c34c, 0x1c372, 0x1c374, 0x1c41a, 0x1c42e, 0x1c432, 0x1c434, 0x1c44e, 0x1c45c, 0x1c462, 0x1c464, 0x1c468, 0x1c476, 0x1c48e, 0x1c49c, 0x1c4b8, 0x1c4c2, 0x1c4c8, 0x1c4d0, 0x1c4de, 0x1c4e6, 0x1c4ec, 0x1c4fa, 0x1c51c, 0x1c538, 0x1c570, 0x1c57e, 0x1c582, 0x1c584, 0x1c588, 0x1c590, 0x1c59e, 0x1c5a0, 0x1c5bc, 0x1c5c6, 0x1c5cc, 0x1c5d8, 0x1c5ee, 0x1c5f2, 0x1c5f4, 0x1c616, 0x1c626, 0x1c62c, 0x1c63a, 0x1c646, 0x1c64c, 0x1c658, 0x1c66e, 0x1c672, 0x1c674, 0x1c686, 0x1c68c, 0x1c698, 0x1c6b0, 0x1c6be, 0x1c6ce, 0x1c6dc, 0x1c6e2, 0x1c6e4, 0x1c6e8, 0x1c712, 0x1c714, 0x1c722, 0x1c728, 0x1c736, 0x1c742, 0x1c744, 0x1c748, 0x1c750, 0x1c75e, 0x1c766, 0x1c76c, 0x1c77a, 0x1c7ae, 0x1c7d6, 0x1c7ea, 0x1c81a, 0x1c82e, 0x1c832, 0x1c834, 0x1c84e, 0x1c85c, 0x1c862, 0x1c864, 0x1c868, 0x1c876, 0x1c88e, 0x1c89c, 0x1c8b8, 0x1c8c2, 0x1c8c8, 0x1c8d0, 0x1c8de, 0x1c8e6, 0x1c8ec, 0x1c8fa, 0x1c90e, 0x1c938, 0x1c970, 0x1c97e, 0x1c982, 0x1c984, 0x1c990, 0x1c99e, 0x1c9a0, 0x1c9bc, 0x1c9c6, 0x1c9cc, 0x1c9d8, 0x1c9ee, - 0x1c9f2, 0x1c9f4, 0x1ca38, 0x1ca70, 0x1ca7e, 0x1cae0, 0x1cafc, 0x1cb02, 0x1cb04, 0x1cb08, 0x1cb10, 0x1cb20, 0x1cb3c, 0x1cb40, 0x1cb78, 0x1cb86, 0x1cb8c, 0x1cb98, 0x1cbb0, 0x1cbbe, 0x1cbce, 0x1cbdc, 0x1cbe2, 0x1cbe4, 0x1cbe8, 0x1cbf6, 0x1cc16, 0x1cc26, 0x1cc2c, 0x1cc3a, 0x1cc46, 0x1cc58, 0x1cc72, 0x1cc74, 0x1cc86, 0x1ccb0, 0x1ccbe, 0x1ccce, 0x1cce2, 0x1cce4, 0x1cce8, 0x1cd06, 0x1cd0c, 0x1cd18, 0x1cd30, 0x1cd3e, 0x1cd60, 0x1cd7c, 0x1cd9c, 0x1cdc2, 0x1cdc4, 0x1cdc8, 0x1cdd0, 0x1cdde, 0x1cde6, 0x1cdfa, 0x1ce22, 0x1ce28, 0x1ce42, 0x1ce50, 0x1ce5e, 0x1ce66, 0x1ce7a, 0x1ce82, 0x1ce84, 0x1ce88, 0x1ce90, 0x1ce9e, 0x1cea0, 0x1cebc, 0x1cecc, 0x1cef2, 0x1cef4, 0x1cf2e, 0x1cf32, 0x1cf34, 0x1cf4e, 0x1cf5c, 0x1cf62, 0x1cf64, 0x1cf68, 0x1cf96, 0x1cfa6, 0x1cfac, 0x1cfca, 0x1cfd2, 0x1cfd4, 0x1d02e, 0x1d032, 0x1d034, 0x1d04e, 0x1d05c, 0x1d062, 0x1d064, 0x1d068, 0x1d076, 0x1d08e, 0x1d09c, 0x1d0b8, 0x1d0c2, 0x1d0c4, 0x1d0c8, 0x1d0d0, 0x1d0de, 0x1d0e6, 0x1d0ec, 0x1d0fa, 0x1d11c, 0x1d138, 0x1d170, 0x1d17e, 0x1d182, 0x1d184, 0x1d188, 0x1d190, 0x1d19e, 0x1d1a0, 0x1d1bc, 0x1d1c6, 0x1d1cc, 0x1d1d8, 0x1d1ee, 0x1d1f2, 0x1d1f4, 0x1d21c, 0x1d238, 0x1d270, 0x1d27e, 0x1d2e0, 0x1d2fc, 0x1d302, 0x1d304, 0x1d308, 0x1d310, 0x1d31e, 0x1d320, 0x1d33c, 0x1d340, 0x1d378, 0x1d386, 0x1d38c, 0x1d398, 0x1d3b0, 0x1d3be, 0x1d3ce, 0x1d3dc, 0x1d3e2, 0x1d3e4, 0x1d3e8, 0x1d3f6, 0x1d470, 0x1d47e, 0x1d4e0, 0x1d4fc, 0x1d5c0, 0x1d5f8, 0x1d604, 0x1d608, 0x1d610, 0x1d620, 0x1d640, 0x1d678, 0x1d6f0, 0x1d706, 0x1d70c, 0x1d718, 0x1d730, 0x1d73e, 0x1d760, 0x1d77c, 0x1d78e, 0x1d79c, 0x1d7b8, 0x1d7c2, 0x1d7c4, 0x1d7c8, 0x1d7d0, 0x1d7de, 0x1d7e6, 0x1d7ec, 0x1d826, 0x1d82c, 0x1d83a, 0x1d846, 0x1d84c, 0x1d858, 0x1d872, 0x1d874, 0x1d886, 0x1d88c, 0x1d898, 0x1d8b0, 0x1d8be, 0x1d8ce, 0x1d8e2, 0x1d8e4, 0x1d8e8, 0x1d8f6, 0x1d90c, 0x1d918, 0x1d930, 0x1d93e, 0x1d960, 0x1d97c, 0x1d99c, 0x1d9c2, 0x1d9c4, 0x1d9c8, 0x1d9d0, 0x1d9e6, 0x1d9fa, 0x1da0c, 0x1da18, 0x1da30, 0x1da3e, 0x1da60, 0x1da7c, 0x1dac0, 0x1daf8, 0x1db38, 0x1db82, 0x1db84, 0x1db88, 0x1db90, 0x1db9e, - 0x1dba0, 0x1dbcc, 0x1dbf2, 0x1dbf4, 0x1dc22, 0x1dc42, 0x1dc44, 0x1dc48, 0x1dc50, 0x1dc5e, 0x1dc66, 0x1dc7a, 0x1dc82, 0x1dc84, 0x1dc88, 0x1dc90, 0x1dc9e, 0x1dca0, 0x1dcbc, 0x1dccc, 0x1dcf2, 0x1dcf4, 0x1dd04, 0x1dd08, 0x1dd10, 0x1dd1e, 0x1dd20, 0x1dd3c, 0x1dd40, 0x1dd78, 0x1dd86, 0x1dd98, 0x1ddce, 0x1dde2, 0x1dde4, 0x1dde8, 0x1de2e, 0x1de32, 0x1de34, 0x1de4e, 0x1de5c, 0x1de62, 0x1de64, 0x1de68, 0x1de8e, 0x1de9c, 0x1deb8, 0x1dec2, 0x1dec4, 0x1dec8, 0x1ded0, 0x1dee6, 0x1defa, 0x1df16, 0x1df26, 0x1df2c, 0x1df46, 0x1df4c, 0x1df58, 0x1df72, 0x1df74, 0x1df8a, 0x1df92, 0x1df94, 0x1dfa2, 0x1dfa4, 0x1dfa8, 0x1e08a, 0x1e092, 0x1e094, 0x1e0a2, 0x1e0a4, 0x1e0a8, 0x1e0b6, 0x1e0da, 0x1e10a, 0x1e112, 0x1e114, 0x1e122, 0x1e124, 0x1e128, 0x1e136, 0x1e142, 0x1e144, 0x1e148, 0x1e150, 0x1e166, 0x1e16c, 0x1e17a, 0x1e19a, 0x1e1b2, 0x1e1b4, 0x1e20a, 0x1e212, 0x1e214, 0x1e222, 0x1e224, 0x1e228, 0x1e236, 0x1e242, 0x1e248, 0x1e250, 0x1e25e, 0x1e266, 0x1e26c, 0x1e27a, 0x1e282, 0x1e284, 0x1e288, 0x1e290, 0x1e2a0, 0x1e2bc, 0x1e2c6, 0x1e2cc, 0x1e2d8, 0x1e2ee, 0x1e2f2, 0x1e2f4, 0x1e31a, 0x1e332, 0x1e334, 0x1e35c, 0x1e362, 0x1e364, 0x1e368, 0x1e3ba, 0x1e40a, 0x1e412, 0x1e414, 0x1e422, 0x1e428, 0x1e436, 0x1e442, 0x1e448, 0x1e450, 0x1e45e, 0x1e466, 0x1e46c, 0x1e47a, 0x1e482, 0x1e484, 0x1e490, 0x1e49e, 0x1e4a0, 0x1e4bc, 0x1e4c6, 0x1e4cc, 0x1e4d8, 0x1e4ee, 0x1e4f2, 0x1e4f4, 0x1e502, 0x1e504, 0x1e508, 0x1e510, 0x1e51e, 0x1e520, 0x1e53c, 0x1e540, 0x1e578, 0x1e586, 0x1e58c, 0x1e598, 0x1e5b0, 0x1e5be, 0x1e5ce, 0x1e5dc, 0x1e5e2, 0x1e5e4, 0x1e5e8, 0x1e5f6, 0x1e61a, 0x1e62e, 0x1e632, 0x1e634, 0x1e64e, 0x1e65c, 0x1e662, 0x1e668, 0x1e68e, 0x1e69c, 0x1e6b8, 0x1e6c2, 0x1e6c4, 0x1e6c8, 0x1e6d0, 0x1e6e6, 0x1e6fa, 0x1e716, 0x1e726, 0x1e72c, 0x1e73a, 0x1e746, 0x1e74c, 0x1e758, 0x1e772, 0x1e774, 0x1e792, 0x1e794, 0x1e7a2, 0x1e7a4, 0x1e7a8, 0x1e7b6, 0x1e812, 0x1e814, 0x1e822, 0x1e824, 0x1e828, 0x1e836, 0x1e842, 0x1e844, 0x1e848, 0x1e850, 0x1e85e, 0x1e866, 0x1e86c, 0x1e87a, 0x1e882, 0x1e884, 0x1e888, 0x1e890, 0x1e89e, 0x1e8a0, 0x1e8bc, 0x1e8c6, - 0x1e8cc, 0x1e8d8, 0x1e8ee, 0x1e8f2, 0x1e8f4, 0x1e902, 0x1e904, 0x1e908, 0x1e910, 0x1e920, 0x1e93c, 0x1e940, 0x1e978, 0x1e986, 0x1e98c, 0x1e998, 0x1e9b0, 0x1e9be, 0x1e9ce, 0x1e9dc, 0x1e9e2, 0x1e9e4, 0x1e9e8, 0x1e9f6, 0x1ea04, 0x1ea08, 0x1ea10, 0x1ea20, 0x1ea40, 0x1ea78, 0x1eaf0, 0x1eb06, 0x1eb0c, 0x1eb18, 0x1eb30, 0x1eb3e, 0x1eb60, 0x1eb7c, 0x1eb8e, 0x1eb9c, 0x1ebb8, 0x1ebc2, 0x1ebc4, 0x1ebc8, 0x1ebd0, 0x1ebde, 0x1ebe6, 0x1ebec, 0x1ec1a, 0x1ec2e, 0x1ec32, 0x1ec34, 0x1ec4e, 0x1ec5c, 0x1ec62, 0x1ec64, 0x1ec68, 0x1ec8e, 0x1ec9c, 0x1ecb8, 0x1ecc2, 0x1ecc4, 0x1ecc8, 0x1ecd0, 0x1ece6, 0x1ecfa, 0x1ed0e, 0x1ed1c, 0x1ed38, 0x1ed70, 0x1ed7e, 0x1ed82, 0x1ed84, 0x1ed88, 0x1ed90, 0x1ed9e, 0x1eda0, 0x1edcc, 0x1edf2, 0x1edf4, 0x1ee16, 0x1ee26, 0x1ee2c, 0x1ee3a, 0x1ee46, 0x1ee4c, 0x1ee58, 0x1ee6e, 0x1ee72, 0x1ee74, 0x1ee86, 0x1ee8c, 0x1ee98, 0x1eeb0, 0x1eebe, 0x1eece, 0x1eedc, 0x1eee2, 0x1eee4, 0x1eee8, 0x1ef12, 0x1ef22, 0x1ef24, 0x1ef28, 0x1ef36, 0x1ef42, 0x1ef44, 0x1ef48, 0x1ef50, 0x1ef5e, 0x1ef66, 0x1ef6c, 0x1ef7a, 0x1efae, 0x1efb2, 0x1efb4, 0x1efd6, 0x1f096, 0x1f0a6, 0x1f0ac, 0x1f0ba, 0x1f0ca, 0x1f0d2, 0x1f0d4, 0x1f116, 0x1f126, 0x1f12c, 0x1f13a, 0x1f146, 0x1f14c, 0x1f158, 0x1f16e, 0x1f172, 0x1f174, 0x1f18a, 0x1f192, 0x1f194, 0x1f1a2, 0x1f1a4, 0x1f1a8, 0x1f1da, 0x1f216, 0x1f226, 0x1f22c, 0x1f23a, 0x1f246, 0x1f258, 0x1f26e, 0x1f272, 0x1f274, 0x1f286, 0x1f28c, 0x1f298, 0x1f2b0, 0x1f2be, 0x1f2ce, 0x1f2dc, 0x1f2e2, 0x1f2e4, 0x1f2e8, 0x1f2f6, 0x1f30a, 0x1f312, 0x1f314, 0x1f322, 0x1f328, 0x1f342, 0x1f344, 0x1f348, 0x1f350, 0x1f35e, 0x1f366, 0x1f37a, 0x1f39a, 0x1f3ae, 0x1f3b2, 0x1f3b4, 0x1f416, 0x1f426, 0x1f42c, 0x1f43a, 0x1f446, 0x1f44c, 0x1f458, 0x1f46e, 0x1f472, 0x1f474, 0x1f486, 0x1f48c, 0x1f498, 0x1f4b0, 0x1f4be, 0x1f4ce, 0x1f4dc, 0x1f4e2, 0x1f4e4, 0x1f4e8, 0x1f4f6, 0x1f506, 0x1f50c, 0x1f518, 0x1f530, 0x1f53e, 0x1f560, 0x1f57c, 0x1f58e, 0x1f59c, 0x1f5b8, 0x1f5c2, 0x1f5c4, 0x1f5c8, 0x1f5d0, 0x1f5de, 0x1f5e6, 0x1f5ec, 0x1f5fa, 0x1f60a, 0x1f612, 0x1f614, 0x1f622, 0x1f624, 0x1f628, 0x1f636, 0x1f642, 0x1f644, - 0x1f648, 0x1f650, 0x1f65e, 0x1f666, 0x1f67a, 0x1f682, 0x1f684, 0x1f688, 0x1f690, 0x1f69e, 0x1f6a0, 0x1f6bc, 0x1f6cc, 0x1f6f2, 0x1f6f4, 0x1f71a, 0x1f72e, 0x1f732, 0x1f734, 0x1f74e, 0x1f75c, 0x1f762, 0x1f764, 0x1f768, 0x1f776, 0x1f796, 0x1f7a6, 0x1f7ac, 0x1f7ba, 0x1f7d2, 0x1f7d4, 0x1f89a, 0x1f8ae, 0x1f8b2, 0x1f8b4, 0x1f8d6, 0x1f8ea, 0x1f91a, 0x1f92e, 0x1f932, 0x1f934, 0x1f94e, 0x1f95c, 0x1f962, 0x1f964, 0x1f968, 0x1f976, 0x1f996, 0x1f9a6, 0x1f9ac, 0x1f9ba, 0x1f9ca, 0x1f9d2, 0x1f9d4, 0x1fa1a, 0x1fa2e, 0x1fa32, 0x1fa34, 0x1fa4e, 0x1fa5c, 0x1fa62, 0x1fa64, 0x1fa68, 0x1fa76, 0x1fa8e, 0x1fa9c, 0x1fab8, 0x1fac2, 0x1fac4, 0x1fac8, 0x1fad0, 0x1fade, 0x1fae6, 0x1faec, 0x1fb16, 0x1fb26, 0x1fb2c, 0x1fb3a, 0x1fb46, 0x1fb4c, 0x1fb58, 0x1fb6e, 0x1fb72, 0x1fb74, 0x1fb8a, 0x1fb92, 0x1fb94, 0x1fba2, 0x1fba4, 0x1fba8, 0x1fbb6, 0x1fbda}; - - /// This table contains to codewords for all symbols. - //UPGRADE_NOTE: Final was removed from the declaration of 'CODEWORD_TABLE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] CODEWORD_TABLE = new int[]{2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511, 873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815, 814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752, 2739, 2737, 2728, 2727, 2725, 2730, 2785, 2783, 2778, 2777, 2775, 2780, 787, 781, 747, 739, 736, 2413, 754, 752, 1719, 692, 689, 681, 2371, 678, 2369, 700, 697, 694, 703, 1688, 1686, 642, 638, 2343, 631, 2341, 627, 2338, 651, 646, 643, 2345, 654, 652, 1652, 1650, 1647, 1654, 601, 599, 2322, 596, 2321, 594, 2319, 2317, 611, 610, 608, 606, 2324, 603, 2323, 615, 614, 612, 1617, 1616, 1614, 1612, 616, 1619, 1618, 2575, 2538, 2536, 905, 901, 898, 909, 2509, 2507, 2504, 870, 867, 864, 860, 2512, 875, 872, 1781, 2490, 2489, 2487, 2485, 1748, 836, 834, 832, 830, 2494, 827, 2492, 843, 841, 839, 845, 1765, 1763, 2701, 2676, 2674, 2653, 2648, 2656, 2634, 2633, 2631, 2629, 1821, 2638, 2636, 2770, 2763, 2761, 2750, 2745, 2753, 2736, 2735, 2733, 2731, 1848, 2740, 2738, 2786, 2784, 591, 588, 576, 569, 566, 2296, 1590, 537, 534, 526, 2276, 522, 2274, 545, 542, 539, 548, 1572, 1570, 481, 2245, 466, 2242, 462, 2239, 492, 485, 482, 2249, 496, 494, 1534, 1531, 1528, 1538, 413, 2196, 406, 2191, 2188, 425, 419, 2202, 415, 2199, 432, 430, 427, 1472, 1467, 1464, 433, 1476, 1474, 368, 367, 2160, 365, 2159, 362, 2157, 2155, 2152, 378, 377, 375, 2166, 372, 2165, 369, 2162, 383, 381, 379, 2168, 1419, 1418, 1416, 1414, 385, 1411, 384, 1423, 1422, 1420, 1424, 2461, 802, 2441, 2439, 790, 786, 783, 794, 2409, 2406, 2403, 750, 742, 738, 2414, 756, 753, 1720, 2367, 2365, 2362, 2359, 1663, 693, 691, 684, 2373, 680, 2370, 702, 699, 696, 704, 1690, 1687, 2337, 2336, 2334, 2332, 1624, 2329, 1622, 640, 637, 2344, 634, 2342, 630, 2340, 650, 648, 645, 2346, 655, 653, 1653, 1651, 1649, 1655, 2612, 2597, 2595, 2571, 2568, 2565, 2576, 2534, 2529, 2526, 1787, - 2540, 2537, 907, 904, 900, 910, 2503, 2502, 2500, 2498, 1768, 2495, 1767, 2510, 2508, 2506, 869, 866, 863, 2513, 876, 874, 1782, 2720, 2713, 2711, 2697, 2694, 2691, 2702, 2672, 2670, 2664, 1828, 2678, 2675, 2647, 2646, 2644, 2642, 1823, 2639, 1822, 2654, 2652, 2650, 2657, 2771, 1855, 2765, 2762, 1850, 1849, 2751, 2749, 2747, 2754, 353, 2148, 344, 342, 336, 2142, 332, 2140, 345, 1375, 1373, 306, 2130, 299, 2128, 295, 2125, 319, 314, 311, 2132, 1354, 1352, 1349, 1356, 262, 257, 2101, 253, 2096, 2093, 274, 273, 267, 2107, 263, 2104, 280, 278, 275, 1316, 1311, 1308, 1320, 1318, 2052, 202, 2050, 2044, 2040, 219, 2063, 212, 2060, 208, 2055, 224, 221, 2066, 1260, 1258, 1252, 231, 1248, 229, 1266, 1264, 1261, 1268, 155, 1998, 153, 1996, 1994, 1991, 1988, 165, 164, 2007, 162, 2006, 159, 2003, 2000, 172, 171, 169, 2012, 166, 2010, 1186, 1184, 1182, 1179, 175, 1176, 173, 1192, 1191, 1189, 1187, 176, 1194, 1193, 2313, 2307, 2305, 592, 589, 2294, 2292, 2289, 578, 572, 568, 2297, 580, 1591, 2272, 2267, 2264, 1547, 538, 536, 529, 2278, 525, 2275, 547, 544, 541, 1574, 1571, 2237, 2235, 2229, 1493, 2225, 1489, 478, 2247, 470, 2244, 465, 2241, 493, 488, 484, 2250, 498, 495, 1536, 1533, 1530, 1539, 2187, 2186, 2184, 2182, 1432, 2179, 1430, 2176, 1427, 414, 412, 2197, 409, 2195, 405, 2193, 2190, 426, 424, 421, 2203, 418, 2201, 431, 429, 1473, 1471, 1469, 1466, 434, 1477, 1475, 2478, 2472, 2470, 2459, 2457, 2454, 2462, 803, 2437, 2432, 2429, 1726, 2443, 2440, 792, 789, 785, 2401, 2399, 2393, 1702, 2389, 1699, 2411, 2408, 2405, 745, 741, 2415, 758, 755, 1721, 2358, 2357, 2355, 2353, 1661, 2350, 1660, 2347, 1657, 2368, 2366, 2364, 2361, 1666, 690, 687, 2374, 683, 2372, 701, 698, 705, 1691, 1689, 2619, 2617, 2610, 2608, 2605, 2613, 2593, 2588, 2585, 1803, 2599, 2596, 2563, 2561, 2555, 1797, 2551, 1795, 2573, 2570, 2567, 2577, 2525, 2524, 2522, 2520, 1786, 2517, 1785, 2514, 1783, 2535, 2533, 2531, 2528, 1788, 2541, 2539, 906, 903, 911, 2721, 1844, 2715, 2712, 1838, 1836, 2699, 2696, 2693, 2703, 1827, 1826, 1824, 2673, - 2671, 2669, 2666, 1829, 2679, 2677, 1858, 1857, 2772, 1854, 1853, 1851, 1856, 2766, 2764, 143, 1987, 139, 1986, 135, 133, 131, 1984, 128, 1983, 125, 1981, 138, 137, 136, 1985, 1133, 1132, 1130, 112, 110, 1974, 107, 1973, 104, 1971, 1969, 122, 121, 119, 117, 1977, 114, 1976, 124, 1115, 1114, 1112, 1110, 1117, 1116, 84, 83, 1953, 81, 1952, 78, 1950, 1948, 1945, 94, 93, 91, 1959, 88, 1958, 85, 1955, 99, 97, 95, 1961, 1086, 1085, 1083, 1081, 1078, 100, 1090, 1089, 1087, 1091, 49, 47, 1917, 44, 1915, 1913, 1910, 1907, 59, 1926, 56, 1925, 53, 1922, 1919, 66, 64, 1931, 61, 1929, 1042, 1040, 1038, 71, 1035, 70, 1032, 68, 1048, 1047, 1045, 1043, 1050, 1049, 12, 10, 1869, 1867, 1864, 1861, 21, 1880, 19, 1877, 1874, 1871, 28, 1888, 25, 1886, 22, 1883, 982, 980, 977, 974, 32, 30, 991, 989, 987, 984, 34, 995, 994, 992, 2151, 2150, 2147, 2146, 2144, 356, 355, 354, 2149, 2139, 2138, 2136, 2134, 1359, 343, 341, 338, 2143, 335, 2141, 348, 347, 346, 1376, 1374, 2124, 2123, 2121, 2119, 1326, 2116, 1324, 310, 308, 305, 2131, 302, 2129, 298, 2127, 320, 318, 316, 313, 2133, 322, 321, 1355, 1353, 1351, 1357, 2092, 2091, 2089, 2087, 1276, 2084, 1274, 2081, 1271, 259, 2102, 256, 2100, 252, 2098, 2095, 272, 269, 2108, 266, 2106, 281, 279, 277, 1317, 1315, 1313, 1310, 282, 1321, 1319, 2039, 2037, 2035, 2032, 1203, 2029, 1200, 1197, 207, 2053, 205, 2051, 201, 2049, 2046, 2043, 220, 218, 2064, 215, 2062, 211, 2059, 228, 226, 223, 2069, 1259, 1257, 1254, 232, 1251, 230, 1267, 1265, 1263, 2316, 2315, 2312, 2311, 2309, 2314, 2304, 2303, 2301, 2299, 1593, 2308, 2306, 590, 2288, 2287, 2285, 2283, 1578, 2280, 1577, 2295, 2293, 2291, 579, 577, 574, 571, 2298, 582, 581, 1592, 2263, 2262, 2260, 2258, 1545, 2255, 1544, 2252, 1541, 2273, 2271, 2269, 2266, 1550, 535, 532, 2279, 528, 2277, 546, 543, 549, 1575, 1573, 2224, 2222, 2220, 1486, 2217, 1485, 2214, 1482, 1479, 2238, 2236, 2234, 2231, 1496, 2228, 1492, 480, 477, 2248, 473, 2246, 469, 2243, 490, 487, 2251, 497, 1537, 1535, 1532, 2477, 2476, 2474, 2479, 2469, 2468, 2466, 2464, 1730 - , 2473, 2471, 2453, 2452, 2450, 2448, 1729, 2445, 1728, 2460, 2458, 2456, 2463, 805, 804, 2428, 2427, 2425, 2423, 1725, 2420, 1724, 2417, 1722, 2438, 2436, 2434, 2431, 1727, 2444, 2442, 793, 791, 788, 795, 2388, 2386, 2384, 1697, 2381, 1696, 2378, 1694, 1692, 2402, 2400, 2398, 2395, 1703, 2392, 1701, 2412, 2410, 2407, 751, 748, 744, 2416, 759, 757, 1807, 2620, 2618, 1806, 1805, 2611, 2609, 2607, 2614, 1802, 1801, 1799, 2594, 2592, 2590, 2587, 1804, 2600, 2598, 1794, 1793, 1791, 1789, 2564, 2562, 2560, 2557, 1798, 2554, 1796, 2574, 2572, 2569, 2578, 1847, 1846, 2722, 1843, 1842, 1840, 1845, 2716, 2714, 1835, 1834, 1832, 1830, 1839, 1837, 2700, 2698, 2695, 2704, 1817, 1811, 1810, 897, 862, 1777, 829, 826, 838, 1760, 1758, 808, 2481, 1741, 1740, 1738, 1743, 2624, 1818, 2726, 2776, 782, 740, 737, 1715, 686, 679, 695, 1682, 1680, 639, 628, 2339, 647, 644, 1645, 1643, 1640, 1648, 602, 600, 597, 595, 2320, 593, 2318, 609, 607, 604, 1611, 1610, 1608, 1606, 613, 1615, 1613, 2328, 926, 924, 892, 886, 899, 857, 850, 2505, 1778, 824, 823, 821, 819, 2488, 818, 2486, 833, 831, 828, 840, 1761, 1759, 2649, 2632, 2630, 2746, 2734, 2732, 2782, 2781, 570, 567, 1587, 531, 527, 523, 540, 1566, 1564, 476, 467, 463, 2240, 486, 483, 1524, 1521, 1518, 1529, 411, 403, 2192, 399, 2189, 423, 416, 1462, 1457, 1454, 428, 1468, 1465, 2210, 366, 363, 2158, 360, 2156, 357, 2153, 376, 373, 370, 2163, 1410, 1409, 1407, 1405, 382, 1402, 380, 1417, 1415, 1412, 1421, 2175, 2174, 777, 774, 771, 784, 732, 725, 722, 2404, 743, 1716, 676, 674, 668, 2363, 665, 2360, 685, 1684, 1681, 626, 624, 622, 2335, 620, 2333, 617, 2330, 641, 635, 649, 1646, 1644, 1642, 2566, 928, 925, 2530, 2527, 894, 891, 888, 2501, 2499, 2496, 858, 856, 854, 851, 1779, 2692, 2668, 2665, 2645, 2643, 2640, 2651, 2768, 2759, 2757, 2744, 2743, 2741, 2748, 352, 1382, 340, 337, 333, 1371, 1369, 307, 300, 296, 2126, 315, 312, 1347, 1342, 1350, 261, 258, 250, 2097, 246, 2094, 271, 268, 264, 1306, 1301, 1298, 276, 1312, 1309, 2115, 203, 2048, 195, 2045, 191, 2041, 213, 209 - , 2056, 1246, 1244, 1238, 225, 1234, 222, 1256, 1253, 1249, 1262, 2080, 2079, 154, 1997, 150, 1995, 147, 1992, 1989, 163, 160, 2004, 156, 2001, 1175, 1174, 1172, 1170, 1167, 170, 1164, 167, 1185, 1183, 1180, 1177, 174, 1190, 1188, 2025, 2024, 2022, 587, 586, 564, 559, 556, 2290, 573, 1588, 520, 518, 512, 2268, 508, 2265, 530, 1568, 1565, 461, 457, 2233, 450, 2230, 446, 2226, 479, 471, 489, 1526, 1523, 1520, 397, 395, 2185, 392, 2183, 389, 2180, 2177, 410, 2194, 402, 422, 1463, 1461, 1459, 1456, 1470, 2455, 799, 2433, 2430, 779, 776, 773, 2397, 2394, 2390, 734, 728, 724, 746, 1717, 2356, 2354, 2351, 2348, 1658, 677, 675, 673, 670, 667, 688, 1685, 1683, 2606, 2589, 2586, 2559, 2556, 2552, 927, 2523, 2521, 2518, 2515, 1784, 2532, 895, 893, 890, 2718, 2709, 2707, 2689, 2687, 2684, 2663, 2662, 2660, 2658, 1825, 2667, 2769, 1852, 2760, 2758, 142, 141, 1139, 1138, 134, 132, 129, 126, 1982, 1129, 1128, 1126, 1131, 113, 111, 108, 105, 1972, 101, 1970, 120, 118, 115, 1109, 1108, 1106, 1104, 123, 1113, 1111, 82, 79, 1951, 75, 1949, 72, 1946, 92, 89, 86, 1956, 1077, 1076, 1074, 1072, 98, 1069, 96, 1084, 1082, 1079, 1088, 1968, 1967, 48, 45, 1916, 42, 1914, 39, 1911, 1908, 60, 57, 54, 1923, 50, 1920, 1031, 1030, 1028, 1026, 67, 1023, 65, 1020, 62, 1041, 1039, 1036, 1033, 69, 1046, 1044, 1944, 1943, 1941, 11, 9, 1868, 7, 1865, 1862, 1859, 20, 1878, 16, 1875, 13, 1872, 970, 968, 966, 963, 29, 960, 26, 23, 983, 981, 978, 975, 33, 971, 31, 990, 988, 985, 1906, 1904, 1902, 993, 351, 2145, 1383, 331, 330, 328, 326, 2137, 323, 2135, 339, 1372, 1370, 294, 293, 291, 289, 2122, 286, 2120, 283, 2117, 309, 303, 317, 1348, 1346, 1344, 245, 244, 242, 2090, 239, 2088, 236, 2085, 2082, 260, 2099, 249, 270, 1307, 1305, 1303, 1300, 1314, 189, 2038, 186, 2036, 183, 2033, 2030, 2026, 206, 198, 2047, 194, 216, 1247, 1245, 1243, 1240, 227, 1237, 1255, 2310, 2302, 2300, 2286, 2284, 2281, 565, 563, 561, 558, 575, 1589, 2261, 2259, 2256, 2253, 1542, 521, 519, 517, 514, 2270, 511, 533, 1569, 1567, 2223, 2221, 2218, 2215, 1483, 2211, - 1480, 459, 456, 453, 2232, 449, 474, 491, 1527, 1525, 1522, 2475, 2467, 2465, 2451, 2449, 2446, 801, 800, 2426, 2424, 2421, 2418, 1723, 2435, 780, 778, 775, 2387, 2385, 2382, 2379, 1695, 2375, 1693, 2396, 735, 733, 730, 727, 749, 1718, 2616, 2615, 2604, 2603, 2601, 2584, 2583, 2581, 2579, 1800, 2591, 2550, 2549, 2547, 2545, 1792, 2542, 1790, 2558, 929, 2719, 1841, 2710, 2708, 1833, 1831, 2690, 2688, 2686, 1815, 1809, 1808, 1774, 1756, 1754, 1737, 1736, 1734, 1739, 1816, 1711, 1676, 1674, 633, 629, 1638, 1636, 1633, 1641, 598, 1605, 1604, 1602, 1600, 605, 1609, 1607, 2327, 887, 853, 1775, 822, 820, 1757, 1755, 1584, 524, 1560, 1558, 468, 464, 1514, 1511, 1508, 1519, 408, 404, 400, 1452, 1447, 1444, 417, 1458, 1455, 2208, 364, 361, 358, 2154, 1401, 1400, 1398, 1396, 374, 1393, 371, 1408, 1406, 1403, 1413, 2173, 2172, 772, 726, 723, 1712, 672, 669, 666, 682, 1678, 1675, 625, 623, 621, 618, 2331, 636, 632, 1639, 1637, 1635, 920, 918, 884, 880, 889, 849, 848, 847, 846, 2497, 855, 852, 1776, 2641, 2742, 2787, 1380, 334, 1367, 1365, 301, 297, 1340, 1338, 1335, 1343, 255, 251, 247, 1296, 1291, 1288, 265, 1302, 1299, 2113, 204, 196, 192, 2042, 1232, 1230, 1224, 214, 1220, 210, 1242, 1239, 1235, 1250, 2077, 2075, 151, 148, 1993, 144, 1990, 1163, 1162, 1160, 1158, 1155, 161, 1152, 157, 1173, 1171, 1168, 1165, 168, 1181, 1178, 2021, 2020, 2018, 2023, 585, 560, 557, 1585, 516, 509, 1562, 1559, 458, 447, 2227, 472, 1516, 1513, 1510, 398, 396, 393, 390, 2181, 386, 2178, 407, 1453, 1451, 1449, 1446, 420, 1460, 2209, 769, 764, 720, 712, 2391, 729, 1713, 664, 663, 661, 659, 2352, 656, 2349, 671, 1679, 1677, 2553, 922, 919, 2519, 2516, 885, 883, 881, 2685, 2661, 2659, 2767, 2756, 2755, 140, 1137, 1136, 130, 127, 1125, 1124, 1122, 1127, 109, 106, 102, 1103, 1102, 1100, 1098, 116, 1107, 1105, 1980, 80, 76, 73, 1947, 1068, 1067, 1065, 1063, 90, 1060, 87, 1075, 1073, 1070, 1080, 1966, 1965, 46, 43, 40, 1912, 36, 1909, 1019, 1018, 1016, 1014, 58, 1011, 55, 1008, 51, 1029, 1027, 1024, 1021, 63, 1037, 1034, 1940, 1939, - 1937, 1942, 8, 1866, 4, 1863, 1, 1860, 956, 954, 952, 949, 946, 17, 14, 969, 967, 964, 961, 27, 957, 24, 979, 976, 972, 1901, 1900, 1898, 1896, 986, 1905, 1903, 350, 349, 1381, 329, 327, 324, 1368, 1366, 292, 290, 287, 284, 2118, 304, 1341, 1339, 1337, 1345, 243, 240, 237, 2086, 233, 2083, 254, 1297, 1295, 1293, 1290, 1304, 2114, 190, 187, 184, 2034, 180, 2031, 177, 2027, 199, 1233, 1231, 1229, 1226, 217, 1223, 1241, 2078, 2076, 584, 555, 554, 552, 550, 2282, 562, 1586, 507, 506, 504, 502, 2257, 499, 2254, 515, 1563, 1561, 445, 443, 441, 2219, 438, 2216, 435, 2212, 460, 454, 475, 1517, 1515, 1512, 2447, 798, 797, 2422, 2419, 770, 768, 766, 2383, 2380, 2376, 721, 719, 717, 714, 731, 1714, 2602, 2582, 2580, 2548, 2546, 2543, 923, 921, 2717, 2706, 2705, 2683, 2682, 2680, 1771, 1752, 1750, 1733, 1732, 1731, 1735, 1814, 1707, 1670, 1668, 1631, 1629, 1626, 1634, 1599, 1598, 1596, 1594, 1603, 1601, 2326, 1772, 1753, 1751, 1581, 1554, 1552, 1504, 1501, 1498, 1509, 1442, 1437, 1434, 401, 1448, 1445, 2206, 1392, 1391, 1389, 1387, 1384, 359, 1399, 1397, 1394, 1404, 2171, 2170, 1708, 1672, 1669, 619, 1632, 1630, 1628, 1773, 1378, 1363, 1361, 1333, 1328, 1336, 1286, 1281, 1278, 248, 1292, 1289, 2111, 1218, 1216, 1210, 197, 1206, 193, 1228, 1225, 1221, 1236, 2073, 2071, 1151, 1150, 1148, 1146, 152, 1143, 149, 1140, 145, 1161, 1159, 1156, 1153, 158, 1169, 1166, 2017, 2016, 2014, 2019, 1582, 510, 1556, 1553, 452, 448, 1506, 1500, 394, 391, 387, 1443, 1441, 1439, 1436, 1450, 2207, 765, 716, 713, 1709, 662, 660, 657, 1673, 1671, 916, 914, 879, 878, 877, 882, 1135, 1134, 1121, 1120, 1118, 1123, 1097, 1096, 1094, 1092, 103, 1101, 1099, 1979, 1059, 1058, 1056, 1054, 77, 1051, 74, 1066, 1064, 1061, 1071, 1964, 1963, 1007, 1006, 1004, 1002, 999, 41, 996, 37, 1017, 1015, 1012, 1009, 52, 1025, 1022, 1936, 1935, 1933, 1938, 942, 940, 938, 935, 932, 5, 2, 955, 953, 950, 947, 18, 943, 15, 965, 962, 958, 1895, 1894, 1892, 1890, 973, 1899, 1897, 1379, 325, 1364, 1362, 288, 285, 1334, 1332, 1330, 241, 238, 234, 1287, 1285, - 1283, 1280, 1294, 2112, 188, 185, 181, 178, 2028, 1219, 1217, 1215, 1212, 200, 1209, 1227, 2074, 2072, 583, 553, 551, 1583, 505, 503, 500, 513, 1557, 1555, 444, 442, 439, 436, 2213, 455, 451, 1507, 1505, 1502, 796, 763, 762, 760, 767, 711, 710, 708, 706, 2377, 718, 715, 1710, 2544, 917, 915, 2681, 1627, 1597, 1595, 2325, 1769, 1749, 1747, 1499, 1438, 1435, 2204, 1390, 1388, 1385, 1395, 2169, 2167, 1704, 1665, 1662, 1625, 1623, 1620, 1770, 1329, 1282, 1279, 2109, 1214, 1207, 1222, 2068, 2065, 1149, 1147, 1144, 1141, 146, 1157, 1154, 2013, 2011, 2008, 2015, 1579, 1549, 1546, 1495, 1487, 1433, 1431, 1428, 1425, 388, 1440, 2205, 1705, 658, 1667, 1664, 1119, 1095, 1093, 1978, 1057, 1055, 1052, 1062, 1962, 1960, 1005, 1003, 1000, 997, 38, 1013, 1010, 1932, 1930, 1927, 1934, 941, 939, 936, 933, 6, 930, 3, 951, 948, 944, 1889, 1887, 1884, 1881, 959, 1893, 1891, 35, 1377, 1360, 1358, 1327, 1325, 1322, 1331, 1277, 1275, 1272, 1269, 235, 1284, 2110, 1205, 1204, 1201, 1198, 182, 1195, 179, 1213, 2070, 2067, 1580, 501, 1551, 1548, 440, 437, 1497, 1494, 1490, 1503, 761, 709, 707, 1706, 913, 912, 2198, 1386, 2164, 2161, 1621, 1766, 2103, 1208, 2058, 2054, 1145, 1142, 2005, 2002, 1999, 2009, 1488, 1429, 1426, 2200, 1698, 1659, 1656, 1975, 1053, 1957, 1954, 1001, 998, 1924, 1921, 1918, 1928, 937, 934, 931, 1879, 1876, 1873, 1870, 945, 1885, 1882, 1323, 1273, 1270, 2105, 1202, 1199, 1196, 1211, 2061, 2057, 1576, 1543, 1540, 1484, 1481, 1478, 1491, 1700}; + else + { + long cw = CODEWORD_TABLE[i] - 1; + cw %= 929; + return (int) cw; + } + } + + /// + /// Use a binary search to find the index of the codeword corresponding to + /// this symbol. + /// + /// the symbol from the barcode. + /// the index into the codeword table. + private static int findCodewordIndex(long symbol) + { + int first = 0; + int upto = SYMBOL_TABLE.Length; + while (first < upto) + { + int mid = (int)((uint)(first + upto) >> 1); // Compute mid point. + if (symbol < SYMBOL_TABLE[mid]) + { + upto = mid; // repeat search in bottom half. + } + else if (symbol > SYMBOL_TABLE[mid]) + { + first = mid + 1; // Repeat search in top half. + } + else + { + return mid; // Found it. return position + } + } + return -1; + } + + /// + /// Returns an array of locations representing the erasures. + /// + public int[] Erasures + { + get + { + return erasures; + } + } + + public int ECLevel + { + get + { + return ecLevel; + } + } + + /// + /// The sorted table of all possible symbols. Extracted from the PDF417 + /// specification. The index of a symbol in this table corresponds to the + /// index into the codeword table. + /// + private static readonly int[] SYMBOL_TABLE = {0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac, 0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482, 0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e, 0x10520, 0x1053c, 0x10540, 0x10578, 0x10586, 0x1058c, 0x10598, 0x105b0, 0x105be, 0x105ce, 0x105dc, 0x105e2, 0x105e4, 0x105e8, 0x105f6, 0x1062e, 0x1064e, 0x1065c, 0x1068e, 0x1069c, 0x106b8, 0x106de, 0x106fa, 0x10716, 0x10726, 0x1072c, 0x10746, 0x1074c, 0x10758, 0x1076e, 0x10792, 0x10794, 0x107a2, 0x107a4, 0x107a8, 0x107b6, 0x10822, 0x10828, 0x10842, 0x10848, 0x10850, 0x1085e, 0x10866, 0x1086c, 0x1087a, 0x10882, 0x10884, 0x10890, 0x1089e, 0x108a0, 0x108bc, 0x108c6, 0x108cc, 0x108d8, 0x108ee, 0x108f2, 0x108f4, 0x10902, 0x10908, 0x1091e, 0x10920, 0x1093c, 0x10940, 0x10978, 0x10986, 0x10998, 0x109b0, 0x109be, 0x109ce, 0x109dc, 0x109e2, 0x109e4, 0x109e8, 0x109f6, 0x10a08, 0x10a10, 0x10a1e, 0x10a20, 0x10a3c, 0x10a40, 0x10a78, 0x10af0, 0x10b06, 0x10b0c, 0x10b18, 0x10b30, 0x10b3e, 0x10b60, 0x10b7c, 0x10b8e, 0x10b9c, 0x10bb8, 0x10bc2, 0x10bc4, 0x10bc8, 0x10bd0, 0x10bde, 0x10be6, 0x10bec, 0x10c2e, 0x10c4e, 0x10c5c, 0x10c62, 0x10c64, 0x10c68, 0x10c76, 0x10c8e, 0x10c9c, 0x10cb8, 0x10cc2, 0x10cc4, 0x10cc8, 0x10cd0, 0x10cde, 0x10ce6, 0x10cec, 0x10cfa, 0x10d0e, 0x10d1c, 0x10d38, 0x10d70, 0x10d7e, 0x10d82, 0x10d84, 0x10d88, 0x10d90, 0x10d9e, 0x10da0, 0x10dbc, 0x10dc6, 0x10dcc, 0x10dd8, 0x10dee, 0x10df2, 0x10df4, 0x10e16, 0x10e26, 0x10e2c, 0x10e46, 0x10e58, 0x10e6e, 0x10e86, 0x10e8c, 0x10e98, 0x10eb0, 0x10ebe, 0x10ece, 0x10edc, 0x10f0a, 0x10f12, 0x10f14, 0x10f22, 0x10f28, 0x10f36, 0x10f42, 0x10f44, 0x10f48, 0x10f50, 0x10f5e, 0x10f66, 0x10f6c, 0x10fb2, 0x10fb4, 0x11022, 0x11028, 0x11042, 0x11048, 0x11050, 0x1105e, 0x1107a, 0x11082, 0x11084, 0x11090, 0x1109e, 0x110a0, 0x110bc, 0x110c6, 0x110cc, 0x110d8, 0x110ee, 0x110f2, 0x110f4, 0x11102, 0x1111e, 0x11120, 0x1113c, 0x11140, 0x11178, 0x11186, 0x11198, 0x111b0, 0x111be, 0x111ce, 0x111dc, 0x111e2, 0x111e4, 0x111e8, 0x111f6, 0x11208, 0x1121e, 0x11220, 0x11278, 0x112f0, 0x1130c, 0x11330, 0x1133e, 0x11360, 0x1137c, 0x1138e, 0x1139c, 0x113b8, 0x113c2, 0x113c8, 0x113d0, 0x113de, 0x113e6, 0x113ec, 0x11408, 0x11410, 0x1141e, 0x11420, 0x1143c, 0x11440, 0x11478, 0x114f0, 0x115e0, 0x1160c, 0x11618, 0x11630, 0x1163e, 0x11660, 0x1167c, 0x116c0, 0x116f8, 0x1171c, 0x11738, 0x11770, 0x1177e, 0x11782, 0x11784, 0x11788, 0x11790, 0x1179e, 0x117a0, 0x117bc, 0x117c6, 0x117cc, 0x117d8, 0x117ee, 0x1182e, 0x11834, 0x1184e, 0x1185c, 0x11862, 0x11864, 0x11868, 0x11876, 0x1188e, 0x1189c, 0x118b8, 0x118c2, 0x118c8, 0x118d0, 0x118de, 0x118e6, 0x118ec, 0x118fa, 0x1190e, 0x1191c, 0x11938, 0x11970, 0x1197e, 0x11982, 0x11984, 0x11990, 0x1199e, 0x119a0, 0x119bc, 0x119c6, 0x119cc, 0x119d8, 0x119ee, 0x119f2, 0x119f4, 0x11a0e, 0x11a1c, 0x11a38, 0x11a70, 0x11a7e, 0x11ae0, 0x11afc, 0x11b08, 0x11b10, 0x11b1e, 0x11b20, 0x11b3c, 0x11b40, 0x11b78, 0x11b8c, 0x11b98, 0x11bb0, 0x11bbe, 0x11bce, 0x11bdc, 0x11be2, 0x11be4, 0x11be8, 0x11bf6, 0x11c16, 0x11c26, 0x11c2c, 0x11c46, 0x11c4c, 0x11c58, 0x11c6e, 0x11c86, 0x11c98, 0x11cb0, 0x11cbe, 0x11cce, 0x11cdc, 0x11ce2, 0x11ce4, 0x11ce8, 0x11cf6, 0x11d06, 0x11d0c, 0x11d18, 0x11d30, 0x11d3e, 0x11d60, 0x11d7c, 0x11d8e, 0x11d9c, 0x11db8, 0x11dc4, 0x11dc8, 0x11dd0, 0x11dde, 0x11de6, 0x11dec, 0x11dfa, 0x11e0a, 0x11e12, 0x11e14, 0x11e22, 0x11e24, 0x11e28, 0x11e36, 0x11e42, 0x11e44, 0x11e50, 0x11e5e, 0x11e66, 0x11e6c, 0x11e82, 0x11e84, 0x11e88, 0x11e90, 0x11e9e, 0x11ea0, 0x11ebc, 0x11ec6, 0x11ecc, 0x11ed8, 0x11eee, 0x11f1a, 0x11f2e, 0x11f32, 0x11f34, 0x11f4e, 0x11f5c, 0x11f62, 0x11f64, 0x11f68, 0x11f76, 0x12048, 0x1205e, 0x12082, 0x12084, 0x12090, 0x1209e, 0x120a0, 0x120bc, 0x120d8, 0x120f2, 0x120f4, 0x12108, 0x1211e, 0x12120, 0x1213c, 0x12140, 0x12178, 0x12186, 0x12198, 0x121b0, 0x121be, 0x121e2, 0x121e4, 0x121e8, 0x121f6, 0x12204, 0x12210, 0x1221e, 0x12220, 0x12278, 0x122f0, 0x12306, 0x1230c, 0x12330, 0x1233e, 0x12360, 0x1237c, 0x1238e, 0x1239c, 0x123b8, 0x123c2, 0x123c8, 0x123d0, 0x123e6, 0x123ec, 0x1241e, 0x12420, 0x1243c, 0x124f0, 0x125e0, 0x12618, 0x1263e, 0x12660, 0x1267c, 0x126c0, 0x126f8, 0x12738, 0x12770, 0x1277e, 0x12782, 0x12784, 0x12790, 0x1279e, 0x127a0, 0x127bc, 0x127c6, 0x127cc, 0x127d8, 0x127ee, 0x12820, 0x1283c, 0x12840, 0x12878, 0x128f0, 0x129e0, 0x12bc0, 0x12c18, 0x12c30, 0x12c3e, 0x12c60, 0x12c7c, 0x12cc0, 0x12cf8, 0x12df0, 0x12e1c, 0x12e38, 0x12e70, 0x12e7e, 0x12ee0, 0x12efc, 0x12f04, 0x12f08, 0x12f10, 0x12f20, 0x12f3c, 0x12f40, 0x12f78, 0x12f86, 0x12f8c, 0x12f98, 0x12fb0, 0x12fbe, 0x12fce, 0x12fdc, 0x1302e, 0x1304e, 0x1305c, 0x13062, 0x13068, 0x1308e, 0x1309c, 0x130b8, 0x130c2, 0x130c8, 0x130d0, 0x130de, 0x130ec, 0x130fa, 0x1310e, 0x13138, 0x13170, 0x1317e, 0x13182, 0x13184, 0x13190, 0x1319e, 0x131a0, 0x131bc, 0x131c6, 0x131cc, 0x131d8, 0x131f2, 0x131f4, 0x1320e, 0x1321c, 0x13270, 0x1327e, 0x132e0, 0x132fc, 0x13308, 0x1331e, 0x13320, 0x1333c, 0x13340, 0x13378, 0x13386, 0x13398, 0x133b0, 0x133be, 0x133ce, 0x133dc, 0x133e2, 0x133e4, 0x133e8, 0x133f6, 0x1340e, 0x1341c, 0x13438, 0x13470, 0x1347e, 0x134e0, 0x134fc, 0x135c0, 0x135f8, 0x13608, 0x13610, 0x1361e, 0x13620, 0x1363c, 0x13640, 0x13678, 0x136f0, 0x1370c, 0x13718, 0x13730, 0x1373e, 0x13760, 0x1377c, 0x1379c, 0x137b8, 0x137c2, 0x137c4, 0x137c8, 0x137d0, 0x137de, 0x137e6, 0x137ec, 0x13816, 0x13826, 0x1382c, 0x13846, 0x1384c, 0x13858, 0x1386e, 0x13874, 0x13886, 0x13898, 0x138b0, 0x138be, 0x138ce, 0x138dc, 0x138e2, 0x138e4, 0x138e8, 0x13906, 0x1390c, 0x13930, 0x1393e, 0x13960, 0x1397c, 0x1398e, 0x1399c, 0x139b8, 0x139c8, 0x139d0, 0x139de, 0x139e6, 0x139ec, 0x139fa, 0x13a06, 0x13a0c, 0x13a18, 0x13a30, 0x13a3e, 0x13a60, 0x13a7c, 0x13ac0, 0x13af8, 0x13b0e, 0x13b1c, 0x13b38, 0x13b70, 0x13b7e, 0x13b88, 0x13b90, 0x13b9e, 0x13ba0, 0x13bbc, 0x13bcc, 0x13bd8, 0x13bee, 0x13bf2, 0x13bf4, 0x13c12, 0x13c14, 0x13c22, 0x13c24, 0x13c28, 0x13c36, 0x13c42, 0x13c48, 0x13c50, 0x13c5e, 0x13c66, 0x13c6c, 0x13c82, 0x13c84, 0x13c90, 0x13c9e, 0x13ca0, 0x13cbc, 0x13cc6, 0x13ccc, 0x13cd8, 0x13cee, 0x13d02, 0x13d04, 0x13d08, 0x13d10, 0x13d1e, 0x13d20, 0x13d3c, 0x13d40, 0x13d78, 0x13d86, 0x13d8c, 0x13d98, 0x13db0, 0x13dbe, 0x13dce, 0x13ddc, 0x13de4, 0x13de8, 0x13df6, 0x13e1a, 0x13e2e, 0x13e32, 0x13e34, 0x13e4e, 0x13e5c, 0x13e62, 0x13e64, 0x13e68, 0x13e76, 0x13e8e, 0x13e9c, 0x13eb8, 0x13ec2, 0x13ec4, 0x13ec8, 0x13ed0, 0x13ede, 0x13ee6, 0x13eec, 0x13f26, 0x13f2c, 0x13f3a, 0x13f46, 0x13f4c, 0x13f58, 0x13f6e, 0x13f72, 0x13f74, 0x14082, 0x1409e, 0x140a0, 0x140bc, 0x14104, 0x14108, 0x14110, 0x1411e, 0x14120, 0x1413c, 0x14140, 0x14178, 0x1418c, 0x14198, 0x141b0, 0x141be, 0x141e2, 0x141e4, 0x141e8, 0x14208, 0x14210, 0x1421e, 0x14220, 0x1423c, 0x14240, 0x14278, 0x142f0, 0x14306, 0x1430c, 0x14318, 0x14330, 0x1433e, 0x14360, 0x1437c, 0x1438e, 0x143c2, 0x143c4, 0x143c8, 0x143d0, 0x143e6, 0x143ec, 0x14408, 0x14410, 0x1441e, 0x14420, 0x1443c, 0x14440, 0x14478, 0x144f0, 0x145e0, 0x1460c, 0x14618, 0x14630, 0x1463e, 0x14660, 0x1467c, 0x146c0, 0x146f8, 0x1471c, 0x14738, 0x14770, 0x1477e, 0x14782, 0x14784, 0x14788, 0x14790, 0x147a0, 0x147bc, 0x147c6, 0x147cc, 0x147d8, 0x147ee, 0x14810, 0x14820, 0x1483c, 0x14840, 0x14878, 0x148f0, 0x149e0, 0x14bc0, 0x14c30, 0x14c3e, 0x14c60, 0x14c7c, 0x14cc0, 0x14cf8, 0x14df0, 0x14e38, 0x14e70, 0x14e7e, 0x14ee0, 0x14efc, 0x14f04, 0x14f08, 0x14f10, 0x14f1e, 0x14f20, 0x14f3c, 0x14f40, 0x14f78, 0x14f86, 0x14f8c, 0x14f98, 0x14fb0, 0x14fce, 0x14fdc, 0x15020, 0x15040, 0x15078, 0x150f0, 0x151e0, 0x153c0, 0x15860, 0x1587c, 0x158c0, 0x158f8, 0x159f0, 0x15be0, 0x15c70, 0x15c7e, 0x15ce0, 0x15cfc, 0x15dc0, 0x15df8, 0x15e08, 0x15e10, 0x15e20, 0x15e40, 0x15e78, 0x15ef0, 0x15f0c, 0x15f18, 0x15f30, 0x15f60, 0x15f7c, 0x15f8e, 0x15f9c, 0x15fb8, 0x1604e, 0x1605c, 0x1608e, 0x1609c, 0x160b8, 0x160c2, 0x160c4, 0x160c8, 0x160de, 0x1610e, 0x1611c, 0x16138, 0x16170, 0x1617e, 0x16184, 0x16188, 0x16190, 0x1619e, 0x161a0, 0x161bc, 0x161c6, 0x161cc, 0x161d8, 0x161f2, 0x161f4, 0x1620e, 0x1621c, 0x16238, 0x16270, 0x1627e, 0x162e0, 0x162fc, 0x16304, 0x16308, 0x16310, 0x1631e, 0x16320, 0x1633c, 0x16340, 0x16378, 0x16386, 0x1638c, 0x16398, 0x163b0, 0x163be, 0x163ce, 0x163dc, 0x163e2, 0x163e4, 0x163e8, 0x163f6, 0x1640e, 0x1641c, 0x16438, 0x16470, 0x1647e, 0x164e0, 0x164fc, 0x165c0, 0x165f8, 0x16610, 0x1661e, 0x16620, 0x1663c, 0x16640, 0x16678, 0x166f0, 0x16718, 0x16730, 0x1673e, 0x16760, 0x1677c, 0x1678e, 0x1679c, 0x167b8, 0x167c2, 0x167c4, 0x167c8, 0x167d0, 0x167de, 0x167e6, 0x167ec, 0x1681c, 0x16838, 0x16870, 0x168e0, 0x168fc, 0x169c0, 0x169f8, 0x16bf0, 0x16c10, 0x16c1e, 0x16c20, 0x16c3c, 0x16c40, 0x16c78, 0x16cf0, 0x16de0, 0x16e18, 0x16e30, 0x16e3e, 0x16e60, 0x16e7c, 0x16ec0, 0x16ef8, 0x16f1c, 0x16f38, 0x16f70, 0x16f7e, 0x16f84, 0x16f88, 0x16f90, 0x16f9e, 0x16fa0, 0x16fbc, 0x16fc6, 0x16fcc, 0x16fd8, 0x17026, 0x1702c, 0x17046, 0x1704c, 0x17058, 0x1706e, 0x17086, 0x1708c, 0x17098, 0x170b0, 0x170be, 0x170ce, 0x170dc, 0x170e8, 0x17106, 0x1710c, 0x17118, 0x17130, 0x1713e, 0x17160, 0x1717c, 0x1718e, 0x1719c, 0x171b8, 0x171c2, 0x171c4, 0x171c8, 0x171d0, 0x171de, 0x171e6, 0x171ec, 0x171fa, 0x17206, 0x1720c, 0x17218, 0x17230, 0x1723e, 0x17260, 0x1727c, 0x172c0, 0x172f8, 0x1730e, 0x1731c, 0x17338, 0x17370, 0x1737e, 0x17388, 0x17390, 0x1739e, 0x173a0, 0x173bc, 0x173cc, 0x173d8, 0x173ee, 0x173f2, 0x173f4, 0x1740c, 0x17418, 0x17430, 0x1743e, 0x17460, 0x1747c, 0x174c0, 0x174f8, 0x175f0, 0x1760e, 0x1761c, 0x17638, 0x17670, 0x1767e, 0x176e0, 0x176fc, 0x17708, 0x17710, 0x1771e, 0x17720, 0x1773c, 0x17740, 0x17778, 0x17798, 0x177b0, 0x177be, 0x177dc, 0x177e2, 0x177e4, 0x177e8, 0x17822, 0x17824, 0x17828, 0x17836, 0x17842, 0x17844, 0x17848, 0x17850, 0x1785e, 0x17866, 0x1786c, 0x17882, 0x17884, 0x17888, 0x17890, 0x1789e, 0x178a0, 0x178bc, 0x178c6, 0x178cc, 0x178d8, 0x178ee, 0x178f2, 0x178f4, 0x17902, 0x17904, 0x17908, 0x17910, 0x1791e, 0x17920, 0x1793c, 0x17940, 0x17978, 0x17986, 0x1798c, 0x17998, 0x179b0, 0x179be, 0x179ce, 0x179dc, 0x179e2, 0x179e4, 0x179e8, 0x179f6, 0x17a04, 0x17a08, 0x17a10, 0x17a1e, 0x17a20, 0x17a3c, 0x17a40, 0x17a78, 0x17af0, 0x17b06, 0x17b0c, 0x17b18, 0x17b30, 0x17b3e, 0x17b60, 0x17b7c, 0x17b8e, 0x17b9c, 0x17bb8, 0x17bc4, 0x17bc8, 0x17bd0, 0x17bde, 0x17be6, 0x17bec, 0x17c2e, 0x17c32, 0x17c34, 0x17c4e, 0x17c5c, 0x17c62, 0x17c64, 0x17c68, 0x17c76, 0x17c8e, 0x17c9c, 0x17cb8, 0x17cc2, 0x17cc4, 0x17cc8, 0x17cd0, 0x17cde, 0x17ce6, 0x17cec, 0x17d0e, 0x17d1c, 0x17d38, 0x17d70, 0x17d82, 0x17d84, 0x17d88, 0x17d90, 0x17d9e, 0x17da0, 0x17dbc, 0x17dc6, 0x17dcc, 0x17dd8, 0x17dee, 0x17e26, 0x17e2c, 0x17e3a, 0x17e46, 0x17e4c, 0x17e58, 0x17e6e, 0x17e72, 0x17e74, 0x17e86, 0x17e8c, 0x17e98, 0x17eb0, 0x17ece, 0x17edc, 0x17ee2, 0x17ee4, 0x17ee8, 0x17ef6, 0x1813a, 0x18172, 0x18174, 0x18216, 0x18226, 0x1823a, 0x1824c, 0x18258, 0x1826e, 0x18272, 0x18274, 0x18298, 0x182be, 0x182e2, 0x182e4, 0x182e8, 0x182f6, 0x1835e, 0x1837a, 0x183ae, 0x183d6, 0x18416, 0x18426, 0x1842c, 0x1843a, 0x18446, 0x18458, 0x1846e, 0x18472, 0x18474, 0x18486, 0x184b0, 0x184be, 0x184ce, 0x184dc, 0x184e2, 0x184e4, 0x184e8, 0x184f6, 0x18506, 0x1850c, 0x18518, 0x18530, 0x1853e, 0x18560, 0x1857c, 0x1858e, 0x1859c, 0x185b8, 0x185c2, 0x185c4, 0x185c8, 0x185d0, 0x185de, 0x185e6, 0x185ec, 0x185fa, 0x18612, 0x18614, 0x18622, 0x18628, 0x18636, 0x18642, 0x18650, 0x1865e, 0x1867a, 0x18682, 0x18684, 0x18688, 0x18690, 0x1869e, 0x186a0, 0x186bc, 0x186c6, 0x186cc, 0x186d8, 0x186ee, 0x186f2, 0x186f4, 0x1872e, 0x1874e, 0x1875c, 0x18796, 0x187a6, 0x187ac, 0x187d2, 0x187d4, 0x18826, 0x1882c, 0x1883a, 0x18846, 0x1884c, 0x18858, 0x1886e, 0x18872, 0x18874, 0x18886, 0x18898, 0x188b0, 0x188be, 0x188ce, 0x188dc, 0x188e2, 0x188e4, 0x188e8, 0x188f6, 0x1890c, 0x18930, 0x1893e, 0x18960, 0x1897c, 0x1898e, 0x189b8, 0x189c2, 0x189c8, 0x189d0, 0x189de, 0x189e6, 0x189ec, 0x189fa, 0x18a18, 0x18a30, 0x18a3e, 0x18a60, 0x18a7c, 0x18ac0, 0x18af8, 0x18b1c, 0x18b38, 0x18b70, 0x18b7e, 0x18b82, 0x18b84, 0x18b88, 0x18b90, 0x18b9e, 0x18ba0, 0x18bbc, 0x18bc6, 0x18bcc, 0x18bd8, 0x18bee, 0x18bf2, 0x18bf4, 0x18c22, 0x18c24, 0x18c28, 0x18c36, 0x18c42, 0x18c48, 0x18c50, 0x18c5e, 0x18c66, 0x18c7a, 0x18c82, 0x18c84, 0x18c90, 0x18c9e, 0x18ca0, 0x18cbc, 0x18ccc, 0x18cf2, 0x18cf4, 0x18d04, 0x18d08, 0x18d10, 0x18d1e, 0x18d20, 0x18d3c, 0x18d40, 0x18d78, 0x18d86, 0x18d98, 0x18dce, 0x18de2, 0x18de4, 0x18de8, 0x18e2e, 0x18e32, 0x18e34, 0x18e4e, 0x18e5c, 0x18e62, 0x18e64, 0x18e68, 0x18e8e, 0x18e9c, 0x18eb8, 0x18ec2, 0x18ec4, 0x18ec8, 0x18ed0, 0x18efa, 0x18f16, 0x18f26, 0x18f2c, 0x18f46, 0x18f4c, 0x18f58, 0x18f6e, 0x18f8a, 0x18f92, 0x18f94, 0x18fa2, 0x18fa4, 0x18fa8, 0x18fb6, 0x1902c, 0x1903a, 0x19046, 0x1904c, 0x19058, 0x19072, 0x19074, 0x19086, 0x19098, 0x190b0, 0x190be, 0x190ce, 0x190dc, 0x190e2, 0x190e8, 0x190f6, 0x19106, 0x1910c, 0x19130, 0x1913e, 0x19160, 0x1917c, 0x1918e, 0x1919c, 0x191b8, 0x191c2, 0x191c8, 0x191d0, 0x191de, 0x191e6, 0x191ec, 0x191fa, 0x19218, 0x1923e, 0x19260, 0x1927c, 0x192c0, 0x192f8, 0x19338, 0x19370, 0x1937e, 0x19382, 0x19384, 0x19390, 0x1939e, 0x193a0, 0x193bc, 0x193c6, 0x193cc, 0x193d8, 0x193ee, 0x193f2, 0x193f4, 0x19430, 0x1943e, 0x19460, 0x1947c, 0x194c0, 0x194f8, 0x195f0, 0x19638, 0x19670, 0x1967e, 0x196e0, 0x196fc, 0x19702, 0x19704, 0x19708, 0x19710, 0x19720, 0x1973c, 0x19740, 0x19778, 0x19786, 0x1978c, 0x19798, 0x197b0, 0x197be, 0x197ce, 0x197dc, 0x197e2, 0x197e4, 0x197e8, 0x19822, 0x19824, 0x19842, 0x19848, 0x19850, 0x1985e, 0x19866, 0x1987a, 0x19882, 0x19884, 0x19890, 0x1989e, 0x198a0, 0x198bc, 0x198cc, 0x198f2, 0x198f4, 0x19902, 0x19908, 0x1991e, 0x19920, 0x1993c, 0x19940, 0x19978, 0x19986, 0x19998, 0x199ce, 0x199e2, 0x199e4, 0x199e8, 0x19a08, 0x19a10, 0x19a1e, 0x19a20, 0x19a3c, 0x19a40, 0x19a78, 0x19af0, 0x19b18, 0x19b3e, 0x19b60, 0x19b9c, 0x19bc2, 0x19bc4, 0x19bc8, 0x19bd0, 0x19be6, 0x19c2e, 0x19c34, 0x19c4e, 0x19c5c, 0x19c62, 0x19c64, 0x19c68, 0x19c8e, 0x19c9c, 0x19cb8, 0x19cc2, 0x19cc8, 0x19cd0, 0x19ce6, 0x19cfa, 0x19d0e, 0x19d1c, 0x19d38, 0x19d70, 0x19d7e, 0x19d82, 0x19d84, 0x19d88, 0x19d90, 0x19da0, 0x19dcc, 0x19df2, 0x19df4, 0x19e16, 0x19e26, 0x19e2c, 0x19e46, 0x19e4c, 0x19e58, 0x19e74, 0x19e86, 0x19e8c, 0x19e98, 0x19eb0, 0x19ebe, 0x19ece, 0x19ee2, 0x19ee4, 0x19ee8, 0x19f0a, 0x19f12, 0x19f14, 0x19f22, 0x19f24, 0x19f28, 0x19f42, 0x19f44, 0x19f48, 0x19f50, 0x19f5e, 0x19f6c, 0x19f9a, 0x19fae, 0x19fb2, 0x19fb4, 0x1a046, 0x1a04c, 0x1a072, 0x1a074, 0x1a086, 0x1a08c, 0x1a098, 0x1a0b0, 0x1a0be, 0x1a0e2, 0x1a0e4, 0x1a0e8, 0x1a0f6, 0x1a106, 0x1a10c, 0x1a118, 0x1a130, 0x1a13e, 0x1a160, 0x1a17c, 0x1a18e, 0x1a19c, 0x1a1b8, 0x1a1c2, 0x1a1c4, 0x1a1c8, 0x1a1d0, 0x1a1de, 0x1a1e6, 0x1a1ec, 0x1a218, 0x1a230, 0x1a23e, 0x1a260, 0x1a27c, 0x1a2c0, 0x1a2f8, 0x1a31c, 0x1a338, 0x1a370, 0x1a37e, 0x1a382, 0x1a384, 0x1a388, 0x1a390, 0x1a39e, 0x1a3a0, 0x1a3bc, 0x1a3c6, 0x1a3cc, 0x1a3d8, 0x1a3ee, 0x1a3f2, 0x1a3f4, 0x1a418, 0x1a430, 0x1a43e, 0x1a460, 0x1a47c, 0x1a4c0, 0x1a4f8, 0x1a5f0, 0x1a61c, 0x1a638, 0x1a670, 0x1a67e, 0x1a6e0, 0x1a6fc, 0x1a702, 0x1a704, 0x1a708, 0x1a710, 0x1a71e, 0x1a720, 0x1a73c, 0x1a740, 0x1a778, 0x1a786, 0x1a78c, 0x1a798, 0x1a7b0, 0x1a7be, 0x1a7ce, 0x1a7dc, 0x1a7e2, 0x1a7e4, 0x1a7e8, 0x1a830, 0x1a860, 0x1a87c, 0x1a8c0, 0x1a8f8, 0x1a9f0, 0x1abe0, 0x1ac70, 0x1ac7e, 0x1ace0, 0x1acfc, 0x1adc0, 0x1adf8, 0x1ae04, 0x1ae08, 0x1ae10, 0x1ae20, 0x1ae3c, 0x1ae40, 0x1ae78, 0x1aef0, 0x1af06, 0x1af0c, 0x1af18, 0x1af30, 0x1af3e, 0x1af60, 0x1af7c, 0x1af8e, 0x1af9c, 0x1afb8, 0x1afc4, 0x1afc8, 0x1afd0, 0x1afde, 0x1b042, 0x1b05e, 0x1b07a, 0x1b082, 0x1b084, 0x1b088, 0x1b090, 0x1b09e, 0x1b0a0, 0x1b0bc, 0x1b0cc, 0x1b0f2, 0x1b0f4, 0x1b102, 0x1b104, 0x1b108, 0x1b110, 0x1b11e, 0x1b120, 0x1b13c, 0x1b140, 0x1b178, 0x1b186, 0x1b198, 0x1b1ce, 0x1b1e2, 0x1b1e4, 0x1b1e8, 0x1b204, 0x1b208, 0x1b210, 0x1b21e, 0x1b220, 0x1b23c, 0x1b240, 0x1b278, 0x1b2f0, 0x1b30c, 0x1b33e, 0x1b360, 0x1b39c, 0x1b3c2, 0x1b3c4, 0x1b3c8, 0x1b3d0, 0x1b3e6, 0x1b410, 0x1b41e, 0x1b420, 0x1b43c, 0x1b440, 0x1b478, 0x1b4f0, 0x1b5e0, 0x1b618, 0x1b660, 0x1b67c, 0x1b6c0, 0x1b738, 0x1b782, 0x1b784, 0x1b788, 0x1b790, 0x1b79e, 0x1b7a0, 0x1b7cc, 0x1b82e, 0x1b84e, 0x1b85c, 0x1b88e, 0x1b89c, 0x1b8b8, 0x1b8c2, 0x1b8c4, 0x1b8c8, 0x1b8d0, 0x1b8e6, 0x1b8fa, 0x1b90e, 0x1b91c, 0x1b938, 0x1b970, 0x1b97e, 0x1b982, 0x1b984, 0x1b988, 0x1b990, 0x1b99e, 0x1b9a0, 0x1b9cc, 0x1b9f2, 0x1b9f4, 0x1ba0e, 0x1ba1c, 0x1ba38, 0x1ba70, 0x1ba7e, 0x1bae0, 0x1bafc, 0x1bb08, 0x1bb10, 0x1bb20, 0x1bb3c, 0x1bb40, 0x1bb98, 0x1bbce, 0x1bbe2, 0x1bbe4, 0x1bbe8, 0x1bc16, 0x1bc26, 0x1bc2c, 0x1bc46, 0x1bc4c, 0x1bc58, 0x1bc72, 0x1bc74, 0x1bc86, 0x1bc8c, 0x1bc98, 0x1bcb0, 0x1bcbe, 0x1bcce, 0x1bce2, 0x1bce4, 0x1bce8, 0x1bd06, 0x1bd0c, 0x1bd18, 0x1bd30, 0x1bd3e, 0x1bd60, 0x1bd7c, 0x1bd9c, 0x1bdc2, 0x1bdc4, 0x1bdc8, 0x1bdd0, 0x1bde6, 0x1bdfa, 0x1be12, 0x1be14, 0x1be22, 0x1be24, 0x1be28, 0x1be42, 0x1be44, 0x1be48, 0x1be50, 0x1be5e, 0x1be66, 0x1be82, 0x1be84, 0x1be88, 0x1be90, 0x1be9e, 0x1bea0, 0x1bebc, 0x1becc, 0x1bef4, 0x1bf1a, 0x1bf2e, 0x1bf32, 0x1bf34, 0x1bf4e, 0x1bf5c, 0x1bf62, 0x1bf64, 0x1bf68, 0x1c09a, 0x1c0b2, 0x1c0b4, 0x1c11a, 0x1c132, 0x1c134, 0x1c162, 0x1c164, 0x1c168, 0x1c176, 0x1c1ba, 0x1c21a, 0x1c232, 0x1c234, 0x1c24e, 0x1c25c, 0x1c262, 0x1c264, 0x1c268, 0x1c276, 0x1c28e, 0x1c2c2, 0x1c2c4, 0x1c2c8, 0x1c2d0, 0x1c2de, 0x1c2e6, 0x1c2ec, 0x1c2fa, 0x1c316, 0x1c326, 0x1c33a, 0x1c346, 0x1c34c, 0x1c372, 0x1c374, 0x1c41a, 0x1c42e, 0x1c432, 0x1c434, 0x1c44e, 0x1c45c, 0x1c462, 0x1c464, 0x1c468, 0x1c476, 0x1c48e, 0x1c49c, 0x1c4b8, 0x1c4c2, 0x1c4c8, 0x1c4d0, 0x1c4de, 0x1c4e6, 0x1c4ec, 0x1c4fa, 0x1c51c, 0x1c538, 0x1c570, 0x1c57e, 0x1c582, 0x1c584, 0x1c588, 0x1c590, 0x1c59e, 0x1c5a0, 0x1c5bc, 0x1c5c6, 0x1c5cc, 0x1c5d8, 0x1c5ee, 0x1c5f2, 0x1c5f4, 0x1c616, 0x1c626, 0x1c62c, 0x1c63a, 0x1c646, 0x1c64c, 0x1c658, 0x1c66e, 0x1c672, 0x1c674, 0x1c686, 0x1c68c, 0x1c698, 0x1c6b0, 0x1c6be, 0x1c6ce, 0x1c6dc, 0x1c6e2, 0x1c6e4, 0x1c6e8, 0x1c712, 0x1c714, 0x1c722, 0x1c728, 0x1c736, 0x1c742, 0x1c744, 0x1c748, 0x1c750, 0x1c75e, 0x1c766, 0x1c76c, 0x1c77a, 0x1c7ae, 0x1c7d6, 0x1c7ea, 0x1c81a, 0x1c82e, 0x1c832, 0x1c834, 0x1c84e, 0x1c85c, 0x1c862, 0x1c864, 0x1c868, 0x1c876, 0x1c88e, 0x1c89c, 0x1c8b8, 0x1c8c2, 0x1c8c8, 0x1c8d0, 0x1c8de, 0x1c8e6, 0x1c8ec, 0x1c8fa, 0x1c90e, 0x1c938, 0x1c970, 0x1c97e, 0x1c982, 0x1c984, 0x1c990, 0x1c99e, 0x1c9a0, 0x1c9bc, 0x1c9c6, 0x1c9cc, 0x1c9d8, 0x1c9ee, 0x1c9f2, 0x1c9f4, 0x1ca38, 0x1ca70, 0x1ca7e, 0x1cae0, 0x1cafc, 0x1cb02, 0x1cb04, 0x1cb08, 0x1cb10, 0x1cb20, 0x1cb3c, 0x1cb40, 0x1cb78, 0x1cb86, 0x1cb8c, 0x1cb98, 0x1cbb0, 0x1cbbe, 0x1cbce, 0x1cbdc, 0x1cbe2, 0x1cbe4, 0x1cbe8, 0x1cbf6, 0x1cc16, 0x1cc26, 0x1cc2c, 0x1cc3a, 0x1cc46, 0x1cc58, 0x1cc72, 0x1cc74, 0x1cc86, 0x1ccb0, 0x1ccbe, 0x1ccce, 0x1cce2, 0x1cce4, 0x1cce8, 0x1cd06, 0x1cd0c, 0x1cd18, 0x1cd30, 0x1cd3e, 0x1cd60, 0x1cd7c, 0x1cd9c, 0x1cdc2, 0x1cdc4, 0x1cdc8, 0x1cdd0, 0x1cdde, 0x1cde6, 0x1cdfa, 0x1ce22, 0x1ce28, 0x1ce42, 0x1ce50, 0x1ce5e, 0x1ce66, 0x1ce7a, 0x1ce82, 0x1ce84, 0x1ce88, 0x1ce90, 0x1ce9e, 0x1cea0, 0x1cebc, 0x1cecc, 0x1cef2, 0x1cef4, 0x1cf2e, 0x1cf32, 0x1cf34, 0x1cf4e, 0x1cf5c, 0x1cf62, 0x1cf64, 0x1cf68, 0x1cf96, 0x1cfa6, 0x1cfac, 0x1cfca, 0x1cfd2, 0x1cfd4, 0x1d02e, 0x1d032, 0x1d034, 0x1d04e, 0x1d05c, 0x1d062, 0x1d064, 0x1d068, 0x1d076, 0x1d08e, 0x1d09c, 0x1d0b8, 0x1d0c2, 0x1d0c4, 0x1d0c8, 0x1d0d0, 0x1d0de, 0x1d0e6, 0x1d0ec, 0x1d0fa, 0x1d11c, 0x1d138, 0x1d170, 0x1d17e, 0x1d182, 0x1d184, 0x1d188, 0x1d190, 0x1d19e, 0x1d1a0, 0x1d1bc, 0x1d1c6, 0x1d1cc, 0x1d1d8, 0x1d1ee, 0x1d1f2, 0x1d1f4, 0x1d21c, 0x1d238, 0x1d270, 0x1d27e, 0x1d2e0, 0x1d2fc, 0x1d302, 0x1d304, 0x1d308, 0x1d310, 0x1d31e, 0x1d320, 0x1d33c, 0x1d340, 0x1d378, 0x1d386, 0x1d38c, 0x1d398, 0x1d3b0, 0x1d3be, 0x1d3ce, 0x1d3dc, 0x1d3e2, 0x1d3e4, 0x1d3e8, 0x1d3f6, 0x1d470, 0x1d47e, 0x1d4e0, 0x1d4fc, 0x1d5c0, 0x1d5f8, 0x1d604, 0x1d608, 0x1d610, 0x1d620, 0x1d640, 0x1d678, 0x1d6f0, 0x1d706, 0x1d70c, 0x1d718, 0x1d730, 0x1d73e, 0x1d760, 0x1d77c, 0x1d78e, 0x1d79c, 0x1d7b8, 0x1d7c2, 0x1d7c4, 0x1d7c8, 0x1d7d0, 0x1d7de, 0x1d7e6, 0x1d7ec, 0x1d826, 0x1d82c, 0x1d83a, 0x1d846, 0x1d84c, 0x1d858, 0x1d872, 0x1d874, 0x1d886, 0x1d88c, 0x1d898, 0x1d8b0, 0x1d8be, 0x1d8ce, 0x1d8e2, 0x1d8e4, 0x1d8e8, 0x1d8f6, 0x1d90c, 0x1d918, 0x1d930, 0x1d93e, 0x1d960, 0x1d97c, 0x1d99c, 0x1d9c2, 0x1d9c4, 0x1d9c8, 0x1d9d0, 0x1d9e6, 0x1d9fa, 0x1da0c, 0x1da18, 0x1da30, 0x1da3e, 0x1da60, 0x1da7c, 0x1dac0, 0x1daf8, 0x1db38, 0x1db82, 0x1db84, 0x1db88, 0x1db90, 0x1db9e, 0x1dba0, 0x1dbcc, 0x1dbf2, 0x1dbf4, 0x1dc22, 0x1dc42, 0x1dc44, 0x1dc48, 0x1dc50, 0x1dc5e, 0x1dc66, 0x1dc7a, 0x1dc82, 0x1dc84, 0x1dc88, 0x1dc90, 0x1dc9e, 0x1dca0, 0x1dcbc, 0x1dccc, 0x1dcf2, 0x1dcf4, 0x1dd04, 0x1dd08, 0x1dd10, 0x1dd1e, 0x1dd20, 0x1dd3c, 0x1dd40, 0x1dd78, 0x1dd86, 0x1dd98, 0x1ddce, 0x1dde2, 0x1dde4, 0x1dde8, 0x1de2e, 0x1de32, 0x1de34, 0x1de4e, 0x1de5c, 0x1de62, 0x1de64, 0x1de68, 0x1de8e, 0x1de9c, 0x1deb8, 0x1dec2, 0x1dec4, 0x1dec8, 0x1ded0, 0x1dee6, 0x1defa, 0x1df16, 0x1df26, 0x1df2c, 0x1df46, 0x1df4c, 0x1df58, 0x1df72, 0x1df74, 0x1df8a, 0x1df92, 0x1df94, 0x1dfa2, 0x1dfa4, 0x1dfa8, 0x1e08a, 0x1e092, 0x1e094, 0x1e0a2, 0x1e0a4, 0x1e0a8, 0x1e0b6, 0x1e0da, 0x1e10a, 0x1e112, 0x1e114, 0x1e122, 0x1e124, 0x1e128, 0x1e136, 0x1e142, 0x1e144, 0x1e148, 0x1e150, 0x1e166, 0x1e16c, 0x1e17a, 0x1e19a, 0x1e1b2, 0x1e1b4, 0x1e20a, 0x1e212, 0x1e214, 0x1e222, 0x1e224, 0x1e228, 0x1e236, 0x1e242, 0x1e248, 0x1e250, 0x1e25e, 0x1e266, 0x1e26c, 0x1e27a, 0x1e282, 0x1e284, 0x1e288, 0x1e290, 0x1e2a0, 0x1e2bc, 0x1e2c6, 0x1e2cc, 0x1e2d8, 0x1e2ee, 0x1e2f2, 0x1e2f4, 0x1e31a, 0x1e332, 0x1e334, 0x1e35c, 0x1e362, 0x1e364, 0x1e368, 0x1e3ba, 0x1e40a, 0x1e412, 0x1e414, 0x1e422, 0x1e428, 0x1e436, 0x1e442, 0x1e448, 0x1e450, 0x1e45e, 0x1e466, 0x1e46c, 0x1e47a, 0x1e482, 0x1e484, 0x1e490, 0x1e49e, 0x1e4a0, 0x1e4bc, 0x1e4c6, 0x1e4cc, 0x1e4d8, 0x1e4ee, 0x1e4f2, 0x1e4f4, 0x1e502, 0x1e504, 0x1e508, 0x1e510, 0x1e51e, 0x1e520, 0x1e53c, 0x1e540, 0x1e578, 0x1e586, 0x1e58c, 0x1e598, 0x1e5b0, 0x1e5be, 0x1e5ce, 0x1e5dc, 0x1e5e2, 0x1e5e4, 0x1e5e8, 0x1e5f6, 0x1e61a, 0x1e62e, 0x1e632, 0x1e634, 0x1e64e, 0x1e65c, 0x1e662, 0x1e668, 0x1e68e, 0x1e69c, 0x1e6b8, 0x1e6c2, 0x1e6c4, 0x1e6c8, 0x1e6d0, 0x1e6e6, 0x1e6fa, 0x1e716, 0x1e726, 0x1e72c, 0x1e73a, 0x1e746, 0x1e74c, 0x1e758, 0x1e772, 0x1e774, 0x1e792, 0x1e794, 0x1e7a2, 0x1e7a4, 0x1e7a8, 0x1e7b6, 0x1e812, 0x1e814, 0x1e822, 0x1e824, 0x1e828, 0x1e836, 0x1e842, 0x1e844, 0x1e848, 0x1e850, 0x1e85e, 0x1e866, 0x1e86c, 0x1e87a, 0x1e882, 0x1e884, 0x1e888, 0x1e890, 0x1e89e, 0x1e8a0, 0x1e8bc, 0x1e8c6, 0x1e8cc, 0x1e8d8, 0x1e8ee, 0x1e8f2, 0x1e8f4, 0x1e902, 0x1e904, 0x1e908, 0x1e910, 0x1e920, 0x1e93c, 0x1e940, 0x1e978, 0x1e986, 0x1e98c, 0x1e998, 0x1e9b0, 0x1e9be, 0x1e9ce, 0x1e9dc, 0x1e9e2, 0x1e9e4, 0x1e9e8, 0x1e9f6, 0x1ea04, 0x1ea08, 0x1ea10, 0x1ea20, 0x1ea40, 0x1ea78, 0x1eaf0, 0x1eb06, 0x1eb0c, 0x1eb18, 0x1eb30, 0x1eb3e, 0x1eb60, 0x1eb7c, 0x1eb8e, 0x1eb9c, 0x1ebb8, 0x1ebc2, 0x1ebc4, 0x1ebc8, 0x1ebd0, 0x1ebde, 0x1ebe6, 0x1ebec, 0x1ec1a, 0x1ec2e, 0x1ec32, 0x1ec34, 0x1ec4e, 0x1ec5c, 0x1ec62, 0x1ec64, 0x1ec68, 0x1ec8e, 0x1ec9c, 0x1ecb8, 0x1ecc2, 0x1ecc4, 0x1ecc8, 0x1ecd0, 0x1ece6, 0x1ecfa, 0x1ed0e, 0x1ed1c, 0x1ed38, 0x1ed70, 0x1ed7e, 0x1ed82, 0x1ed84, 0x1ed88, 0x1ed90, 0x1ed9e, 0x1eda0, 0x1edcc, 0x1edf2, 0x1edf4, 0x1ee16, 0x1ee26, 0x1ee2c, 0x1ee3a, 0x1ee46, 0x1ee4c, 0x1ee58, 0x1ee6e, 0x1ee72, 0x1ee74, 0x1ee86, 0x1ee8c, 0x1ee98, 0x1eeb0, 0x1eebe, 0x1eece, 0x1eedc, 0x1eee2, 0x1eee4, 0x1eee8, 0x1ef12, 0x1ef22, 0x1ef24, 0x1ef28, 0x1ef36, 0x1ef42, 0x1ef44, 0x1ef48, 0x1ef50, 0x1ef5e, 0x1ef66, 0x1ef6c, 0x1ef7a, 0x1efae, 0x1efb2, 0x1efb4, 0x1efd6, 0x1f096, 0x1f0a6, 0x1f0ac, 0x1f0ba, 0x1f0ca, 0x1f0d2, 0x1f0d4, 0x1f116, 0x1f126, 0x1f12c, 0x1f13a, 0x1f146, 0x1f14c, 0x1f158, 0x1f16e, 0x1f172, 0x1f174, 0x1f18a, 0x1f192, 0x1f194, 0x1f1a2, 0x1f1a4, 0x1f1a8, 0x1f1da, 0x1f216, 0x1f226, 0x1f22c, 0x1f23a, 0x1f246, 0x1f258, 0x1f26e, 0x1f272, 0x1f274, 0x1f286, 0x1f28c, 0x1f298, 0x1f2b0, 0x1f2be, 0x1f2ce, 0x1f2dc, 0x1f2e2, 0x1f2e4, 0x1f2e8, 0x1f2f6, 0x1f30a, 0x1f312, 0x1f314, 0x1f322, 0x1f328, 0x1f342, 0x1f344, 0x1f348, 0x1f350, 0x1f35e, 0x1f366, 0x1f37a, 0x1f39a, 0x1f3ae, 0x1f3b2, 0x1f3b4, 0x1f416, 0x1f426, 0x1f42c, 0x1f43a, 0x1f446, 0x1f44c, 0x1f458, 0x1f46e, 0x1f472, 0x1f474, 0x1f486, 0x1f48c, 0x1f498, 0x1f4b0, 0x1f4be, 0x1f4ce, 0x1f4dc, 0x1f4e2, 0x1f4e4, 0x1f4e8, 0x1f4f6, 0x1f506, 0x1f50c, 0x1f518, 0x1f530, 0x1f53e, 0x1f560, 0x1f57c, 0x1f58e, 0x1f59c, 0x1f5b8, 0x1f5c2, 0x1f5c4, 0x1f5c8, 0x1f5d0, 0x1f5de, 0x1f5e6, 0x1f5ec, 0x1f5fa, 0x1f60a, 0x1f612, 0x1f614, 0x1f622, 0x1f624, 0x1f628, 0x1f636, 0x1f642, 0x1f644, 0x1f648, 0x1f650, 0x1f65e, 0x1f666, 0x1f67a, 0x1f682, 0x1f684, 0x1f688, 0x1f690, 0x1f69e, 0x1f6a0, 0x1f6bc, 0x1f6cc, 0x1f6f2, 0x1f6f4, 0x1f71a, 0x1f72e, 0x1f732, 0x1f734, 0x1f74e, 0x1f75c, 0x1f762, 0x1f764, 0x1f768, 0x1f776, 0x1f796, 0x1f7a6, 0x1f7ac, 0x1f7ba, 0x1f7d2, 0x1f7d4, 0x1f89a, 0x1f8ae, 0x1f8b2, 0x1f8b4, 0x1f8d6, 0x1f8ea, 0x1f91a, 0x1f92e, 0x1f932, 0x1f934, 0x1f94e, 0x1f95c, 0x1f962, 0x1f964, 0x1f968, 0x1f976, 0x1f996, 0x1f9a6, 0x1f9ac, 0x1f9ba, 0x1f9ca, 0x1f9d2, 0x1f9d4, 0x1fa1a, 0x1fa2e, 0x1fa32, 0x1fa34, 0x1fa4e, 0x1fa5c, 0x1fa62, 0x1fa64, 0x1fa68, 0x1fa76, 0x1fa8e, 0x1fa9c, 0x1fab8, 0x1fac2, 0x1fac4, 0x1fac8, 0x1fad0, 0x1fade, 0x1fae6, 0x1faec, 0x1fb16, 0x1fb26, 0x1fb2c, 0x1fb3a, 0x1fb46, 0x1fb4c, 0x1fb58, 0x1fb6e, 0x1fb72, 0x1fb74, 0x1fb8a, 0x1fb92, 0x1fb94, 0x1fba2, 0x1fba4, 0x1fba8, 0x1fbb6, 0x1fbda}; + + /// + /// This table contains to codewords for all symbols. + /// + private static readonly int[] CODEWORD_TABLE = {2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511, 873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815, 814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752, 2739, 2737, 2728, 2727, 2725, 2730, 2785, 2783, 2778, 2777, 2775, 2780, 787, 781, 747, 739, 736, 2413, 754, 752, 1719, 692, 689, 681, 2371, 678, 2369, 700, 697, 694, 703, 1688, 1686, 642, 638, 2343, 631, 2341, 627, 2338, 651, 646, 643, 2345, 654, 652, 1652, 1650, 1647, 1654, 601, 599, 2322, 596, 2321, 594, 2319, 2317, 611, 610, 608, 606, 2324, 603, 2323, 615, 614, 612, 1617, 1616, 1614, 1612, 616, 1619, 1618, 2575, 2538, 2536, 905, 901, 898, 909, 2509, 2507, 2504, 870, 867, 864, 860, 2512, 875, 872, 1781, 2490, 2489, 2487, 2485, 1748, 836, 834, 832, 830, 2494, 827, 2492, 843, 841, 839, 845, 1765, 1763, 2701, 2676, 2674, 2653, 2648, 2656, 2634, 2633, 2631, 2629, 1821, 2638, 2636, 2770, 2763, 2761, 2750, 2745, 2753, 2736, 2735, 2733, 2731, 1848, 2740, 2738, 2786, 2784, 591, 588, 576, 569, 566, 2296, 1590, 537, 534, 526, 2276, 522, 2274, 545, 542, 539, 548, 1572, 1570, 481, 2245, 466, 2242, 462, 2239, 492, 485, 482, 2249, 496, 494, 1534, 1531, 1528, 1538, 413, 2196, 406, 2191, 2188, 425, 419, 2202, 415, 2199, 432, 430, 427, 1472, 1467, 1464, 433, 1476, 1474, 368, 367, 2160, 365, 2159, 362, 2157, 2155, 2152, 378, 377, 375, 2166, 372, 2165, 369, 2162, 383, 381, 379, 2168, 1419, 1418, 1416, 1414, 385, 1411, 384, 1423, 1422, 1420, 1424, 2461, 802, 2441, 2439, 790, 786, 783, 794, 2409, 2406, 2403, 750, 742, 738, 2414, 756, 753, 1720, 2367, 2365, 2362, 2359, 1663, 693, 691, 684, 2373, 680, 2370, 702, 699, 696, 704, 1690, 1687, 2337, 2336, 2334, 2332, 1624, 2329, 1622, 640, 637, 2344, 634, 2342, 630, 2340, 650, 648, 645, 2346, 655, 653, 1653, 1651, 1649, 1655, 2612, 2597, 2595, 2571, 2568, 2565, 2576, 2534, 2529, 2526, 1787, 2540, 2537, 907, 904, 900, 910, 2503, 2502, 2500, 2498, 1768, 2495, 1767, 2510, 2508, 2506, 869, 866, 863, 2513, 876, 874, 1782, 2720, 2713, 2711, 2697, 2694, 2691, 2702, 2672, 2670, 2664, 1828, 2678, 2675, 2647, 2646, 2644, 2642, 1823, 2639, 1822, 2654, 2652, 2650, 2657, 2771, 1855, 2765, 2762, 1850, 1849, 2751, 2749, 2747, 2754, 353, 2148, 344, 342, 336, 2142, 332, 2140, 345, 1375, 1373, 306, 2130, 299, 2128, 295, 2125, 319, 314, 311, 2132, 1354, 1352, 1349, 1356, 262, 257, 2101, 253, 2096, 2093, 274, 273, 267, 2107, 263, 2104, 280, 278, 275, 1316, 1311, 1308, 1320, 1318, 2052, 202, 2050, 2044, 2040, 219, 2063, 212, 2060, 208, 2055, 224, 221, 2066, 1260, 1258, 1252, 231, 1248, 229, 1266, 1264, 1261, 1268, 155, 1998, 153, 1996, 1994, 1991, 1988, 165, 164, 2007, 162, 2006, 159, 2003, 2000, 172, 171, 169, 2012, 166, 2010, 1186, 1184, 1182, 1179, 175, 1176, 173, 1192, 1191, 1189, 1187, 176, 1194, 1193, 2313, 2307, 2305, 592, 589, 2294, 2292, 2289, 578, 572, 568, 2297, 580, 1591, 2272, 2267, 2264, 1547, 538, 536, 529, 2278, 525, 2275, 547, 544, 541, 1574, 1571, 2237, 2235, 2229, 1493, 2225, 1489, 478, 2247, 470, 2244, 465, 2241, 493, 488, 484, 2250, 498, 495, 1536, 1533, 1530, 1539, 2187, 2186, 2184, 2182, 1432, 2179, 1430, 2176, 1427, 414, 412, 2197, 409, 2195, 405, 2193, 2190, 426, 424, 421, 2203, 418, 2201, 431, 429, 1473, 1471, 1469, 1466, 434, 1477, 1475, 2478, 2472, 2470, 2459, 2457, 2454, 2462, 803, 2437, 2432, 2429, 1726, 2443, 2440, 792, 789, 785, 2401, 2399, 2393, 1702, 2389, 1699, 2411, 2408, 2405, 745, 741, 2415, 758, 755, 1721, 2358, 2357, 2355, 2353, 1661, 2350, 1660, 2347, 1657, 2368, 2366, 2364, 2361, 1666, 690, 687, 2374, 683, 2372, 701, 698, 705, 1691, 1689, 2619, 2617, 2610, 2608, 2605, 2613, 2593, 2588, 2585, 1803, 2599, 2596, 2563, 2561, 2555, 1797, 2551, 1795, 2573, 2570, 2567, 2577, 2525, 2524, 2522, 2520, 1786, 2517, 1785, 2514, 1783, 2535, 2533, 2531, 2528, 1788, 2541, 2539, 906, 903, 911, 2721, 1844, 2715, 2712, 1838, 1836, 2699, 2696, 2693, 2703, 1827, 1826, 1824, 2673, 2671, 2669, 2666, 1829, 2679, 2677, 1858, 1857, 2772, 1854, 1853, 1851, 1856, 2766, 2764, 143, 1987, 139, 1986, 135, 133, 131, 1984, 128, 1983, 125, 1981, 138, 137, 136, 1985, 1133, 1132, 1130, 112, 110, 1974, 107, 1973, 104, 1971, 1969, 122, 121, 119, 117, 1977, 114, 1976, 124, 1115, 1114, 1112, 1110, 1117, 1116, 84, 83, 1953, 81, 1952, 78, 1950, 1948, 1945, 94, 93, 91, 1959, 88, 1958, 85, 1955, 99, 97, 95, 1961, 1086, 1085, 1083, 1081, 1078, 100, 1090, 1089, 1087, 1091, 49, 47, 1917, 44, 1915, 1913, 1910, 1907, 59, 1926, 56, 1925, 53, 1922, 1919, 66, 64, 1931, 61, 1929, 1042, 1040, 1038, 71, 1035, 70, 1032, 68, 1048, 1047, 1045, 1043, 1050, 1049, 12, 10, 1869, 1867, 1864, 1861, 21, 1880, 19, 1877, 1874, 1871, 28, 1888, 25, 1886, 22, 1883, 982, 980, 977, 974, 32, 30, 991, 989, 987, 984, 34, 995, 994, 992, 2151, 2150, 2147, 2146, 2144, 356, 355, 354, 2149, 2139, 2138, 2136, 2134, 1359, 343, 341, 338, 2143, 335, 2141, 348, 347, 346, 1376, 1374, 2124, 2123, 2121, 2119, 1326, 2116, 1324, 310, 308, 305, 2131, 302, 2129, 298, 2127, 320, 318, 316, 313, 2133, 322, 321, 1355, 1353, 1351, 1357, 2092, 2091, 2089, 2087, 1276, 2084, 1274, 2081, 1271, 259, 2102, 256, 2100, 252, 2098, 2095, 272, 269, 2108, 266, 2106, 281, 279, 277, 1317, 1315, 1313, 1310, 282, 1321, 1319, 2039, 2037, 2035, 2032, 1203, 2029, 1200, 1197, 207, 2053, 205, 2051, 201, 2049, 2046, 2043, 220, 218, 2064, 215, 2062, 211, 2059, 228, 226, 223, 2069, 1259, 1257, 1254, 232, 1251, 230, 1267, 1265, 1263, 2316, 2315, 2312, 2311, 2309, 2314, 2304, 2303, 2301, 2299, 1593, 2308, 2306, 590, 2288, 2287, 2285, 2283, 1578, 2280, 1577, 2295, 2293, 2291, 579, 577, 574, 571, 2298, 582, 581, 1592, 2263, 2262, 2260, 2258, 1545, 2255, 1544, 2252, 1541, 2273, 2271, 2269, 2266, 1550, 535, 532, 2279, 528, 2277, 546, 543, 549, 1575, 1573, 2224, 2222, 2220, 1486, 2217, 1485, 2214, 1482, 1479, 2238, 2236, 2234, 2231, 1496, 2228, 1492, 480, 477, 2248, 473, 2246, 469, 2243, 490, 487, 2251, 497, 1537, 1535, 1532, 2477, 2476, 2474, 2479, 2469, 2468, 2466, 2464, 1730, 2473, 2471, 2453, 2452, 2450, 2448, 1729, 2445, 1728, 2460, 2458, 2456, 2463, 805, 804, 2428, 2427, 2425, 2423, 1725, 2420, 1724, 2417, 1722, 2438, 2436, 2434, 2431, 1727, 2444, 2442, 793, 791, 788, 795, 2388, 2386, 2384, 1697, 2381, 1696, 2378, 1694, 1692, 2402, 2400, 2398, 2395, 1703, 2392, 1701, 2412, 2410, 2407, 751, 748, 744, 2416, 759, 757, 1807, 2620, 2618, 1806, 1805, 2611, 2609, 2607, 2614, 1802, 1801, 1799, 2594, 2592, 2590, 2587, 1804, 2600, 2598, 1794, 1793, 1791, 1789, 2564, 2562, 2560, 2557, 1798, 2554, 1796, 2574, 2572, 2569, 2578, 1847, 1846, 2722, 1843, 1842, 1840, 1845, 2716, 2714, 1835, 1834, 1832, 1830, 1839, 1837, 2700, 2698, 2695, 2704, 1817, 1811, 1810, 897, 862, 1777, 829, 826, 838, 1760, 1758, 808, 2481, 1741, 1740, 1738, 1743, 2624, 1818, 2726, 2776, 782, 740, 737, 1715, 686, 679, 695, 1682, 1680, 639, 628, 2339, 647, 644, 1645, 1643, 1640, 1648, 602, 600, 597, 595, 2320, 593, 2318, 609, 607, 604, 1611, 1610, 1608, 1606, 613, 1615, 1613, 2328, 926, 924, 892, 886, 899, 857, 850, 2505, 1778, 824, 823, 821, 819, 2488, 818, 2486, 833, 831, 828, 840, 1761, 1759, 2649, 2632, 2630, 2746, 2734, 2732, 2782, 2781, 570, 567, 1587, 531, 527, 523, 540, 1566, 1564, 476, 467, 463, 2240, 486, 483, 1524, 1521, 1518, 1529, 411, 403, 2192, 399, 2189, 423, 416, 1462, 1457, 1454, 428, 1468, 1465, 2210, 366, 363, 2158, 360, 2156, 357, 2153, 376, 373, 370, 2163, 1410, 1409, 1407, 1405, 382, 1402, 380, 1417, 1415, 1412, 1421, 2175, 2174, 777, 774, 771, 784, 732, 725, 722, 2404, 743, 1716, 676, 674, 668, 2363, 665, 2360, 685, 1684, 1681, 626, 624, 622, 2335, 620, 2333, 617, 2330, 641, 635, 649, 1646, 1644, 1642, 2566, 928, 925, 2530, 2527, 894, 891, 888, 2501, 2499, 2496, 858, 856, 854, 851, 1779, 2692, 2668, 2665, 2645, 2643, 2640, 2651, 2768, 2759, 2757, 2744, 2743, 2741, 2748, 352, 1382, 340, 337, 333, 1371, 1369, 307, 300, 296, 2126, 315, 312, 1347, 1342, 1350, 261, 258, 250, 2097, 246, 2094, 271, 268, 264, 1306, 1301, 1298, 276, 1312, 1309, 2115, 203, 2048, 195, 2045, 191, 2041, 213, 209, 2056, 1246, 1244, 1238, 225, 1234, 222, 1256, 1253, 1249, 1262, 2080, 2079, 154, 1997, 150, 1995, 147, 1992, 1989, 163, 160, 2004, 156, 2001, 1175, 1174, 1172, 1170, 1167, 170, 1164, 167, 1185, 1183, 1180, 1177, 174, 1190, 1188, 2025, 2024, 2022, 587, 586, 564, 559, 556, 2290, 573, 1588, 520, 518, 512, 2268, 508, 2265, 530, 1568, 1565, 461, 457, 2233, 450, 2230, 446, 2226, 479, 471, 489, 1526, 1523, 1520, 397, 395, 2185, 392, 2183, 389, 2180, 2177, 410, 2194, 402, 422, 1463, 1461, 1459, 1456, 1470, 2455, 799, 2433, 2430, 779, 776, 773, 2397, 2394, 2390, 734, 728, 724, 746, 1717, 2356, 2354, 2351, 2348, 1658, 677, 675, 673, 670, 667, 688, 1685, 1683, 2606, 2589, 2586, 2559, 2556, 2552, 927, 2523, 2521, 2518, 2515, 1784, 2532, 895, 893, 890, 2718, 2709, 2707, 2689, 2687, 2684, 2663, 2662, 2660, 2658, 1825, 2667, 2769, 1852, 2760, 2758, 142, 141, 1139, 1138, 134, 132, 129, 126, 1982, 1129, 1128, 1126, 1131, 113, 111, 108, 105, 1972, 101, 1970, 120, 118, 115, 1109, 1108, 1106, 1104, 123, 1113, 1111, 82, 79, 1951, 75, 1949, 72, 1946, 92, 89, 86, 1956, 1077, 1076, 1074, 1072, 98, 1069, 96, 1084, 1082, 1079, 1088, 1968, 1967, 48, 45, 1916, 42, 1914, 39, 1911, 1908, 60, 57, 54, 1923, 50, 1920, 1031, 1030, 1028, 1026, 67, 1023, 65, 1020, 62, 1041, 1039, 1036, 1033, 69, 1046, 1044, 1944, 1943, 1941, 11, 9, 1868, 7, 1865, 1862, 1859, 20, 1878, 16, 1875, 13, 1872, 970, 968, 966, 963, 29, 960, 26, 23, 983, 981, 978, 975, 33, 971, 31, 990, 988, 985, 1906, 1904, 1902, 993, 351, 2145, 1383, 331, 330, 328, 326, 2137, 323, 2135, 339, 1372, 1370, 294, 293, 291, 289, 2122, 286, 2120, 283, 2117, 309, 303, 317, 1348, 1346, 1344, 245, 244, 242, 2090, 239, 2088, 236, 2085, 2082, 260, 2099, 249, 270, 1307, 1305, 1303, 1300, 1314, 189, 2038, 186, 2036, 183, 2033, 2030, 2026, 206, 198, 2047, 194, 216, 1247, 1245, 1243, 1240, 227, 1237, 1255, 2310, 2302, 2300, 2286, 2284, 2281, 565, 563, 561, 558, 575, 1589, 2261, 2259, 2256, 2253, 1542, 521, 519, 517, 514, 2270, 511, 533, 1569, 1567, 2223, 2221, 2218, 2215, 1483, 2211, 1480, 459, 456, 453, 2232, 449, 474, 491, 1527, 1525, 1522, 2475, 2467, 2465, 2451, 2449, 2446, 801, 800, 2426, 2424, 2421, 2418, 1723, 2435, 780, 778, 775, 2387, 2385, 2382, 2379, 1695, 2375, 1693, 2396, 735, 733, 730, 727, 749, 1718, 2616, 2615, 2604, 2603, 2601, 2584, 2583, 2581, 2579, 1800, 2591, 2550, 2549, 2547, 2545, 1792, 2542, 1790, 2558, 929, 2719, 1841, 2710, 2708, 1833, 1831, 2690, 2688, 2686, 1815, 1809, 1808, 1774, 1756, 1754, 1737, 1736, 1734, 1739, 1816, 1711, 1676, 1674, 633, 629, 1638, 1636, 1633, 1641, 598, 1605, 1604, 1602, 1600, 605, 1609, 1607, 2327, 887, 853, 1775, 822, 820, 1757, 1755, 1584, 524, 1560, 1558, 468, 464, 1514, 1511, 1508, 1519, 408, 404, 400, 1452, 1447, 1444, 417, 1458, 1455, 2208, 364, 361, 358, 2154, 1401, 1400, 1398, 1396, 374, 1393, 371, 1408, 1406, 1403, 1413, 2173, 2172, 772, 726, 723, 1712, 672, 669, 666, 682, 1678, 1675, 625, 623, 621, 618, 2331, 636, 632, 1639, 1637, 1635, 920, 918, 884, 880, 889, 849, 848, 847, 846, 2497, 855, 852, 1776, 2641, 2742, 2787, 1380, 334, 1367, 1365, 301, 297, 1340, 1338, 1335, 1343, 255, 251, 247, 1296, 1291, 1288, 265, 1302, 1299, 2113, 204, 196, 192, 2042, 1232, 1230, 1224, 214, 1220, 210, 1242, 1239, 1235, 1250, 2077, 2075, 151, 148, 1993, 144, 1990, 1163, 1162, 1160, 1158, 1155, 161, 1152, 157, 1173, 1171, 1168, 1165, 168, 1181, 1178, 2021, 2020, 2018, 2023, 585, 560, 557, 1585, 516, 509, 1562, 1559, 458, 447, 2227, 472, 1516, 1513, 1510, 398, 396, 393, 390, 2181, 386, 2178, 407, 1453, 1451, 1449, 1446, 420, 1460, 2209, 769, 764, 720, 712, 2391, 729, 1713, 664, 663, 661, 659, 2352, 656, 2349, 671, 1679, 1677, 2553, 922, 919, 2519, 2516, 885, 883, 881, 2685, 2661, 2659, 2767, 2756, 2755, 140, 1137, 1136, 130, 127, 1125, 1124, 1122, 1127, 109, 106, 102, 1103, 1102, 1100, 1098, 116, 1107, 1105, 1980, 80, 76, 73, 1947, 1068, 1067, 1065, 1063, 90, 1060, 87, 1075, 1073, 1070, 1080, 1966, 1965, 46, 43, 40, 1912, 36, 1909, 1019, 1018, 1016, 1014, 58, 1011, 55, 1008, 51, 1029, 1027, 1024, 1021, 63, 1037, 1034, 1940, 1939, 1937, 1942, 8, 1866, 4, 1863, 1, 1860, 956, 954, 952, 949, 946, 17, 14, 969, 967, 964, 961, 27, 957, 24, 979, 976, 972, 1901, 1900, 1898, 1896, 986, 1905, 1903, 350, 349, 1381, 329, 327, 324, 1368, 1366, 292, 290, 287, 284, 2118, 304, 1341, 1339, 1337, 1345, 243, 240, 237, 2086, 233, 2083, 254, 1297, 1295, 1293, 1290, 1304, 2114, 190, 187, 184, 2034, 180, 2031, 177, 2027, 199, 1233, 1231, 1229, 1226, 217, 1223, 1241, 2078, 2076, 584, 555, 554, 552, 550, 2282, 562, 1586, 507, 506, 504, 502, 2257, 499, 2254, 515, 1563, 1561, 445, 443, 441, 2219, 438, 2216, 435, 2212, 460, 454, 475, 1517, 1515, 1512, 2447, 798, 797, 2422, 2419, 770, 768, 766, 2383, 2380, 2376, 721, 719, 717, 714, 731, 1714, 2602, 2582, 2580, 2548, 2546, 2543, 923, 921, 2717, 2706, 2705, 2683, 2682, 2680, 1771, 1752, 1750, 1733, 1732, 1731, 1735, 1814, 1707, 1670, 1668, 1631, 1629, 1626, 1634, 1599, 1598, 1596, 1594, 1603, 1601, 2326, 1772, 1753, 1751, 1581, 1554, 1552, 1504, 1501, 1498, 1509, 1442, 1437, 1434, 401, 1448, 1445, 2206, 1392, 1391, 1389, 1387, 1384, 359, 1399, 1397, 1394, 1404, 2171, 2170, 1708, 1672, 1669, 619, 1632, 1630, 1628, 1773, 1378, 1363, 1361, 1333, 1328, 1336, 1286, 1281, 1278, 248, 1292, 1289, 2111, 1218, 1216, 1210, 197, 1206, 193, 1228, 1225, 1221, 1236, 2073, 2071, 1151, 1150, 1148, 1146, 152, 1143, 149, 1140, 145, 1161, 1159, 1156, 1153, 158, 1169, 1166, 2017, 2016, 2014, 2019, 1582, 510, 1556, 1553, 452, 448, 1506, 1500, 394, 391, 387, 1443, 1441, 1439, 1436, 1450, 2207, 765, 716, 713, 1709, 662, 660, 657, 1673, 1671, 916, 914, 879, 878, 877, 882, 1135, 1134, 1121, 1120, 1118, 1123, 1097, 1096, 1094, 1092, 103, 1101, 1099, 1979, 1059, 1058, 1056, 1054, 77, 1051, 74, 1066, 1064, 1061, 1071, 1964, 1963, 1007, 1006, 1004, 1002, 999, 41, 996, 37, 1017, 1015, 1012, 1009, 52, 1025, 1022, 1936, 1935, 1933, 1938, 942, 940, 938, 935, 932, 5, 2, 955, 953, 950, 947, 18, 943, 15, 965, 962, 958, 1895, 1894, 1892, 1890, 973, 1899, 1897, 1379, 325, 1364, 1362, 288, 285, 1334, 1332, 1330, 241, 238, 234, 1287, 1285, 1283, 1280, 1294, 2112, 188, 185, 181, 178, 2028, 1219, 1217, 1215, 1212, 200, 1209, 1227, 2074, 2072, 583, 553, 551, 1583, 505, 503, 500, 513, 1557, 1555, 444, 442, 439, 436, 2213, 455, 451, 1507, 1505, 1502, 796, 763, 762, 760, 767, 711, 710, 708, 706, 2377, 718, 715, 1710, 2544, 917, 915, 2681, 1627, 1597, 1595, 2325, 1769, 1749, 1747, 1499, 1438, 1435, 2204, 1390, 1388, 1385, 1395, 2169, 2167, 1704, 1665, 1662, 1625, 1623, 1620, 1770, 1329, 1282, 1279, 2109, 1214, 1207, 1222, 2068, 2065, 1149, 1147, 1144, 1141, 146, 1157, 1154, 2013, 2011, 2008, 2015, 1579, 1549, 1546, 1495, 1487, 1433, 1431, 1428, 1425, 388, 1440, 2205, 1705, 658, 1667, 1664, 1119, 1095, 1093, 1978, 1057, 1055, 1052, 1062, 1962, 1960, 1005, 1003, 1000, 997, 38, 1013, 1010, 1932, 1930, 1927, 1934, 941, 939, 936, 933, 6, 930, 3, 951, 948, 944, 1889, 1887, 1884, 1881, 959, 1893, 1891, 35, 1377, 1360, 1358, 1327, 1325, 1322, 1331, 1277, 1275, 1272, 1269, 235, 1284, 2110, 1205, 1204, 1201, 1198, 182, 1195, 179, 1213, 2070, 2067, 1580, 501, 1551, 1548, 440, 437, 1497, 1494, 1490, 1503, 761, 709, 707, 1706, 913, 912, 2198, 1386, 2164, 2161, 1621, 1766, 2103, 1208, 2058, 2054, 1145, 1142, 2005, 2002, 1999, 2009, 1488, 1429, 1426, 2200, 1698, 1659, 1656, 1975, 1053, 1957, 1954, 1001, 998, 1924, 1921, 1918, 1928, 937, 934, 931, 1879, 1876, 1873, 1870, 945, 1885, 1882, 1323, 1273, 1270, 2105, 1202, 1199, 1196, 1211, 2061, 2057, 1576, 1543, 1540, 1484, 1481, 1478, 1491, 1700}; } + } \ No newline at end of file diff --git a/csharp/pdf417/decoder/DecodedBitStreamParser.cs b/csharp/pdf417/decoder/DecodedBitStreamParser.cs index f3bbaf6e2..a57084914 100755 --- a/csharp/pdf417/decoder/DecodedBitStreamParser.cs +++ b/csharp/pdf417/decoder/DecodedBitStreamParser.cs @@ -1,735 +1,649 @@ +using System.Text; + /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using DecoderResult = com.google.zxing.common.DecoderResult; + * 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. + */ + namespace com.google.zxing.pdf417.decoder { - - ///

This class contains the methods for decoding the PDF417 codewords.

+ + using FormatException = com.google.zxing.FormatException; + using DecoderResult = com.google.zxing.common.DecoderResult; + + + /// + ///

This class contains the methods for decoding the PDF417 codewords.

/// + /// @author SITA Lab (kevin.osullivan@sita.aero) ///
- /// SITA Lab (kevin.osullivan@sita.aero) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class DecodedBitStreamParser + internal sealed class DecodedBitStreamParser { - - private const int TEXT_COMPACTION_MODE_LATCH = 900; - private const int BYTE_COMPACTION_MODE_LATCH = 901; - private const int NUMERIC_COMPACTION_MODE_LATCH = 902; - private const int BYTE_COMPACTION_MODE_LATCH_6 = 924; - private const int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928; - private const int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923; - private const int MACRO_PDF417_TERMINATOR = 922; - private const int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913; - private const int MAX_NUMERIC_CODEWORDS = 15; - - private const int ALPHA = 0; - private const int LOWER = 1; - private const int MIXED = 2; - private const int PUNCT = 3; - private const int PUNCT_SHIFT = 4; - - private const int PL = 25; - private const int LL = 27; - private const int AS = 27; - private const int ML = 28; - private const int AL = 28; - private const int PS = 29; - private const int PAL = 29; - - //UPGRADE_NOTE: Final was removed from the declaration of 'PUNCT_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] PUNCT_CHARS = new char[]{';', '<', '>', '@', '[', (char) (92), '}', '_', (char) (96), '~', '!', (char) (13), (char) (9), ',', ':', (char) (10), '-', '.', '$', '/', (char) (34), '|', '*', '(', ')', '?', '{', '}', (char) (39)}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'MIXED_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] MIXED_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&', (char) (13), (char) (9), ',', ':', '#', '-', '.', '$', '/', '+', '%', '*', '=', '^'}; - - // Table containing values for the exponent of 900. - // This is used in the numeric compaction decode algorithm. - //UPGRADE_NOTE: Final was removed from the declaration of 'EXP900'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly System.String[] EXP900 = new System.String[]{"000000000000000000000000000000000000000000001", "000000000000000000000000000000000000000000900", "000000000000000000000000000000000000000810000", "000000000000000000000000000000000000729000000", "000000000000000000000000000000000656100000000", "000000000000000000000000000000590490000000000", "000000000000000000000000000531441000000000000", "000000000000000000000000478296900000000000000", "000000000000000000000430467210000000000000000", "000000000000000000387420489000000000000000000", "000000000000000348678440100000000000000000000", "000000000000313810596090000000000000000000000", "000000000282429536481000000000000000000000000", "000000254186582832900000000000000000000000000", "000228767924549610000000000000000000000000000", "205891132094649000000000000000000000000000000"}; - - private DecodedBitStreamParser() + + private enum Mode + { + ALPHA, + LOWER, + MIXED, + PUNCT, + ALPHA_SHIFT, + PUNCT_SHIFT + } + + private const int TEXT_COMPACTION_MODE_LATCH = 900; + private const int BYTE_COMPACTION_MODE_LATCH = 901; + private const int NUMERIC_COMPACTION_MODE_LATCH = 902; + private const int BYTE_COMPACTION_MODE_LATCH_6 = 924; + private const int BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928; + private const int BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923; + private const int MACRO_PDF417_TERMINATOR = 922; + private const int MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913; + private const int MAX_NUMERIC_CODEWORDS = 15; + + private const int PL = 25; + private const int LL = 27; + private const int AS = 27; + private const int ML = 28; + private const int AL = 28; + private const int PS = 29; + private const int PAL = 29; + + private static readonly char[] PUNCT_CHARS = {';', '<', '>', '@', '[', '\\', '}', '_', '`', '~', '!', '\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*', '(', ')', '?', '{', '}', '\''}; + + private static readonly char[] MIXED_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&', '\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*', '=', '^'}; + + /// + /// Table containing values for the exponent of 900. + /// This is used in the numeric compaction decode algorithm. + /// + private static readonly System.Numerics.BigInteger[] EXP900; + static DecodedBitStreamParser() + { + EXP900 = new System.Numerics.BigInteger[16]; + EXP900[0] = System.Numerics.BigInteger.One; + System.Numerics.BigInteger nineHundred = new System.Numerics.BigInteger(900); + EXP900[1] = nineHundred; + for (int i = 2; i < EXP900.Length; i++) { + EXP900[i] = EXP900[i - 1] * nineHundred; } - - internal static DecoderResult decode(int[] codewords) + } + + private DecodedBitStreamParser() + { + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static com.google.zxing.common.DecoderResult decode(int[] codewords) throws com.google.zxing.FormatException + internal static DecoderResult decode(int[] codewords) + { + StringBuilder result = new StringBuilder(100); + // Get compaction mode + int codeIndex = 1; + int code = codewords[codeIndex++]; + while (codeIndex < codewords[0]) { - System.Text.StringBuilder result = new System.Text.StringBuilder(100); - // Get compaction mode - int codeIndex = 1; + switch (code) + { + case TEXT_COMPACTION_MODE_LATCH: + codeIndex = textCompaction(codewords, codeIndex, result); + break; + case BYTE_COMPACTION_MODE_LATCH: + codeIndex = byteCompaction(code, codewords, codeIndex, result); + break; + case NUMERIC_COMPACTION_MODE_LATCH: + codeIndex = numericCompaction(codewords, codeIndex, result); + break; + case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: + codeIndex = byteCompaction(code, codewords, codeIndex, result); + break; + case BYTE_COMPACTION_MODE_LATCH_6: + codeIndex = byteCompaction(code, codewords, codeIndex, result); + break; + default: + // Default to text compaction. During testing numerous barcodes + // appeared to be missing the starting mode. In these cases defaulting + // to text compaction seems to work. + codeIndex--; + codeIndex = textCompaction(codewords, codeIndex, result); + break; + } + if (codeIndex < codewords.Length) + { + code = codewords[codeIndex++]; + } + else + { + throw FormatException.FormatInstance; + } + } + if (result.Length == 0) + { + throw FormatException.FormatInstance; + } + return new DecoderResult(null, result.ToString(), null, null); + } + + /// + /// Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be + /// encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as + /// well as selected control characters. + /// + /// The array of codewords (data + error) + /// The current index into the codeword array. + /// The decoded data is appended to the result. + /// The next index into the codeword array. + private static int textCompaction(int[] codewords, int codeIndex, StringBuilder result) + { + // 2 character per codeword + int[] textCompactionData = new int[codewords[0] << 1]; + // Used to hold the byte compaction value if there is a mode shift + int[] byteCompactionData = new int[codewords[0] << 1]; + + int index = 0; + bool end = false; + while ((codeIndex < codewords[0]) && !end) + { + int code = codewords[codeIndex++]; + if (code < TEXT_COMPACTION_MODE_LATCH) + { + textCompactionData[index] = code / 30; + textCompactionData[index + 1] = code % 30; + index += 2; + } + else + { + switch (code) + { + case TEXT_COMPACTION_MODE_LATCH: + // reinitialize text compaction mode to alpha sub mode + textCompactionData[index++] = TEXT_COMPACTION_MODE_LATCH; + break; + case BYTE_COMPACTION_MODE_LATCH: + codeIndex--; + end = true; + break; + case NUMERIC_COMPACTION_MODE_LATCH: + codeIndex--; + end = true; + break; + case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: + // The Mode Shift codeword 913 shall cause a temporary + // switch from Text Compaction mode to Byte Compaction mode. + // This switch shall be in effect for only the next codeword, + // after which the mode shall revert to the prevailing sub-mode + // of the Text Compaction mode. Codeword 913 is only available + // in Text Compaction mode; its use is described in 5.4.2.4. + textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE; + code = codewords[codeIndex++]; + byteCompactionData[index] = code; //Integer.toHexString(code); + index++; + break; + case BYTE_COMPACTION_MODE_LATCH_6: + codeIndex--; + end = true; + break; + } + } + } + decodeTextCompaction(textCompactionData, byteCompactionData, index, result); + return codeIndex; + } + + /// + /// The Text Compaction mode includes all the printable ASCII characters + /// (i.e. values from 32 to 126) and three ASCII control characters: HT or tab + /// (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage + /// return (ASCII value 13). The Text Compaction mode also includes various latch + /// and shift characters which are used exclusively within the mode. The Text + /// Compaction mode encodes up to 2 characters per codeword. The compaction rules + /// for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode + /// switches are defined in 5.4.2.3. + /// + /// The text compaction data. + /// The byte compaction data if there + /// was a mode shift. + /// The size of the text compaction and byte compaction data. + /// The decoded data is appended to the result. + private static void decodeTextCompaction(int[] textCompactionData, int[] byteCompactionData, int length, StringBuilder result) + { + // Beginning from an initial state of the Alpha sub-mode + // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text + // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text + // Compaction mode shall always switch to the Text Compaction Alpha sub-mode. + Mode subMode = Mode.ALPHA; + Mode priorToShiftMode = Mode.ALPHA; + int i = 0; + while (i < length) + { + int subModeCh = textCompactionData[i]; + char ch = '\0'; + switch (subMode) + { + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.ALPHA: + // Alpha (uppercase alphabetic) + if (subModeCh < 26) + { + // Upper case Alpha Character + ch = (char)('A' + subModeCh); + } + else + { + if (subModeCh == 26) + { + ch = ' '; + } + else if (subModeCh == LL) + { + subMode = Mode.LOWER; + } + else if (subModeCh == ML) + { + subMode = Mode.MIXED; + } + else if (subModeCh == PS) + { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = Mode.PUNCT_SHIFT; + } + else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) + { + result.Append((char) byteCompactionData[i]); + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.LOWER: + // Lower (lowercase alphabetic) + if (subModeCh < 26) + { + ch = (char)('a' + subModeCh); + } + else + { + if (subModeCh == 26) + { + ch = ' '; + } + else if (subModeCh == AS) + { + // Shift to alpha + priorToShiftMode = subMode; + subMode = Mode.ALPHA_SHIFT; + } + else if (subModeCh == ML) + { + subMode = Mode.MIXED; + } + else if (subModeCh == PS) + { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = Mode.PUNCT_SHIFT; + } + else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) + { + result.Append((char) byteCompactionData[i]); + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.MIXED: + // Mixed (numeric and some punctuation) + if (subModeCh < PL) + { + ch = MIXED_CHARS[subModeCh]; + } + else + { + if (subModeCh == PL) + { + subMode = Mode.PUNCT; + } + else if (subModeCh == 26) + { + ch = ' '; + } + else if (subModeCh == LL) + { + subMode = Mode.LOWER; + } + else if (subModeCh == AL) + { + subMode = Mode.ALPHA; + } + else if (subModeCh == PS) + { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = Mode.PUNCT_SHIFT; + } + else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) + { + result.Append((char) byteCompactionData[i]); + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.PUNCT: + // Punctuation + if (subModeCh < PAL) + { + ch = PUNCT_CHARS[subModeCh]; + } + else + { + if (subModeCh == PAL) + { + subMode = Mode.ALPHA; + } + else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) + { + result.Append((char) byteCompactionData[i]); + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.ALPHA_SHIFT: + // Restore sub-mode + subMode = priorToShiftMode; + if (subModeCh < 26) + { + ch = (char)('A' + subModeCh); + } + else + { + if (subModeCh == 26) + { + ch = ' '; + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + + case com.google.zxing.pdf417.decoder.DecodedBitStreamParser.Mode.PUNCT_SHIFT: + // Restore sub-mode + subMode = priorToShiftMode; + if (subModeCh < PAL) + { + ch = PUNCT_CHARS[subModeCh]; + } + else + { + if (subModeCh == PAL) + { + subMode = Mode.ALPHA; + } + else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) + { + // PS before Shift-to-Byte is used as a padding character, + // see 5.4.2.4 of the specification + result.Append((char) byteCompactionData[i]); + } + else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) + { + subMode = Mode.ALPHA; + } + } + break; + } + if (ch != 0) + { + // Append decoded character to result + result.Append(ch); + } + i++; + } + } + + /// + /// Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded. + /// This includes all ASCII characters value 0 to 127 inclusive and provides for international + /// character set support. + /// + /// The byte compaction mode i.e. 901 or 924 + /// The array of codewords (data + error) + /// The current index into the codeword array. + /// The decoded data is appended to the result. + /// The next index into the codeword array. + private static int byteCompaction(int mode, int[] codewords, int codeIndex, StringBuilder result) + { + if (mode == BYTE_COMPACTION_MODE_LATCH) + { + // Total number of Byte Compaction characters to be encoded + // is not a multiple of 6 + int count = 0; + long value = 0; + char[] decodedData = new char[6]; + int[] byteCompactedCodewords = new int[6]; + bool end = false; + int nextCode = codewords[codeIndex++]; + while ((codeIndex < codewords[0]) && !end) + { + byteCompactedCodewords[count++] = nextCode; + // Base 900 + value = 900 * value + nextCode; + nextCode = codewords[codeIndex++]; + // perhaps it should be ok to check only nextCode >= TEXT_COMPACTION_MODE_LATCH + if (nextCode == TEXT_COMPACTION_MODE_LATCH || nextCode == BYTE_COMPACTION_MODE_LATCH || nextCode == NUMERIC_COMPACTION_MODE_LATCH || nextCode == BYTE_COMPACTION_MODE_LATCH_6 || nextCode == BEGIN_MACRO_PDF417_CONTROL_BLOCK || nextCode == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || nextCode == MACRO_PDF417_TERMINATOR) + { + codeIndex--; + end = true; + } + else + { + if ((count % 5 == 0) && (count > 0)) + { + // Decode every 5 codewords + // Convert to Base 256 + for (int j = 0; j < 6; ++j) + { + decodedData[5 - j] = (char)(value % 256); + value >>= 8; + } + result.Append(decodedData); + count = 0; + } + } + } + + // if the end of all codewords is reached the last codeword needs to be added + if (codeIndex == codewords[0] && nextCode < TEXT_COMPACTION_MODE_LATCH) + { + byteCompactedCodewords[count++] = nextCode; + } + + // If Byte Compaction mode is invoked with codeword 901, + // the last group of codewords is interpreted directly + // as one byte per codeword, without compaction. + for (int i = 0; i < count; i++) + { + result.Append((char)byteCompactedCodewords[i]); + } + + } + else if (mode == BYTE_COMPACTION_MODE_LATCH_6) + { + // Total number of Byte Compaction characters to be encoded + // is an integer multiple of 6 + int count = 0; + long value = 0; + bool end = false; + while (codeIndex < codewords[0] && !end) + { int code = codewords[codeIndex++]; - while (codeIndex < codewords[0]) + if (code < TEXT_COMPACTION_MODE_LATCH) { - switch (code) - { - - case TEXT_COMPACTION_MODE_LATCH: { - codeIndex = textCompaction(codewords, codeIndex, result); - break; - } - - case BYTE_COMPACTION_MODE_LATCH: { - codeIndex = byteCompaction(code, codewords, codeIndex, result); - break; - } - - case NUMERIC_COMPACTION_MODE_LATCH: { - codeIndex = numericCompaction(codewords, codeIndex, result); - break; - } - - case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: { - codeIndex = byteCompaction(code, codewords, codeIndex, result); - break; - } - - case BYTE_COMPACTION_MODE_LATCH_6: { - codeIndex = byteCompaction(code, codewords, codeIndex, result); - break; - } - - default: { - // Default to text compaction. During testing numerous barcodes - // appeared to be missing the starting mode. In these cases defaulting - // to text compaction seems to work. - codeIndex--; - codeIndex = textCompaction(codewords, codeIndex, result); - break; - } - - } - if (codeIndex < codewords.Length) - { - code = codewords[codeIndex++]; - } - else - { - throw ReaderException.Instance; - } + count++; + // Base 900 + value = 900 * value + code; } - return new DecoderResult(null, result.ToString(), null, null); + else + { + if (code == TEXT_COMPACTION_MODE_LATCH || code == BYTE_COMPACTION_MODE_LATCH || code == NUMERIC_COMPACTION_MODE_LATCH || code == BYTE_COMPACTION_MODE_LATCH_6 || code == BEGIN_MACRO_PDF417_CONTROL_BLOCK || code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || code == MACRO_PDF417_TERMINATOR) + { + codeIndex--; + end = true; + } + } + if ((count % 5 == 0) && (count > 0)) + { + // Decode every 5 codewords + // Convert to Base 256 + char[] decodedData = new char[6]; + for (int j = 0; j < 6; ++j) + { + decodedData[5 - j] = (char)(value & 0xFF); + value >>= 8; + } + result.Append(decodedData); + count = 0; + } + } } - - /// Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be - /// encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as - /// well as selected control characters. - /// - /// - /// The array of codewords (data + error) - /// - /// The current index into the codeword array. - /// - /// The decoded data is appended to the result. - /// - /// The next index into the codeword array. - /// - private static int textCompaction(int[] codewords, int codeIndex, System.Text.StringBuilder result) + return codeIndex; + } + + /// + /// Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings. + /// + /// The array of codewords (data + error) + /// The current index into the codeword array. + /// The decoded data is appended to the result. + /// The next index into the codeword array. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int numericCompaction(int[] codewords, int codeIndex, StringBuilder result) throws com.google.zxing.FormatException + private static int numericCompaction(int[] codewords, int codeIndex, StringBuilder result) + { + int count = 0; + bool end = false; + + int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS]; + + while (codeIndex < codewords[0] && !end) { - // 2 character per codeword - int[] textCompactionData = new int[codewords[0] << 1]; - // Used to hold the byte compaction value if there is a mode shift - int[] byteCompactionData = new int[codewords[0] << 1]; - - int index = 0; - bool end = false; - while ((codeIndex < codewords[0]) && !end) + int code = codewords[codeIndex++]; + if (codeIndex == codewords[0]) + { + end = true; + } + if (code < TEXT_COMPACTION_MODE_LATCH) + { + numericCodewords[count] = code; + count++; + } + else + { + if (code == TEXT_COMPACTION_MODE_LATCH || code == BYTE_COMPACTION_MODE_LATCH || code == BYTE_COMPACTION_MODE_LATCH_6 || code == BEGIN_MACRO_PDF417_CONTROL_BLOCK || code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || code == MACRO_PDF417_TERMINATOR) { - int code = codewords[codeIndex++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - textCompactionData[index] = code / 30; - textCompactionData[index + 1] = code % 30; - index += 2; - } - else - { - switch (code) - { - - case TEXT_COMPACTION_MODE_LATCH: { - codeIndex--; - end = true; - break; - } - - case BYTE_COMPACTION_MODE_LATCH: { - codeIndex--; - end = true; - break; - } - - case NUMERIC_COMPACTION_MODE_LATCH: { - codeIndex--; - end = true; - break; - } - - case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: { - // The Mode Shift codeword 913 shall cause a temporary - // switch from Text Compaction mode to Byte Compaction mode. - // This switch shall be in effect for only the next codeword, - // after which the mode shall revert to the prevailing sub-mode - // of the Text Compaction mode. Codeword 913 is only available - // in Text Compaction mode; its use is described in 5.4.2.4. - textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE; - byteCompactionData[index] = code; //Integer.toHexString(code); - index++; - break; - } - - case BYTE_COMPACTION_MODE_LATCH_6: { - codeIndex--; - end = true; - break; - } - } - } + codeIndex--; + end = true; } - decodeTextCompaction(textCompactionData, byteCompactionData, index, result); - return codeIndex; + } + if (count % MAX_NUMERIC_CODEWORDS == 0 || code == NUMERIC_COMPACTION_MODE_LATCH || end) + { + // Re-invoking Numeric Compaction mode (by using codeword 902 + // while in Numeric Compaction mode) serves to terminate the + // current Numeric Compaction mode grouping as described in 5.4.4.2, + // and then to start a new one grouping. + string s = decodeBase900toBase10(numericCodewords, count); + result.Append(s); + count = 0; + } } - - /// The Text Compaction mode includes all the printable ASCII characters - /// (i.e. values from 32 to 126) and three ASCII control characters: HT or tab - /// (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage - /// return (ASCII value 13). The Text Compaction mode also includes various latch - /// and shift characters which are used exclusively within the mode. The Text - /// Compaction mode encodes up to 2 characters per codeword. The compaction rules - /// for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode - /// switches are defined in 5.4.2.3. - /// - /// - /// The text compaction data. - /// - /// The byte compaction data if there - /// was a mode shift. - /// - /// The size of the text compaction and byte compaction data. - /// - /// The decoded data is appended to the result. - /// - private static void decodeTextCompaction(int[] textCompactionData, int[] byteCompactionData, int length, System.Text.StringBuilder result) + return codeIndex; + } + + /// + /// Convert a list of Numeric Compacted codewords from Base 900 to Base 10. + /// + /// The array of codewords + /// The number of codewords + /// The decoded string representing the Numeric data. + /* + EXAMPLE + Encode the fifteen digit numeric string 000213298174000 + Prefix the numeric string with a 1 and set the initial value of + t = 1 000 213 298 174 000 + Calculate codeword 0 + d0 = 1 000 213 298 174 000 mod 900 = 200 + + t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082 + Calculate codeword 1 + d1 = 1 111 348 109 082 mod 900 = 282 + + t = 1 111 348 109 082 div 900 = 1 234 831 232 + Calculate codeword 2 + d2 = 1 234 831 232 mod 900 = 632 + + t = 1 234 831 232 div 900 = 1 372 034 + Calculate codeword 3 + d3 = 1 372 034 mod 900 = 434 + + t = 1 372 034 div 900 = 1 524 + Calculate codeword 4 + d4 = 1 524 mod 900 = 624 + + t = 1 524 div 900 = 1 + Calculate codeword 5 + d5 = 1 mod 900 = 1 + t = 1 div 900 = 0 + Codeword sequence is: 1, 624, 434, 632, 282, 200 + + Decode the above codewords involves + 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 + + 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000 + + Remove leading 1 => Result is 000213298174000 + */ +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static String decodeBase900toBase10(int[] codewords, int count) throws com.google.zxing.FormatException + private static string decodeBase900toBase10(int[] codewords, int count) + { + System.Numerics.BigInteger result = System.Numerics.BigInteger.Zero; + for (int i = 0; i < count; i++) { - // Beginning from an initial state of the Alpha sub-mode - // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text - // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text - // Compaction mode shall always switch to the Text Compaction Alpha sub-mode. - int subMode = ALPHA; - int priorToShiftMode = ALPHA; - int i = 0; - while (i < length) - { - int subModeCh = textCompactionData[i]; - char ch = (char) (0); - switch (subMode) - { - - case ALPHA: - // Alpha (uppercase alphabetic) - if (subModeCh < 26) - { - // Upper case Alpha Character - ch = (char) ('A' + subModeCh); - } - else - { - if (subModeCh == 26) - { - ch = ' '; - } - else if (subModeCh == LL) - { - subMode = LOWER; - } - else if (subModeCh == ML) - { - subMode = MIXED; - } - else if (subModeCh == PS) - { - // Shift to punctuation - priorToShiftMode = subMode; - subMode = PUNCT_SHIFT; - } - else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) - { - result.Append((char) byteCompactionData[i]); - } - } - break; - - - case LOWER: - // Lower (lowercase alphabetic) - if (subModeCh < 26) - { - ch = (char) ('a' + subModeCh); - } - else - { - if (subModeCh == 26) - { - ch = ' '; - } - else if (subModeCh == AL) - { - subMode = ALPHA; - } - else if (subModeCh == ML) - { - subMode = MIXED; - } - else if (subModeCh == PS) - { - // Shift to punctuation - priorToShiftMode = subMode; - subMode = PUNCT_SHIFT; - } - else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) - { - result.Append((char) byteCompactionData[i]); - } - } - break; - - - case MIXED: - // Mixed (numeric and some punctuation) - if (subModeCh < PL) - { - ch = MIXED_CHARS[subModeCh]; - } - else - { - if (subModeCh == PL) - { - subMode = PUNCT; - } - else if (subModeCh == 26) - { - ch = ' '; - } - else if (subModeCh == AS) - { - //mode_change = true; - } - else if (subModeCh == AL) - { - subMode = ALPHA; - } - else if (subModeCh == PS) - { - // Shift to punctuation - priorToShiftMode = subMode; - subMode = PUNCT_SHIFT; - } - else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) - { - result.Append((char) byteCompactionData[i]); - } - } - break; - - - case PUNCT: - // Punctuation - if (subModeCh < PS) - { - ch = PUNCT_CHARS[subModeCh]; - } - else - { - if (subModeCh == PAL) - { - subMode = ALPHA; - } - else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) - { - result.Append((char) byteCompactionData[i]); - } - } - break; - - - case PUNCT_SHIFT: - // Restore sub-mode - subMode = priorToShiftMode; - if (subModeCh < PS) - { - ch = PUNCT_CHARS[subModeCh]; - } - else - { - if (subModeCh == PAL) - { - subMode = ALPHA; - } - } - break; - } - if (ch != 0) - { - // Append decoded character to result - result.Append(ch); - } - i++; - } + result = result + (EXP900[count - i - 1] * new System.Numerics.BigInteger(codewords[i])); } - - /// Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded. - /// This includes all ASCII characters value 0 to 127 inclusive and provides for international - /// character set support. - /// - /// - /// The byte compaction mode i.e. 901 or 924 - /// - /// The array of codewords (data + error) - /// - /// The current index into the codeword array. - /// - /// The decoded data is appended to the result. - /// - /// The next index into the codeword array. - /// - private static int byteCompaction(int mode, int[] codewords, int codeIndex, System.Text.StringBuilder result) + string resultString = result.ToString(); + if (resultString[0] != '1') { - if (mode == BYTE_COMPACTION_MODE_LATCH) - { - // Total number of Byte Compaction characters to be encoded - // is not a multiple of 6 - int count = 0; - long value_Renamed = 0; - char[] decodedData = new char[6]; - int[] byteCompactedCodewords = new int[6]; - bool end = false; - while ((codeIndex < codewords[0]) && !end) - { - int code = codewords[codeIndex++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - byteCompactedCodewords[count] = code; - count++; - // Base 900 - value_Renamed *= 900; - value_Renamed += code; - } - else - { - if ((code == TEXT_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH) || (code == NUMERIC_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH_6) || (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) || (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) || (code == MACRO_PDF417_TERMINATOR)) - { - } - codeIndex--; - end = true; - } - if ((count % 5 == 0) && (count > 0)) - { - // Decode every 5 codewords - // Convert to Base 256 - for (int j = 0; j < 6; ++j) - { - decodedData[5 - j] = (char) (value_Renamed % 256); - value_Renamed >>= 8; - } - result.Append(decodedData); - count = 0; - } - } - // If Byte Compaction mode is invoked with codeword 901, - // the final group of codewords is interpreted directly - // as one byte per codeword, without compaction. - for (int i = ((count / 5) * 5); i < count; i++) - { - result.Append((char) byteCompactedCodewords[i]); - } - } - else if (mode == BYTE_COMPACTION_MODE_LATCH_6) - { - // Total number of Byte Compaction characters to be encoded - // is an integer multiple of 6 - int count = 0; - long value_Renamed = 0; - bool end = false; - while ((codeIndex < codewords[0]) && !end) - { - int code = codewords[codeIndex++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - count += 1; - // Base 900 - value_Renamed *= 900; - value_Renamed += code; - } - else - { - if ((code == TEXT_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH) || (code == NUMERIC_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH_6) || (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) || (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) || (code == MACRO_PDF417_TERMINATOR)) - { - } - codeIndex--; - end = true; - } - if ((count % 5 == 0) && (count > 0)) - { - // Decode every 5 codewords - // Convert to Base 256 - char[] decodedData = new char[6]; - for (int j = 0; j < 6; ++j) - { - decodedData[5 - j] = (char) (value_Renamed % 256); - value_Renamed >>= 8; - } - result.Append(decodedData); - } - } - } - return codeIndex; + throw FormatException.FormatInstance; } - - /// Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings. - /// - /// - /// The array of codewords (data + error) - /// - /// The current index into the codeword array. - /// - /// The decoded data is appended to the result. - /// - /// The next index into the codeword array. - /// - private static int numericCompaction(int[] codewords, int codeIndex, System.Text.StringBuilder result) - { - int count = 0; - bool end = false; - - int[] numericCodewords = new int[MAX_NUMERIC_CODEWORDS]; - - while ((codeIndex < codewords.Length) && !end) - { - int code = codewords[codeIndex++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - numericCodewords[count] = code; - count++; - } - else - { - if ((code == TEXT_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH) || (code == BYTE_COMPACTION_MODE_LATCH_6) || (code == BEGIN_MACRO_PDF417_CONTROL_BLOCK) || (code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) || (code == MACRO_PDF417_TERMINATOR)) - { - } - codeIndex--; - end = true; - } - if ((count % MAX_NUMERIC_CODEWORDS) == 0 || code == NUMERIC_COMPACTION_MODE_LATCH) - { - // Re-invoking Numeric Compaction mode (by using codeword 902 - // while in Numeric Compaction mode) serves to terminate the - // current Numeric Compaction mode grouping as described in 5.4.4.2, - // and then to start a new one grouping. - System.String s = decodeBase900toBase10(numericCodewords, count); - result.Append(s); - count = 0; - } - } - return codeIndex; - } - - /// Convert a list of Numeric Compacted codewords from Base 900 to Base 10. - /// - /// - /// The array of codewords - /// - /// The number of codewords - /// - /// The decoded string representing the Numeric data. - /// - /* - EXAMPLE - Encode the fifteen digit numeric string 000213298174000 - Prefix the numeric string with a 1 and set the initial value of - t = 1 000 213 298 174 000 - Calculate codeword 0 - d0 = 1 000 213 298 174 000 mod 900 = 200 - - t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082 - Calculate codeword 1 - d1 = 1 111 348 109 082 mod 900 = 282 - - t = 1 111 348 109 082 div 900 = 1 234 831 232 - Calculate codeword 2 - d2 = 1 234 831 232 mod 900 = 632 - - t = 1 234 831 232 div 900 = 1 372 034 - Calculate codeword 3 - d3 = 1 372 034 mod 900 = 434 - - t = 1 372 034 div 900 = 1 524 - Calculate codeword 4 - d4 = 1 524 mod 900 = 624 - - t = 1 524 div 900 = 1 - Calculate codeword 5 - d5 = 1 mod 900 = 1 - t = 1 div 900 = 0 - Codeword sequence is: 1, 624, 434, 632, 282, 200 - - Decode the above codewords involves - 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 + - 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000 - - Remove leading 1 => Result is 000213298174000 - - As there are huge numbers involved here we must use fake out the maths using string - tokens for the numbers. - BigDecimal is not supported by J2ME. - */ - private static System.String decodeBase900toBase10(int[] codewords, int count) - { - System.Text.StringBuilder accum = null; - for (int i = 0; i < count; i++) - { - System.Text.StringBuilder value_Renamed = multiply(EXP900[count - i - 1], codewords[i]); - if (accum == null) - { - // First time in accum=0 - accum = value_Renamed; - } - else - { - accum = add(accum.ToString(), value_Renamed.ToString()); - } - } - System.String result = null; - // Remove leading '1' which was inserted to preserve - // leading zeros - for (int i = 0; i < accum.Length; i++) - { - if (accum[i] == '1') - { - //result = accum.substring(i + 1); - result = accum.ToString().Substring(i + 1); - break; - } - } - if (result == null) - { - // No leading 1 => just write the converted number. - result = accum.ToString(); - } - return result; - } - - /// Multiplies two String numbers - /// - /// - /// Any number represented as a string. - /// - /// A number <= 999. - /// - /// the result of value1 * value2. - /// - private static System.Text.StringBuilder multiply(System.String value1, int value2) - { - System.Text.StringBuilder result = new System.Text.StringBuilder(value1.Length); - for (int i = 0; i < value1.Length; i++) - { - // Put zeros into the result. - result.Append('0'); - } - int hundreds = value2 / 100; - int tens = (value2 / 10) % 10; - int ones = value2 % 10; - // Multiply by ones - for (int j = 0; j < ones; j++) - { - result = add(result.ToString(), value1); - } - // Multiply by tens - for (int j = 0; j < tens; j++) - { - result = add(result.ToString(), (value1 + '0').Substring(1)); - } - // Multiply by hundreds - for (int j = 0; j < hundreds; j++) - { - result = add(result.ToString(), (value1 + "00").Substring(2)); - } - return result; - } - - /// Add two numbers which are represented as strings. - /// - /// - /// - /// - /// - /// - /// the result of value1 + value2 - /// - private static System.Text.StringBuilder add(System.String value1, System.String value2) - { - System.Text.StringBuilder temp1 = new System.Text.StringBuilder(5); - System.Text.StringBuilder temp2 = new System.Text.StringBuilder(5); - System.Text.StringBuilder result = new System.Text.StringBuilder(value1.Length); - for (int i = 0; i < value1.Length; i++) - { - // Put zeros into the result. - result.Append('0'); - } - int carry = 0; - for (int i = value1.Length - 3; i > - 1; i -= 3) - { - - temp1.Length = 0; - temp1.Append(value1[i]); - temp1.Append(value1[i + 1]); - temp1.Append(value1[i + 2]); - - temp2.Length = 0; - temp2.Append(value2[i]); - temp2.Append(value2[i + 1]); - temp2.Append(value2[i + 2]); - - int intValue1 = System.Int32.Parse(temp1.ToString()); - int intValue2 = System.Int32.Parse(temp2.ToString()); - - int sumval = (intValue1 + intValue2 + carry) % 1000; - carry = (intValue1 + intValue2 + carry) / 1000; - - result[i + 2] = (char) ((sumval % 10) + '0'); - result[i + 1] = (char) (((sumval / 10) % 10) + '0'); - result[i] = (char) ((sumval / 100) + '0'); - } - return result; - } - - /* - private static String decodeBase900toBase10(int codewords[], int count) { - BigInteger accum = BigInteger.valueOf(0); - BigInteger value = null; - for (int i = 0; i < count; i++) { - value = BigInteger.valueOf(900).pow(count - i - 1); - value = value.multiply(BigInteger.valueOf(codewords[i])); - accum = accum.add(value); - } - if (debug) System.out.println("Big Integer " + accum); - String result = accum.toString().substring(1); - return result; - } - */ + return resultString.Substring(1); + } + } + } \ No newline at end of file diff --git a/csharp/pdf417/decoder/Decoder.cs b/csharp/pdf417/decoder/Decoder.cs index d3fc47f01..759a15513 100755 --- a/csharp/pdf417/decoder/Decoder.cs +++ b/csharp/pdf417/decoder/Decoder.cs @@ -1,171 +1,158 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; + * 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. + */ + namespace com.google.zxing.pdf417.decoder { - //import com.google.zxing.pdf417.reedsolomon.ReedSolomonDecoder; - - ///

The main class which implements PDF417 Code decoding -- as + + using ChecksumException = com.google.zxing.ChecksumException; + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using ErrorCorrection = com.google.zxing.pdf417.decoder.ec.ErrorCorrection; + + ///

+ ///

The main class which implements PDF417 Code decoding -- as /// opposed to locating and extracting the PDF417 Code from an image.

/// + /// @author SITA Lab (kevin.osullivan@sita.aero) ///
- /// SITA Lab (kevin.osullivan@sita.aero) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Decoder { - - private const int MAX_ERRORS = 3; - private const int MAX_EC_CODEWORDS = 512; - //private final ReedSolomonDecoder rsDecoder; - - public Decoder() + + private const int MAX_ERRORS = 3; + private const int MAX_EC_CODEWORDS = 512; + private readonly ErrorCorrection errorCorrection; + + public Decoder() + { + errorCorrection = new ErrorCorrection(); + } + + /// + ///

Convenience method that can decode a PDF417 Code represented as a 2D array of booleans. + /// "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black PDF417 modules + /// text and bytes encoded within the PDF417 Code +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(boolean[][] image) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + public DecoderResult decode(bool[][] image) + { + int dimension = image.Length; + BitMatrix bits = new BitMatrix(dimension); + for (int i = 0; i < dimension; i++) { - // TODO MGMG - //rsDecoder = new ReedSolomonDecoder(); + for (int j = 0; j < dimension; j++) + { + if (image[j][i]) + { + bits.set(j, i); + } + } } - - ///

Convenience method that can decode a PDF417 Code represented as a 2D array of booleans. - /// "true" is taken to mean a black module.

- /// - ///
- /// booleans representing white/black PDF417 modules - /// - /// text and bytes encoded within the PDF417 Code - /// - /// ReaderException if the PDF417 Code cannot be decoded - public DecoderResult decode(bool[][] image) + return decode(bits); + } + + /// + ///

Decodes a PDF417 Code represented as a . + /// A 1 or "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black PDF417 Code modules + /// text and bytes encoded within the PDF417 Code + /// if the PDF417 Code cannot be decoded +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(com.google.zxing.common.BitMatrix bits) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + public DecoderResult decode(BitMatrix bits) + { + // Construct a parser to read the data codewords and error-correction level + BitMatrixParser parser = new BitMatrixParser(bits); + int[] codewords = parser.readCodewords(); + if (codewords.Length == 0) { - int dimension = image.Length; - BitMatrix bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - for (int j = 0; j < dimension; j++) - { - if (image[j][i]) - { - bits.set_Renamed(j, i); - } - } - } - return decode(bits); + throw FormatException.FormatInstance; } - - ///

Decodes a PDF417 Code represented as a {@link BitMatrix}. - /// A 1 or "true" is taken to mean a black module.

- /// - ///
- /// booleans representing white/black PDF417 Code modules - /// - /// text and bytes encoded within the PDF417 Code - /// - /// ReaderException if the PDF417 Code cannot be decoded - public DecoderResult decode(BitMatrix bits) + + int ecLevel = parser.ECLevel; + int numECCodewords = 1 << (ecLevel + 1); + int[] erasures = parser.Erasures; + + correctErrors(codewords, erasures, numECCodewords); + verifyCodewordCount(codewords, numECCodewords); + + // Decode the codewords + return DecodedBitStreamParser.decode(codewords); + } + + /// + /// Verify that all is OK with the codeword array. + /// + /// + /// an index to the first data codeword. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void verifyCodewordCount(int[] codewords, int numECCodewords) throws com.google.zxing.FormatException + private static void verifyCodewordCount(int[] codewords, int numECCodewords) + { + if (codewords.Length < 4) { - // Construct a parser to read the data codewords and error-correction level - BitMatrixParser parser = new BitMatrixParser(bits); - int[] codewords = parser.readCodewords(); - if (codewords == null || codewords.Length == 0) - { - throw ReaderException.Instance; - } - - int ecLevel = parser.ECLevel; - int numECCodewords = 1 << (ecLevel + 1); - int[] erasures = parser.Erasures; - - correctErrors(codewords, erasures, numECCodewords); - verifyCodewordCount(codewords, numECCodewords); - - // Decode the codewords - return DecodedBitStreamParser.decode(codewords); + // Codeword array size should be at least 4 allowing for + // Count CW, At least one Data CW, Error Correction CW, Error Correction CW + throw FormatException.FormatInstance; } - - /// Verify that all is OK with the codeword array. - /// - /// - /// - /// - /// an index to the first data codeword. - /// - /// ReaderException - private static void verifyCodewordCount(int[] codewords, int numECCodewords) + // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data + // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad + // codewords, but excluding the number of error correction codewords. + int numberOfCodewords = codewords[0]; + if (numberOfCodewords > codewords.Length) { - if (codewords.Length < 4) - { - // Codeword array size should be at least 4 allowing for - // Count CW, At least one Data CW, Error Correction CW, Error Correction CW - throw ReaderException.Instance; - } - // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data - // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad - // codewords, but excluding the number of error correction codewords. - int numberOfCodewords = codewords[0]; - if (numberOfCodewords > codewords.Length) - { - throw ReaderException.Instance; - } - if (numberOfCodewords == 0) - { - // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords) - if (numECCodewords < codewords.Length) - { - codewords[0] = codewords.Length - numECCodewords; - } - else - { - throw ReaderException.Instance; - } - } + throw FormatException.FormatInstance; } - - ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to - /// correct the errors in-place using Reed-Solomon error correction.

- /// - ///
- /// data and error correction codewords - /// - /// ReaderException if error correction fails - private static int correctErrors(int[] codewords, int[] erasures, int numECCodewords) + if (numberOfCodewords == 0) { - if ((erasures != null && erasures.Length > numECCodewords / 2 + MAX_ERRORS) || (numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) - { - // Too many errors or EC Codewords is corrupted - throw ReaderException.Instance; - } - // Try to correct the errors - int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords); - if (erasures != null) - { - int numErasures = erasures.Length; - if (result > 0) - { - numErasures -= result; - } - if (numErasures > MAX_ERRORS) - { - // Still too many errors - throw ReaderException.Instance; - } - } - return result; + // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords) + if (numECCodewords < codewords.Length) + { + codewords[0] = codewords.Length - numECCodewords; + } + else + { + throw FormatException.FormatInstance; + } } + } + + /// + ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to + /// correct the errors in-place.

+ ///
+ /// data and error correction codewords + /// positions of any known erasures + /// number of error correction codewards that were available in codewords + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private void correctErrors(int[] codewords, int[] erasures, int numECCodewords) throws com.google.zxing.ChecksumException + private void correctErrors(int[] codewords, int[] erasures, int numECCodewords) + { + if (erasures.Length > numECCodewords / 2 + MAX_ERRORS || numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS) + { + // Too many errors or EC Codewords is corrupted + throw ChecksumException.ChecksumInstance; + } + errorCorrection.decode(codewords, numECCodewords, erasures); + } + } + } \ No newline at end of file diff --git a/csharp/pdf417/detector/Detector.cs b/csharp/pdf417/detector/Detector.cs index b7b5c7026..76dd887e4 100755 --- a/csharp/pdf417/detector/Detector.cs +++ b/csharp/pdf417/detector/Detector.cs @@ -1,574 +1,577 @@ -/* -* 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. -*/ using System; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DetectorResult = com.google.zxing.common.DetectorResult; -using GridSampler = com.google.zxing.common.GridSampler; +using System.Collections.Generic; +using com.google.zxing.common; + +/* + * 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. + */ + namespace com.google.zxing.pdf417.detector { - - ///

Encapsulates logic that can detect a PDF417 Code in an image, even if the + + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DetectorResult = com.google.zxing.common.DetectorResult; + using GridSampler = com.google.zxing.common.GridSampler; + using MathUtils = com.google.zxing.common.detector.MathUtils; + + + ///

+ ///

Encapsulates logic that can detect a PDF417 Code in an image, even if the /// PDF417 Code is rotated or skewed, or partially obscured.

/// + /// @author SITA Lab (kevin.osullivan@sita.aero) + /// @author dswitkin@google.com (Daniel Switkin) ///
- /// SITA Lab (kevin.osullivan@sita.aero) - /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Detector { - - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static int MAX_AVG_VARIANCE = (int) SupportClass.Identity(((1 << 8) * 0.42f)); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - private static int MAX_INDIVIDUAL_VARIANCE = (int) SupportClass.Identity(((1 << 8) * 0.8f)); - private const int SKEW_THRESHOLD = 2; - - // B S B S B S B S Bar/Space pattern - // 11111111 0 1 0 1 0 1 000 - //UPGRADE_NOTE: Final was removed from the declaration of 'START_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] START_PATTERN = new int[]{8, 1, 1, 1, 1, 1, 1, 3}; - - // 11111111 0 1 0 1 0 1 000 - //UPGRADE_NOTE: Final was removed from the declaration of 'START_PATTERN_REVERSE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] START_PATTERN_REVERSE = new int[]{3, 1, 1, 1, 1, 1, 1, 8}; - - // 1111111 0 1 000 1 0 1 00 1 - //UPGRADE_NOTE: Final was removed from the declaration of 'STOP_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] STOP_PATTERN = new int[]{7, 1, 1, 3, 1, 1, 1, 2, 1}; - - // B S B S B S B S B Bar/Space pattern - // 1111111 0 1 000 1 0 1 00 1 - //UPGRADE_NOTE: Final was removed from the declaration of 'STOP_PATTERN_REVERSE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] STOP_PATTERN_REVERSE = new int[]{1, 2, 1, 1, 1, 3, 1, 1, 7}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BinaryBitmap image; - - public Detector(BinaryBitmap image) + + private const int INTEGER_MATH_SHIFT = 8; + private static readonly int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); + private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f); + private const int SKEW_THRESHOLD = 3; + + // B S B S B S B S Bar/Space pattern + // 11111111 0 1 0 1 0 1 000 + private static readonly int[] START_PATTERN = {8, 1, 1, 1, 1, 1, 1, 3}; + + // 11111111 0 1 0 1 0 1 000 + private static readonly int[] START_PATTERN_REVERSE = {3, 1, 1, 1, 1, 1, 1, 8}; + + // 1111111 0 1 000 1 0 1 00 1 + private static readonly int[] STOP_PATTERN = {7, 1, 1, 3, 1, 1, 1, 2, 1}; + + // B S B S B S B S B Bar/Space pattern + // 1111111 0 1 000 1 0 1 00 1 + private static readonly int[] STOP_PATTERN_REVERSE = {1, 2, 1, 1, 1, 3, 1, 1, 7}; + + private readonly BinaryBitmap image; + + public Detector(BinaryBitmap image) + { + this.image = image; + } + + /// + ///

Detects a PDF417 Code in an image, simply.

+ ///
+ /// encapsulating results of detecting a PDF417 Code + /// if no QR Code can be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect() throws com.google.zxing.NotFoundException + public DetectorResult detect() + { + return detect(null); + } + + /// + ///

Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.

+ ///
+ /// optional hints to detector + /// encapsulating results of detecting a PDF417 Code + /// if no PDF417 Code can be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect(java.util.Map hints) throws com.google.zxing.NotFoundException + public DetectorResult detect(IDictionary hints) + { + // Fetch the 1 bit matrix once up front. + BitMatrix matrix = image.BlackMatrix; + + bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); + + // Try to find the vertices assuming the image is upright. + ResultPoint[] vertices = findVertices(matrix, tryHarder); + if (vertices == null) { - this.image = image; + // Maybe the image is rotated 180 degrees? + vertices = findVertices180(matrix, tryHarder); + if (vertices != null) + { + correctCodeWordVertices(vertices, true); + } } - - ///

Detects a PDF417 Code in an image, simply.

- /// - ///
- /// {@link DetectorResult} encapsulating results of detecting a PDF417 Code - /// - /// ReaderException if no QR Code can be found - public DetectorResult detect() + else { - return detect(null); + correctCodeWordVertices(vertices, false); } - - ///

Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.

- /// - ///
- /// optional hints to detector - /// - /// {@link DetectorResult} encapsulating results of detecting a PDF417 Code - /// - /// ReaderException if no PDF417 Code can be found - public DetectorResult detect(System.Collections.Hashtable hints) + + if (vertices == null) { - // Fetch the 1 bit matrix once up front. - BitMatrix matrix = image.BlackMatrix; - - // Try to find the vertices assuming the image is upright. - ResultPoint[] vertices = findVertices(matrix); - if (vertices == null) + throw NotFoundException.NotFoundInstance; + } + + float moduleWidth = computeModuleWidth(vertices); + if (moduleWidth < 1.0f) + { + throw NotFoundException.NotFoundInstance; + } + + int dimension = computeDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth); + if (dimension < 1) + { + throw NotFoundException.NotFoundInstance; + } + + int ydimension = computeYDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth); + ydimension = ydimension > dimension ? ydimension : dimension; + + // Deskew and sample image. + BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5], vertices[6], vertices[7], dimension, ydimension); + return new DetectorResult(bits, new ResultPoint[]{vertices[5], vertices[4], vertices[6], vertices[7]}); + } + + /// + /// Locate the vertices and the codewords area of a black blob using the Start + /// and Stop patterns as locators. + /// + /// the scanned barcode image. + /// an array containing the vertices: + /// vertices[0] x, y top left barcode + /// vertices[1] x, y bottom left barcode + /// vertices[2] x, y top right barcode + /// vertices[3] x, y bottom right barcode + /// vertices[4] x, y top left codeword area + /// vertices[5] x, y bottom left codeword area + /// vertices[6] x, y top right codeword area + /// vertices[7] x, y bottom right codeword area + private static ResultPoint[] findVertices(BitMatrix matrix, bool tryHarder) + { + int height = matrix.Height; + int width = matrix.Width; + + ResultPoint[] result = new ResultPoint[8]; + bool found = false; + + int[] counters = new int[START_PATTERN.Length]; + + int rowStep = Math.Max(1, height >> (tryHarder ? 9 : 7)); + + // Top Left + for (int i = 0; i < height; i += rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters); + if (loc != null) + { + result[0] = new ResultPoint(loc[0], i); + result[4] = new ResultPoint(loc[1], i); + found = true; + break; + } + } + // Bottom left + if (found) // Found the Top Left vertex + { + found = false; + for (int i = height - 1; i > 0; i -= rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters); + if (loc != null) { - // Maybe the image is rotated 180 degrees? - vertices = findVertices180(matrix); - if (vertices != null) - { - correctCodeWordVertices(vertices, true); - } + result[1] = new ResultPoint(loc[0], i); + result[5] = new ResultPoint(loc[1], i); + found = true; + break; + } + } + } + + counters = new int[STOP_PATTERN.Length]; + + // Top right + if (found) // Found the Bottom Left vertex + { + found = false; + for (int i = 0; i < height; i += rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters); + if (loc != null) + { + result[2] = new ResultPoint(loc[1], i); + result[6] = new ResultPoint(loc[0], i); + found = true; + break; + } + } + } + // Bottom right + if (found) // Found the Top right vertex + { + found = false; + for (int i = height - 1; i > 0; i -= rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters); + if (loc != null) + { + result[3] = new ResultPoint(loc[1], i); + result[7] = new ResultPoint(loc[0], i); + found = true; + break; + } + } + } + return found ? result : null; + } + + /// + /// Locate the vertices and the codewords area of a black blob using the Start + /// and Stop patterns as locators. This assumes that the image is rotated 180 + /// degrees and if it locates the start and stop patterns at it will re-map + /// the vertices for a 0 degree rotation. + /// TODO: Change assumption about barcode location. + /// + /// the scanned barcode image. + /// an array containing the vertices: + /// vertices[0] x, y top left barcode + /// vertices[1] x, y bottom left barcode + /// vertices[2] x, y top right barcode + /// vertices[3] x, y bottom right barcode + /// vertices[4] x, y top left codeword area + /// vertices[5] x, y bottom left codeword area + /// vertices[6] x, y top right codeword area + /// vertices[7] x, y bottom right codeword area + private static ResultPoint[] findVertices180(BitMatrix matrix, bool tryHarder) + { + int height = matrix.Height; + int width = matrix.Width; + int halfWidth = width >> 1; + + ResultPoint[] result = new ResultPoint[8]; + bool found = false; + + int[] counters = new int[START_PATTERN_REVERSE.Length]; + + int rowStep = Math.Max(1, height >> (tryHarder ? 9 : 7)); + + // Top Left + for (int i = height - 1; i > 0; i -= rowStep) + { + int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters); + if (loc != null) + { + result[0] = new ResultPoint(loc[1], i); + result[4] = new ResultPoint(loc[0], i); + found = true; + break; + } + } + // Bottom Left + if (found) // Found the Top Left vertex + { + found = false; + for (int i = 0; i < height; i += rowStep) + { + int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters); + if (loc != null) + { + result[1] = new ResultPoint(loc[1], i); + result[5] = new ResultPoint(loc[0], i); + found = true; + break; + } + } + } + + counters = new int[STOP_PATTERN_REVERSE.Length]; + + // Top Right + if (found) // Found the Bottom Left vertex + { + found = false; + for (int i = height - 1; i > 0; i -= rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters); + if (loc != null) + { + result[2] = new ResultPoint(loc[0], i); + result[6] = new ResultPoint(loc[1], i); + found = true; + break; + } + } + } + // Bottom Right + if (found) // Found the Top Right vertex + { + found = false; + for (int i = 0; i < height; i += rowStep) + { + int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters); + if (loc != null) + { + result[3] = new ResultPoint(loc[0], i); + result[7] = new ResultPoint(loc[1], i); + found = true; + break; + } + } + } + return found ? result : null; + } + + /// + /// Because we scan horizontally to detect the start and stop patterns, the vertical component of + /// the codeword coordinates will be slightly wrong if there is any skew or rotation in the image. + /// This method moves those points back onto the edges of the theoretically perfect bounding + /// quadrilateral if needed. + /// + /// The eight vertices located by findVertices(). + private static void correctCodeWordVertices(ResultPoint[] vertices, bool upsideDown) + { + + float v0x = vertices[0].X; + float v0y = vertices[0].Y; + float v2x = vertices[2].X; + float v2y = vertices[2].Y; + float v4x = vertices[4].X; + float v4y = vertices[4].Y; + float v6x = vertices[6].X; + float v6y = vertices[6].Y; + + float skew = v4y - v6y; + if (upsideDown) + { + skew = -skew; + } + if (skew > SKEW_THRESHOLD) + { + // Fix v4 + float deltax = v6x - v0x; + float deltay = v6y - v0y; + float delta2 = deltax * deltax + deltay * deltay; + float correction = (v4x - v0x) * deltax / delta2; + vertices[4] = new ResultPoint(v0x + correction * deltax, v0y + correction * deltay); + } + else if (-skew > SKEW_THRESHOLD) + { + // Fix v6 + float deltax = v2x - v4x; + float deltay = v2y - v4y; + float delta2 = deltax * deltax + deltay * deltay; + float correction = (v2x - v6x) * deltax / delta2; + vertices[6] = new ResultPoint(v2x - correction * deltax, v2y - correction * deltay); + } + + float v1x = vertices[1].X; + float v1y = vertices[1].Y; + float v3x = vertices[3].X; + float v3y = vertices[3].Y; + float v5x = vertices[5].X; + float v5y = vertices[5].Y; + float v7x = vertices[7].X; + float v7y = vertices[7].Y; + + skew = v7y - v5y; + if (upsideDown) + { + skew = -skew; + } + if (skew > SKEW_THRESHOLD) + { + // Fix v5 + float deltax = v7x - v1x; + float deltay = v7y - v1y; + float delta2 = deltax * deltax + deltay * deltay; + float correction = (v5x - v1x) * deltax / delta2; + vertices[5] = new ResultPoint(v1x + correction * deltax, v1y + correction * deltay); + } + else if (-skew > SKEW_THRESHOLD) + { + // Fix v7 + float deltax = v3x - v5x; + float deltay = v3y - v5y; + float delta2 = deltax * deltax + deltay * deltay; + float correction = (v3x - v7x) * deltax / delta2; + vertices[7] = new ResultPoint(v3x - correction * deltax, v3y - correction * deltay); + } + } + + /// + ///

Estimates module size (pixels in a module) based on the Start and End + /// finder patterns.

+ ///
+ /// an array of vertices: + /// vertices[0] x, y top left barcode + /// vertices[1] x, y bottom left barcode + /// vertices[2] x, y top right barcode + /// vertices[3] x, y bottom right barcode + /// vertices[4] x, y top left codeword area + /// vertices[5] x, y bottom left codeword area + /// vertices[6] x, y top right codeword area + /// vertices[7] x, y bottom right codeword area + /// the module size. + private static float computeModuleWidth(ResultPoint[] vertices) + { + float pixels1 = ResultPoint.distance(vertices[0], vertices[4]); + float pixels2 = ResultPoint.distance(vertices[1], vertices[5]); + float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f); + float pixels3 = ResultPoint.distance(vertices[6], vertices[2]); + float pixels4 = ResultPoint.distance(vertices[7], vertices[3]); + float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f); + return (moduleWidth1 + moduleWidth2) / 2.0f; + } + + /// + /// Computes the dimension (number of modules in a row) of the PDF417 Code + /// based on vertices of the codeword area and estimated module size. + /// + /// of codeword area + /// of codeword area + /// of codeword area + /// of codeword are + /// estimated module size + /// the number of modules in a row. + private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth) + { + int topRowDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleWidth); + int bottomRowDimension = MathUtils.round(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth); + return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17; + } + + /// + /// Computes the y dimension (number of modules in a column) of the PDF417 Code + /// based on vertices of the codeword area and estimated module size. + /// + /// of codeword area + /// of codeword area + /// of codeword area + /// of codeword are + /// estimated module size + /// the number of modules in a row. + private static int computeYDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth) + { + int leftColumnDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleWidth); + int rightColumnDimension = MathUtils.round(ResultPoint.distance(topRight, bottomRight) / moduleWidth); + return (leftColumnDimension + rightColumnDimension) >> 1; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix sampleGrid(com.google.zxing.common.BitMatrix matrix, com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint bottomLeft, com.google.zxing.ResultPoint topRight, com.google.zxing.ResultPoint bottomRight, int xdimension, int ydimension) throws com.google.zxing.NotFoundException + private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int xdimension, int ydimension) + { + + // Note that unlike 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. + GridSampler sampler = GridSampler.Instance; + + return sampler.sampleGrid(matrix, xdimension, ydimension, 0.0f, 0.0f, xdimension, 0.0f, xdimension, ydimension, 0.0f, ydimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY - p4FromX - p3FromY - p3FromX - p2FromY - p2FromX - p1FromY - p1FromX - p4ToY - p4ToX - p3ToY - p3ToX - p2ToY - p2ToX - p1ToY - p1ToX + } + + /// row of black/white values to search + /// x position to start search + /// y position to start search + /// the number of pixels to search on this row + /// pattern of counts of number of black and white pixels that are + /// being searched for as a pattern + /// array of counters, as long as pattern, to re-use + /// start/end horizontal offset of guard pattern, as an array of two ints. + private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern, int[] counters) + { + //Arrays.fill(counters, 0, counters.Length, 0); + counters.Fill(0); + int patternLength = pattern.Length; + bool isWhite = whiteFirst; + + int counterPosition = 0; + int patternStart = column; + for (int x = column; x < column + width; x++) + { + bool pixel = matrix.get(x, row); + if (pixel ^ isWhite) + { + counters[counterPosition]++; + } + else + { + if (counterPosition == patternLength - 1) + { + if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) + { + return new int[]{patternStart, x}; + } + patternStart += counters[0] + counters[1]; + Array.Copy(counters, 2, counters, 0, patternLength - 2); + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; } else { - correctCodeWordVertices(vertices, false); - } - - if (vertices != null) - { - float moduleWidth = computeModuleWidth(vertices); - if (moduleWidth < 1.0f) - { - throw ReaderException.Instance; - } - - int dimension = computeDimension(vertices[4], vertices[6], vertices[5], vertices[7], moduleWidth); - if (dimension < 1) - { - throw ReaderException.Instance; - } - - // Deskew and sample image. - BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5], vertices[6], vertices[7], dimension); - return new DetectorResult(bits, new ResultPoint[]{vertices[4], vertices[5], vertices[6], vertices[7]}); - } - else - { - throw ReaderException.Instance; + counterPosition++; } + counters[counterPosition] = 1; + isWhite = !isWhite; + } } - - /// Locate the vertices and the codewords area of a black blob using the Start - /// and Stop patterns as locators. Assumes that the barcode begins in the left half - /// of the image, and ends in the right half. - /// TODO: Fix this assumption, allowing the barcode to be anywhere in the image. - /// TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER. - /// - /// - /// the scanned barcode image. - /// - /// an array containing the vertices: - /// vertices[0] x, y top left barcode - /// vertices[1] x, y bottom left barcode - /// vertices[2] x, y top right barcode - /// vertices[3] x, y bottom right barcode - /// vertices[4] x, y top left codeword area - /// vertices[5] x, y bottom left codeword area - /// vertices[6] x, y top right codeword area - /// vertices[7] x, y bottom right codeword area - /// - private static ResultPoint[] findVertices(BitMatrix matrix) + return null; + } + + /// + /// Determines how closely a set of observed counts of runs of black/white + /// values matches a given target pattern. This is reported as the ratio of + /// the total variance from the expected pattern proportions across all + /// pattern elements, to the length of the pattern. + /// + /// observed counters + /// expected pattern + /// The most any counter can differ before we give up + /// ratio of total variance between counters and pattern compared to + /// total pattern size, where the ratio has been multiplied by 256. + /// So, 0 means no variance (perfect match); 256 means the total + /// variance between counters and patterns equals the pattern length, + /// higher values mean even more variance + private static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) + { + int numCounters = counters.Length; + int total = 0; + int patternLength = 0; + for (int i = 0; i < numCounters; i++) { - int height = matrix.Height; - int width = matrix.Width; - int halfWidth = width >> 1; - - ResultPoint[] result = new ResultPoint[8]; - bool found = false; - - // Top Left - for (int i = 0; i < height; i++) - { - int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, START_PATTERN); - if (loc != null) - { - result[0] = new ResultPoint(loc[0], i); - result[4] = new ResultPoint(loc[1], i); - found = true; - break; - } - } - // Bottom left - if (found) - { - // Found the Top Left vertex - found = false; - for (int i = height - 1; i > 0; i--) - { - int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, START_PATTERN); - if (loc != null) - { - result[1] = new ResultPoint(loc[0], i); - result[5] = new ResultPoint(loc[1], i); - found = true; - break; - } - } - } - // Top right - if (found) - { - // Found the Bottom Left vertex - found = false; - for (int i = 0; i < height; i++) - { - int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, false, STOP_PATTERN); - if (loc != null) - { - result[2] = new ResultPoint(loc[1], i); - result[6] = new ResultPoint(loc[0], i); - found = true; - break; - } - } - } - // Bottom right - if (found) - { - // Found the Top right vertex - found = false; - for (int i = height - 1; i > 0; i--) - { - int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, false, STOP_PATTERN); - if (loc != null) - { - result[3] = new ResultPoint(loc[1], i); - result[7] = new ResultPoint(loc[0], i); - found = true; - break; - } - } - } - return found?result:null; + total += counters[i]; + patternLength += pattern[i]; } - - /// Locate the vertices and the codewords area of a black blob using the Start - /// and Stop patterns as locators. This assumes that the image is rotated 180 - /// degrees and if it locates the start and stop patterns at it will re-map - /// the vertices for a 0 degree rotation. - /// TODO: Change assumption about barcode location. - /// TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER. - /// - /// - /// the scanned barcode image. - /// - /// an array containing the vertices: - /// vertices[0] x, y top left barcode - /// vertices[1] x, y bottom left barcode - /// vertices[2] x, y top right barcode - /// vertices[3] x, y bottom right barcode - /// vertices[4] x, y top left codeword area - /// vertices[5] x, y bottom left codeword area - /// vertices[6] x, y top right codeword area - /// vertices[7] x, y bottom right codeword area - /// - private static ResultPoint[] findVertices180(BitMatrix matrix) + if (total < patternLength) { - int height = matrix.Height; - int width = matrix.Width; - int halfWidth = width >> 1; - - ResultPoint[] result = new ResultPoint[8]; - bool found = false; - - // Top Left - for (int i = height - 1; i > 0; i--) - { - int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE); - if (loc != null) - { - result[0] = new ResultPoint(loc[1], i); - result[4] = new ResultPoint(loc[0], i); - found = true; - break; - } - } - // Bottom Left - if (found) - { - // Found the Top Left vertex - found = false; - for (int i = 0; i < height; i++) - { - int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE); - if (loc != null) - { - result[1] = new ResultPoint(loc[1], i); - result[5] = new ResultPoint(loc[0], i); - found = true; - break; - } - } - } - // Top Right - if (found) - { - // Found the Bottom Left vertex - found = false; - for (int i = height - 1; i > 0; i--) - { - int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE); - if (loc != null) - { - result[2] = new ResultPoint(loc[0], i); - result[6] = new ResultPoint(loc[1], i); - found = true; - break; - } - } - } - // Bottom Right - if (found) - { - // Found the Top Right vertex - found = false; - for (int i = 0; i < height; i++) - { - int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE); - if (loc != null) - { - result[3] = new ResultPoint(loc[0], i); - result[7] = new ResultPoint(loc[1], i); - found = true; - break; - } - } - } - return found?result:null; + // If we don't even have one pixel per unit of bar width, assume this + // is too small to reliably match, so fail: + return int.MaxValue; } - - /// Because we scan horizontally to detect the start and stop patterns, the vertical component of - /// the codeword coordinates will be slightly wrong if there is any skew or rotation in the image. - /// This method moves those points back onto the edges of the theoretically perfect bounding - /// quadrilateral if needed. - /// - /// - /// The eight vertices located by findVertices(). - /// - private static void correctCodeWordVertices(ResultPoint[] vertices, bool upsideDown) + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits". + int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; + maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8; + + int totalVariance = 0; + for (int x = 0; x < numCounters; x++) { - float skew = vertices[4].Y - vertices[6].Y; - if (upsideDown) - { - skew = - skew; - } - if (skew > SKEW_THRESHOLD) - { - // Fix v4 - float length = vertices[4].X - vertices[0].X; - float deltax = vertices[6].X - vertices[0].X; - float deltay = vertices[6].Y - vertices[0].Y; - float correction = length * deltay / deltax; - vertices[4] = new ResultPoint(vertices[4].X, vertices[4].Y + correction); - } - else if (- skew > SKEW_THRESHOLD) - { - // Fix v6 - float length = vertices[2].X - vertices[6].X; - float deltax = vertices[2].X - vertices[4].X; - float deltay = vertices[2].Y - vertices[4].Y; - float correction = length * deltay / deltax; - vertices[6] = new ResultPoint(vertices[6].X, vertices[6].Y - correction); - } - - skew = vertices[7].Y - vertices[5].Y; - if (upsideDown) - { - skew = - skew; - } - if (skew > SKEW_THRESHOLD) - { - // Fix v5 - float length = vertices[5].X - vertices[1].X; - float deltax = vertices[7].X - vertices[1].X; - float deltay = vertices[7].Y - vertices[1].Y; - float correction = length * deltay / deltax; - vertices[5] = new ResultPoint(vertices[5].X, vertices[5].Y + correction); - } - else if (- skew > SKEW_THRESHOLD) - { - // Fix v7 - float length = vertices[3].X - vertices[7].X; - float deltax = vertices[3].X - vertices[5].X; - float deltay = vertices[3].Y - vertices[5].Y; - float correction = length * deltay / deltax; - vertices[7] = new ResultPoint(vertices[7].X, vertices[7].Y - correction); - } - } - - ///

Estimates module size (pixels in a module) based on the Start and End - /// finder patterns.

- /// - ///
- /// an array of vertices: - /// vertices[0] x, y top left barcode - /// vertices[1] x, y bottom left barcode - /// vertices[2] x, y top right barcode - /// vertices[3] x, y bottom right barcode - /// vertices[4] x, y top left codeword area - /// vertices[5] x, y bottom left codeword area - /// vertices[6] x, y top right codeword area - /// vertices[7] x, y bottom right codeword area - /// - /// the module size. - /// - private static float computeModuleWidth(ResultPoint[] vertices) - { - float pixels1 = ResultPoint.distance(vertices[0], vertices[4]); - float pixels2 = ResultPoint.distance(vertices[1], vertices[5]); - float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f); - float pixels3 = ResultPoint.distance(vertices[6], vertices[2]); - float pixels4 = ResultPoint.distance(vertices[7], vertices[3]); - float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f); - return (moduleWidth1 + moduleWidth2) / 2.0f; - } - - /// Computes the dimension (number of modules in a row) of the PDF417 Code - /// based on vertices of the codeword area and estimated module size. - /// - /// - /// of codeword area - /// - /// of codeword area - /// - /// of codeword area - /// - /// of codeword are - /// - /// estimated module size - /// - /// the number of modules in a row. - /// - private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth) - { - int topRowDimension = round(ResultPoint.distance(topLeft, topRight) / moduleWidth); - int bottomRowDimension = round(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth); - return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17; - /* - * int topRowDimension = round(ResultPoint.distance(topLeft, - * topRight)); //moduleWidth); int bottomRowDimension = - * round(ResultPoint.distance(bottomLeft, bottomRight)); // - * moduleWidth); int dimension = ((topRowDimension + bottomRowDimension) - * >> 1); // Round up to nearest 17 modules i.e. there are 17 modules per - * codeword //int dimension = ((((topRowDimension + bottomRowDimension) >> - * 1) + 8) / 17) * 17; return dimension; - */ - } - - private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int dimension) - { - - // Note that unlike 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. - GridSampler sampler = GridSampler.Instance; - - return sampler.sampleGrid(matrix, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY - } - - /// Ends up being a bit faster than Math.round(). This merely rounds its - /// argument to the nearest int, where x.5 rounds up. - /// - private static int round(float d) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (int) (d + 0.5f); - } - - /// row of black/white values to search - /// - /// x position to start search - /// - /// y position to start search - /// - /// the number of pixels to search on this row - /// - /// pattern of counts of number of black and white pixels that are - /// being searched for as a pattern - /// - /// start/end horizontal offset of guard pattern, as an array of two ints. - /// - private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern) - { - int patternLength = pattern.Length; - // TODO: Find a way to cache this array, as this method is called hundreds of times - // per image, and we want to allocate as seldom as possible. - int[] counters = new int[patternLength]; - bool isWhite = whiteFirst; - - int counterPosition = 0; - int patternStart = column; - for (int x = column; x < column + width; x++) - { - bool pixel = matrix.get_Renamed(x, row); - if (pixel ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) - { - return new int[]{patternStart, x}; - } - patternStart += counters[0] + counters[1]; - for (int y = 2; y < patternLength; y++) - { - counters[y - 2] = counters[y]; - } - counters[patternLength - 2] = 0; - counters[patternLength - 1] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - /// Determines how closely a set of observed counts of runs of black/white - /// values matches a given target pattern. This is reported as the ratio of - /// the total variance from the expected pattern proportions across all - /// pattern elements, to the length of the pattern. - /// - /// - /// observed counters - /// - /// expected pattern - /// - /// The most any counter can differ before we give up - /// - /// ratio of total variance between counters and pattern compared to - /// total pattern size, where the ratio has been multiplied by 256. - /// So, 0 means no variance (perfect match); 256 means the total - /// variance between counters and patterns equals the pattern length, - /// higher values mean even more variance - /// - private static int patternMatchVariance(int[] counters, int[] pattern, int maxIndividualVariance) - { - int numCounters = counters.Length; - int total = 0; - int patternLength = 0; - for (int i = 0; i < numCounters; i++) - { - total += counters[i]; - patternLength += pattern[i]; - } - if (total < patternLength) - { - // If we don't even have one pixel per unit of bar width, assume this - // is too small to reliably match, so fail: - return System.Int32.MaxValue; - } - // We're going to fake floating-point math in integers. We just need to use more bits. - // Scale up patternLength so that intermediate values below like scaledCounter will have - // more "significant digits". - int unitBarWidth = (total << 8) / patternLength; - maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8; - - int totalVariance = 0; - for (int x = 0; x < numCounters; x++) - { - int counter = counters[x] << 8; - int scaledPattern = pattern[x] * unitBarWidth; - int variance = counter > scaledPattern?counter - scaledPattern:scaledPattern - counter; - if (variance > maxIndividualVariance) - { - return System.Int32.MaxValue; - } - totalVariance += variance; - } - return totalVariance / total; + int counter = counters[x] << INTEGER_MATH_SHIFT; + int scaledPattern = pattern[x] * unitBarWidth; + int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) + { + return int.MaxValue; + } + totalVariance += variance; } + return totalVariance / total; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/QRCodeReader.cs b/csharp/qrcode/QRCodeReader.cs index d5d85904f..cbe191887 100755 --- a/csharp/qrcode/QRCodeReader.cs +++ b/csharp/qrcode/QRCodeReader.cs @@ -1,180 +1,213 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using DecodeHintType = com.google.zxing.DecodeHintType; -using Reader = com.google.zxing.Reader; -using ReaderException = com.google.zxing.ReaderException; -using Result = com.google.zxing.Result; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultMetadataType = com.google.zxing.ResultMetadataType; -using BinaryBitmap = com.google.zxing.BinaryBitmap; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; -using DetectorResult = com.google.zxing.common.DetectorResult; -using Decoder = com.google.zxing.qrcode.decoder.Decoder; -using Detector = com.google.zxing.qrcode.detector.Detector; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.qrcode { - - /// This implementation can detect and decode QR Codes in an image. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using BinaryBitmap = com.google.zxing.BinaryBitmap; + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using Reader = com.google.zxing.Reader; + using Result = com.google.zxing.Result; + using ResultMetadataType = com.google.zxing.ResultMetadataType; + using ResultPoint = com.google.zxing.ResultPoint; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using DetectorResult = com.google.zxing.common.DetectorResult; + using Decoder = com.google.zxing.qrcode.decoder.Decoder; + using Detector = com.google.zxing.qrcode.detector.Detector; + + + /// + /// This implementation can detect and decode QR Codes in an image. /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public class QRCodeReader : Reader + public class QRCodeReader : com.google.zxing.Reader { - virtual protected internal Decoder Decoder + + private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; + + private readonly Decoder decoder = new Decoder(); + + protected internal virtual Decoder Decoder + { + get + { + return decoder; + } + } + + /// + /// Locates and decodes a QR code in an image. + /// + /// a String representing the content encoded by the QR code + /// if a QR code cannot be found + /// if a QR code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image) + { + return decode(image, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.ChecksumException, com.google.zxing.FormatException + public Result decode(BinaryBitmap image, IDictionary hints) + { + DecoderResult decoderResult; + ResultPoint[] points; + if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) { - get - { - return decoder; - } - + BitMatrix bits = extractPureBits(image.BlackMatrix); + decoderResult = decoder.decode(bits, hints); + points = NO_POINTS; } - - //UPGRADE_NOTE: Final was removed from the declaration of 'NO_POINTS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - - //UPGRADE_NOTE: Final was removed from the declaration of 'decoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private Decoder decoder = new Decoder(); - - /// Locates and decodes a QR code in an image. - /// - /// - /// a String representing the content encoded by the QR code - /// - /// ReaderException if a QR code cannot be found, or cannot be decoded - public virtual Result decode(BinaryBitmap image) + else { - return decode(image, null); + DetectorResult detectorResult = (new Detector(image.BlackMatrix)).detect(hints); + decoderResult = decoder.decode(detectorResult.Bits, hints); + points = detectorResult.Points; } - - public virtual Result decode(BinaryBitmap image, System.Collections.Hashtable hints) + + Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); + IList byteSegments = decoderResult.ByteSegments; + if (byteSegments != null) { - DecoderResult decoderResult; - ResultPoint[] points; - if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) - { - BitMatrix bits = extractPureBits(image.BlackMatrix); - decoderResult = decoder.decode(bits); - points = NO_POINTS; - } - else - { - DetectorResult detectorResult = new Detector(image.BlackMatrix).detect(hints); - decoderResult = decoder.decode(detectorResult.Bits); - points = detectorResult.Points; - } - - Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); - if (decoderResult.ByteSegments != null) - { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.ByteSegments); - } - if (decoderResult.ECLevel != null) - { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel.ToString()); - } - return result; + result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); } - - /// This method detects a barcode in a "pure" image -- that is, pure monochrome image - /// which contains only an unrotated, unskewed, image of a barcode, with some white border - /// around it. This is a specialized method that works exceptionally fast in this special - /// case. - /// - private static BitMatrix extractPureBits(BitMatrix image) + string ecLevel = decoderResult.ECLevel; + if (ecLevel != null) { - // Now need to determine module size in pixels - - int height = image.Height; - int width = image.Width; - int minDimension = System.Math.Min(height, width); - - // First, skip white border by tracking diagonally from the top left down and to the right: - int borderWidth = 0; - while (borderWidth < minDimension && !image.get_Renamed(borderWidth, borderWidth)) - { - borderWidth++; - } - if (borderWidth == minDimension) - { - throw ReaderException.Instance; - } - - // And then keep tracking across the top-left black module to determine module size - int moduleEnd = borderWidth; - while (moduleEnd < minDimension && image.get_Renamed(moduleEnd, moduleEnd)) - { - moduleEnd++; - } - if (moduleEnd == minDimension) - { - throw ReaderException.Instance; - } - - int moduleSize = moduleEnd - borderWidth; - - // And now find where the rightmost black module on the first row ends - int rowEndOfSymbol = width - 1; - while (rowEndOfSymbol >= 0 && !image.get_Renamed(rowEndOfSymbol, borderWidth)) - { - rowEndOfSymbol--; - } - if (rowEndOfSymbol < 0) - { - throw ReaderException.Instance; - } - rowEndOfSymbol++; - - // Make sure width of barcode is a multiple of module size - if ((rowEndOfSymbol - borderWidth) % moduleSize != 0) - { - throw ReaderException.Instance; - } - int dimension = (rowEndOfSymbol - borderWidth) / moduleSize; - - // Push in the "border" by half the module width so that we start - // sampling in the middle of the module. Just in case the image is a - // little off, this will help recover. - borderWidth += (moduleSize >> 1); - - int sampleDimension = borderWidth + (dimension - 1) * moduleSize; - if (sampleDimension >= width || sampleDimension >= height) - { - throw ReaderException.Instance; - } - - // Now just read off the bits - BitMatrix bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - int iOffset = borderWidth + i * moduleSize; - for (int j = 0; j < dimension; j++) - { - if (image.get_Renamed(borderWidth + j * moduleSize, iOffset)) - { - bits.set_Renamed(j, i); - } - } - } - return bits; + result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); } + return result; + } + + public void reset() + { + // do nothing + } + + /// + /// This method detects a code in a "pure" image -- that is, pure monochrome image + /// which contains only an unrotated, unskewed, image of a code, with some white border + /// around it. This is a specialized method that works exceptionally fast in this special + /// case. + /// + /// + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix extractPureBits(com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static BitMatrix extractPureBits(BitMatrix image) + { + + int[] leftTopBlack = image.TopLeftOnBit; + int[] rightBottomBlack = image.BottomRightOnBit; + if (leftTopBlack == null || rightBottomBlack == null) + { + throw NotFoundException.NotFoundInstance; + } + + float moduleSize = getModuleSize(leftTopBlack, image); + + int top = leftTopBlack[1]; + int bottom = rightBottomBlack[1]; + int left = leftTopBlack[0]; + int right = rightBottomBlack[0]; + + if (bottom - top != right - left) + { + // Special case, where bottom-right module wasn't black so we found something else in the last row + // Assume it's a square, so use height as the width + right = left + (bottom - top); + } + + int matrixWidth = (int)Math.Round((right - left + 1) / moduleSize); + int matrixHeight = (int) Math.Round((bottom - top + 1) / moduleSize); + if (matrixWidth <= 0 || matrixHeight <= 0) + { + throw NotFoundException.NotFoundInstance; + } + if (matrixHeight != matrixWidth) + { + // Only possibly decode square regions + throw NotFoundException.NotFoundInstance; + } + + // 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. + int nudge = (int)(moduleSize / 2.0f); + top += nudge; + left += nudge; + + // Now just read off the bits + BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight); + for (int y = 0; y < matrixHeight; y++) + { + int iOffset = top + (int)(y * moduleSize); + for (int x = 0; x < matrixWidth; x++) + { + if (image.get(left + (int)(x * moduleSize), iOffset)) + { + bits.set(x, y); + } + } + } + return bits; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static float moduleSize(int[] leftTopBlack, com.google.zxing.common.BitMatrix image) throws com.google.zxing.NotFoundException + private static float getModuleSize(int[] leftTopBlack, BitMatrix image) + { + int height = image.Height; + int width = image.Width; + int x = leftTopBlack[0]; + int y = leftTopBlack[1]; + bool inBlack = true; + int transitions = 0; + while (x < width && y < height) + { + if (inBlack != image.get(x, y)) + { + if (++transitions == 5) + { + break; + } + inBlack = !inBlack; + } + x++; + y++; + } + if (x == width || y == height) + { + throw NotFoundException.NotFoundInstance; + } + return (x - leftTopBlack[0]) / 7.0f; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/QRCodeWriter.cs b/csharp/qrcode/QRCodeWriter.cs index 1fb194796..6cd2ca3c7 100755 --- a/csharp/qrcode/QRCodeWriter.cs +++ b/csharp/qrcode/QRCodeWriter.cs @@ -1,170 +1,147 @@ -/* -* 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. -*/ using System; -using BarcodeFormat = com.google.zxing.BarcodeFormat; -using EncodeHintType = com.google.zxing.EncodeHintType; -using Writer = com.google.zxing.Writer; -using WriterException = com.google.zxing.WriterException; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -using Encoder = com.google.zxing.qrcode.encoder.Encoder; -using QRCode = com.google.zxing.qrcode.encoder.QRCode; -using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.qrcode { - - /// This object renders a QR Code as a ByteMatrix 2D array of greyscale values. + + using BarcodeFormat = com.google.zxing.BarcodeFormat; + using EncodeHintType = com.google.zxing.EncodeHintType; + using Writer = com.google.zxing.Writer; + using WriterException = com.google.zxing.WriterException; + using BitMatrix = com.google.zxing.common.BitMatrix; + using ByteMatrix = com.google.zxing.qrcode.encoder.ByteMatrix; + using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + using Encoder = com.google.zxing.qrcode.encoder.Encoder; + using QRCode = com.google.zxing.qrcode.encoder.QRCode; + + + /// + /// This object renders a QR Code as a BitMatrix 2D array of greyscale values. /// + /// @author dswitkin@google.com (Daniel Switkin) /// - /// dswitkin@google.com (Daniel Switkin) - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class QRCodeWriter : Writer + public sealed class QRCodeWriter : com.google.zxing.Writer { - - private const int QUIET_ZONE_SIZE = 4; - - public ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height) + + private const int QUIET_ZONE_SIZE = 4; + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, com.google.zxing.BarcodeFormat format, int width, int height) throws com.google.zxing.WriterException + public BitMatrix encode(string contents, BarcodeFormat format, int width, int height) + { + + return encode(contents, format, width, height, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.BitMatrix encode(String contents, com.google.zxing.BarcodeFormat format, int width, int height, java.util.Map hints) throws com.google.zxing.WriterException + public BitMatrix encode(string contents, BarcodeFormat format, int width, int height, IDictionary hints) + { + + if (contents.Length == 0) { - - return encode(contents, format, width, height, null); + throw new System.ArgumentException("Found empty contents"); } - - public ByteMatrix encode(System.String contents, BarcodeFormat format, int width, int height, System.Collections.Hashtable hints) + + if (format != BarcodeFormat.QR_CODE) { - - if (contents == null || contents.Length == 0) - { - throw new System.ArgumentException("Found empty contents"); - } - - if (format != BarcodeFormat.QR_CODE) - { - throw new System.ArgumentException("Can only encode QR_CODE, but got " + format); - } - - if (width < 0 || height < 0) - { - throw new System.ArgumentException("Requested dimensions are too small: " + width + 'x' + height); - } - - ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; - if (hints != null) - { - ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints[EncodeHintType.ERROR_CORRECTION]; - if (requestedECLevel != null) - { - errorCorrectionLevel = requestedECLevel; - } - } - - QRCode code = new QRCode(); - Encoder.encode(contents, errorCorrectionLevel, hints, code); - return renderResult(code, width, height); + throw new System.ArgumentException("Can only encode QR_CODE, but got " + format); } - - // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses - // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). - private static ByteMatrix renderResult(QRCode code, int width, int height) + + if (width < 0 || height < 0) { - ByteMatrix input = code.Matrix; - int inputWidth = input.Width; - int inputHeight = input.Height; - int qrWidth = inputWidth + (QUIET_ZONE_SIZE << 1); - int qrHeight = inputHeight + (QUIET_ZONE_SIZE << 1); - int outputWidth = System.Math.Max(width, qrWidth); - int outputHeight = System.Math.Max(height, qrHeight); - - int multiple = System.Math.Min(outputWidth / qrWidth, outputHeight / qrHeight); - // Padding includes both the quiet zone and the extra white pixels to accommodate the requested - // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. - // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will - // handle all the padding from 100x100 (the actual QR) up to 200x160. - int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; - int topPadding = (outputHeight - (inputHeight * multiple)) / 2; - - ByteMatrix output = new ByteMatrix(outputWidth, outputHeight); - sbyte[][] outputArray = output.Array; - - // We could be tricky and use the first row in each set of multiple as the temporary storage, - // instead of allocating this separate array. - sbyte[] row = new sbyte[outputWidth]; - - // 1. Write the white lines at the top - for (int y = 0; y < topPadding; y++) - { - setRowColor(outputArray[y], (sbyte) SupportClass.Identity(255)); - } - - // 2. Expand the QR image to the multiple - sbyte[][] inputArray = input.Array; - for (int y = 0; y < inputHeight; y++) - { - // a. Write the white pixels at the left of each row - for (int x = 0; x < leftPadding; x++) - { - row[x] = (sbyte) SupportClass.Identity(255); - } - - // b. Write the contents of this row of the barcode - int offset = leftPadding; - for (int x = 0; x < inputWidth; x++) - { - // Redivivus.in Java to c# Porting update - Type cased sbyte - // 30/01/2010 - // sbyte value_Renamed = (inputArray[y][x] == 1)?0:(sbyte) SupportClass.Identity(255); - sbyte value_Renamed = (sbyte)((inputArray[y][x] == 1) ? 0 : SupportClass.Identity(255)); - for (int z = 0; z < multiple; z++) - { - row[offset + z] = value_Renamed; - } - offset += multiple; - } - - // c. Write the white pixels at the right of each row - offset = leftPadding + (inputWidth * multiple); - for (int x = offset; x < outputWidth; x++) - { - row[x] = (sbyte) SupportClass.Identity(255); - } - - // d. Write the completed row multiple times - offset = topPadding + (y * multiple); - for (int z = 0; z < multiple; z++) - { - Array.Copy(row, 0, outputArray[offset + z], 0, outputWidth); - } - } - - // 3. Write the white lines at the bottom - int offset2 = topPadding + (inputHeight * multiple); - for (int y = offset2; y < outputHeight; y++) - { - setRowColor(outputArray[y], (sbyte) SupportClass.Identity(255)); - } - - return output; + throw new System.ArgumentException("Requested dimensions are too small: " + width + 'x' + height); } - - private static void setRowColor(sbyte[] row, sbyte value_Renamed) + + ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L; + int quietZone = QUIET_ZONE_SIZE; + if (hints != null) { - for (int x = 0; x < row.Length; x++) - { - row[x] = value_Renamed; - } + //ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints[EncodeHintType.ERROR_CORRECTION]; + ErrorCorrectionLevel requestedECLevel = null; + if (hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) + { + requestedECLevel = (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION]; + } + if (requestedECLevel != null) + { + errorCorrectionLevel = requestedECLevel; + } + + //int? quietZoneInt = (int?) hints[EncodeHintType.MARGIN]; + int? quietZoneInt = null; + if (hints.ContainsKey(EncodeHintType.MARGIN)) + { + quietZoneInt = (int?) hints[EncodeHintType.MARGIN]; + } + + if (quietZoneInt != null) + { + quietZone = (int)quietZoneInt; + } } + + QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints); + return renderResult(code, width, height, quietZone); + } + + // Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses + // 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap). + private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) + { + ByteMatrix input = code.Matrix; + if (input == null) + { + throw new InvalidOperationException(); + } + int inputWidth = input.Width; + int inputHeight = input.Height; + int qrWidth = inputWidth + (quietZone << 1); + int qrHeight = inputHeight + (quietZone << 1); + int outputWidth = Math.Max(width, qrWidth); + int outputHeight = Math.Max(height, qrHeight); + + int multiple = Math.Min(outputWidth / qrWidth, outputHeight / qrHeight); + // Padding includes both the quiet zone and the extra white pixels to accommodate the requested + // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. + // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will + // handle all the padding from 100x100 (the actual QR) up to 200x160. + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + int topPadding = (outputHeight - (inputHeight * multiple)) / 2; + + BitMatrix output = new BitMatrix(outputWidth, outputHeight); + + for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) + { + // Write the contents of this row of the barcode + for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) + { + if (input.get(inputX, inputY) == 1) + { + output.setRegion(outputX, outputY, multiple, multiple); + } + } + } + + return output; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/decoder/BitMatrixParser.cs b/csharp/qrcode/decoder/BitMatrixParser.cs index 505b1f83b..55b4cf683 100755 --- a/csharp/qrcode/decoder/BitMatrixParser.cs +++ b/csharp/qrcode/decoder/BitMatrixParser.cs @@ -1,241 +1,239 @@ /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class BitMatrixParser + + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + /// + /// @author Sean Owen + /// + internal sealed class BitMatrixParser { - - //UPGRADE_NOTE: Final was removed from the declaration of 'bitMatrix '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix bitMatrix; - private Version parsedVersion; - private FormatInformation parsedFormatInfo; - - /// {@link BitMatrix} to parse - /// - /// ReaderException if dimension is not >= 21 and 1 mod 4 - internal BitMatrixParser(BitMatrix bitMatrix) + + private readonly BitMatrix bitMatrix; + private Version parsedVersion; + private FormatInformation parsedFormatInfo; + + /// to parse + /// if dimension is not >= 21 and 1 mod 4 +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: BitMatrixParser(com.google.zxing.common.BitMatrix bitMatrix) throws com.google.zxing.FormatException + internal BitMatrixParser(BitMatrix bitMatrix) + { + int dimension = bitMatrix.Height; + if (dimension < 21 || (dimension & 0x03) != 1) { - int dimension = bitMatrix.Dimension; - if (dimension < 21 || (dimension & 0x03) != 1) - { - throw ReaderException.Instance; - } - this.bitMatrix = bitMatrix; + throw FormatException.FormatInstance; } - - ///

Reads format information from one of its two locations within the QR Code.

- /// - ///
- /// {@link FormatInformation} encapsulating the QR Code's format info - /// - /// ReaderException if both format information locations cannot be parsed as - /// the valid encoding of format information - /// - internal FormatInformation readFormatInformation() + this.bitMatrix = bitMatrix; + } + + /// + ///

Reads format information from one of its two locations within the QR Code.

+ ///
+ /// encapsulating the QR Code's format info + /// if both format information locations cannot be parsed as + /// the valid encoding of format information +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: FormatInformation readFormatInformation() throws com.google.zxing.FormatException + internal FormatInformation readFormatInformation() + { + + if (parsedFormatInfo != null) { - - if (parsedFormatInfo != null) - { - return parsedFormatInfo; - } - - // Read top-left format info bits - int formatInfoBits = 0; - for (int i = 0; i < 6; i++) - { - formatInfoBits = copyBit(i, 8, formatInfoBits); - } - // .. and skip a bit in the timing pattern ... - formatInfoBits = copyBit(7, 8, formatInfoBits); - formatInfoBits = copyBit(8, 8, formatInfoBits); - formatInfoBits = copyBit(8, 7, formatInfoBits); - // .. and skip a bit in the timing pattern ... - for (int j = 5; j >= 0; j--) - { - formatInfoBits = copyBit(8, j, formatInfoBits); - } - - parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); - if (parsedFormatInfo != null) - { - return parsedFormatInfo; - } - - // Hmm, failed. Try the top-right/bottom-left pattern - int dimension = bitMatrix.Dimension; - formatInfoBits = 0; - int iMin = dimension - 8; - for (int i = dimension - 1; i >= iMin; i--) - { - formatInfoBits = copyBit(i, 8, formatInfoBits); - } - for (int j = dimension - 7; j < dimension; j++) - { - formatInfoBits = copyBit(8, j, formatInfoBits); - } - - parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); - if (parsedFormatInfo != null) - { - return parsedFormatInfo; - } - throw ReaderException.Instance; + return parsedFormatInfo; } - - ///

Reads version information from one of its two locations within the QR Code.

- /// - ///
- /// {@link Version} encapsulating the QR Code's version - /// - /// ReaderException if both version information locations cannot be parsed as - /// the valid encoding of version information - /// - internal Version readVersion() + + // Read top-left format info bits + int formatInfoBits1 = 0; + for (int i = 0; i < 6; i++) { - - if (parsedVersion != null) + formatInfoBits1 = copyBit(i, 8, formatInfoBits1); + } + // .. and skip a bit in the timing pattern ... + formatInfoBits1 = copyBit(7, 8, formatInfoBits1); + formatInfoBits1 = copyBit(8, 8, formatInfoBits1); + formatInfoBits1 = copyBit(8, 7, formatInfoBits1); + // .. and skip a bit in the timing pattern ... + for (int j = 5; j >= 0; j--) + { + formatInfoBits1 = copyBit(8, j, formatInfoBits1); + } + + // Read the top-right/bottom-left pattern too + int dimension = bitMatrix.Height; + int formatInfoBits2 = 0; + int jMin = dimension - 7; + for (int j = dimension - 1; j >= jMin; j--) + { + formatInfoBits2 = copyBit(8, j, formatInfoBits2); + } + for (int i = dimension - 8; i < dimension; i++) + { + formatInfoBits2 = copyBit(i, 8, formatInfoBits2); + } + + parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2); + if (parsedFormatInfo != null) + { + return parsedFormatInfo; + } + throw FormatException.FormatInstance; + } + + /// + ///

Reads version information from one of its two locations within the QR Code.

+ ///
+ /// encapsulating the QR Code's version + /// if both version information locations cannot be parsed as + /// the valid encoding of version information +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: Version readVersion() throws com.google.zxing.FormatException + internal Version readVersion() + { + + if (parsedVersion != null) + { + return parsedVersion; + } + + int dimension = bitMatrix.Height; + + int provisionalVersion = (dimension - 17) >> 2; + if (provisionalVersion <= 6) + { + return Version.getVersionForNumber(provisionalVersion); + } + + // Read top-right version info: 3 wide by 6 tall + int versionBits = 0; + int ijMin = dimension - 11; + for (int j = 5; j >= 0; j--) + { + for (int i = dimension - 9; i >= ijMin; i--) + { + versionBits = copyBit(i, j, versionBits); + } + } + + Version theParsedVersion = Version.decodeVersionInformation(versionBits); + if (theParsedVersion != null && theParsedVersion.DimensionForVersion == dimension) + { + parsedVersion = theParsedVersion; + return theParsedVersion; + } + + // Hmm, failed. Try bottom left: 6 wide by 3 tall + versionBits = 0; + for (int i = 5; i >= 0; i--) + { + for (int j = dimension - 9; j >= ijMin; j--) + { + versionBits = copyBit(i, j, versionBits); + } + } + + theParsedVersion = Version.decodeVersionInformation(versionBits); + if (theParsedVersion != null && theParsedVersion.DimensionForVersion == dimension) + { + parsedVersion = theParsedVersion; + return theParsedVersion; + } + throw FormatException.FormatInstance; + } + + private int copyBit(int i, int j, int versionBits) + { + return bitMatrix.get(i, j) ? (versionBits << 1) | 0x1 : versionBits << 1; + } + + /// + ///

Reads the bits in the representing the finder pattern in the + /// correct order in order to reconstitute the codewords bytes contained within the + /// QR Code.

+ ///
+ /// bytes encoded within the QR Code + /// if the exact number of bytes expected is not read +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: byte[] readCodewords() throws com.google.zxing.FormatException + internal sbyte[] readCodewords() + { + + FormatInformation formatInfo = readFormatInformation(); + Version version = readVersion(); + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + DataMask dataMask = DataMask.forReference((int) formatInfo.DataMask); + int dimension = bitMatrix.Height; + dataMask.unmaskBitMatrix(bitMatrix, dimension); + + BitMatrix functionPattern = version.buildFunctionPattern(); + + bool readingUp = true; + sbyte[] result = new sbyte[version.TotalCodewords]; + int resultOffset = 0; + int currentByte = 0; + int bitsRead = 0; + // Read columns in pairs, from right to left + for (int j = dimension - 1; j > 0; j -= 2) + { + if (j == 6) + { + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + j--; + } + // Read alternatingly from bottom to top then top to bottom + for (int count = 0; count < dimension; count++) + { + int i = readingUp ? dimension - 1 - count : count; + for (int col = 0; col < 2; col++) { - return parsedVersion; - } - - int dimension = bitMatrix.Dimension; - - int provisionalVersion = (dimension - 17) >> 2; - if (provisionalVersion <= 6) - { - return Version.getVersionForNumber(provisionalVersion); - } - - // Read top-right version info: 3 wide by 6 tall - int versionBits = 0; - int ijMin = dimension - 11; - for (int j = 5; j >= 0; j--) - { - for (int i = dimension - 9; i >= ijMin; i--) + // Ignore bits covered by the function pattern + if (!functionPattern.get(j - col, i)) + { + // Read a bit + bitsRead++; + currentByte <<= 1; + if (bitMatrix.get(j - col, i)) { - versionBits = copyBit(i, j, versionBits); + currentByte |= 1; } - } - - parsedVersion = Version.decodeVersionInformation(versionBits); - if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension) - { - return parsedVersion; - } - - // Hmm, failed. Try bottom left: 6 wide by 3 tall - versionBits = 0; - for (int i = 5; i >= 0; i--) - { - for (int j = dimension - 9; j >= ijMin; j--) + // If we've made a whole byte, save it off + if (bitsRead == 8) { - versionBits = copyBit(i, j, versionBits); + result[resultOffset++] = (sbyte) currentByte; + bitsRead = 0; + currentByte = 0; } + } } - - parsedVersion = Version.decodeVersionInformation(versionBits); - if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension) - { - return parsedVersion; - } - throw ReaderException.Instance; + } + readingUp ^= true; // readingUp = !readingUp; // switch directions } - - private int copyBit(int i, int j, int versionBits) + if (resultOffset != version.TotalCodewords) { - return bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1; - } - - ///

Reads the bits in the {@link BitMatrix} representing the finder pattern in the - /// correct order in order to reconstitute the codewords bytes contained within the - /// QR Code.

- /// - ///
- /// bytes encoded within the QR Code - /// - /// ReaderException if the exact number of bytes expected is not read - internal sbyte[] readCodewords() - { - - FormatInformation formatInfo = readFormatInformation(); - Version version = readVersion(); - - // Get the data mask for the format used in this QR Code. This will exclude - // some bits from reading as we wind through the bit matrix. - DataMask dataMask = DataMask.forReference((int) formatInfo.DataMask); - int dimension = bitMatrix.Dimension; - dataMask.unmaskBitMatrix(bitMatrix, dimension); - - BitMatrix functionPattern = version.buildFunctionPattern(); - - bool readingUp = true; - sbyte[] result = new sbyte[version.TotalCodewords]; - int resultOffset = 0; - int currentByte = 0; - int bitsRead = 0; - // Read columns in pairs, from right to left - for (int j = dimension - 1; j > 0; j -= 2) - { - if (j == 6) - { - // Skip whole column with vertical alignment pattern; - // saves time and makes the other code proceed more cleanly - j--; - } - // Read alternatingly from bottom to top then top to bottom - for (int count = 0; count < dimension; count++) - { - int i = readingUp?dimension - 1 - count:count; - for (int col = 0; col < 2; col++) - { - // Ignore bits covered by the function pattern - if (!functionPattern.get_Renamed(j - col, i)) - { - // Read a bit - bitsRead++; - currentByte <<= 1; - if (bitMatrix.get_Renamed(j - col, i)) - { - currentByte |= 1; - } - // If we've made a whole byte, save it off - if (bitsRead == 8) - { - result[resultOffset++] = (sbyte) currentByte; - bitsRead = 0; - currentByte = 0; - } - } - } - } - readingUp ^= true; // readingUp = !readingUp; // switch directions - } - if (resultOffset != version.TotalCodewords) - { - throw ReaderException.Instance; - } - return result; + throw FormatException.FormatInstance; } + return result; + } + } } \ No newline at end of file diff --git a/csharp/qrcode/decoder/DataBlock.cs b/csharp/qrcode/decoder/DataBlock.cs index 91925f26d..13cd60f86 100755 --- a/csharp/qrcode/decoder/DataBlock.cs +++ b/csharp/qrcode/decoder/DataBlock.cs @@ -1,151 +1,144 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - ///

Encapsulates a block of data within a QR Code. QR Codes may split their data into + + ///

+ ///

Encapsulates a block of data within a QR Code. QR 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.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class DataBlock + internal sealed class DataBlock { - internal int NumDataCodewords + + private readonly int numDataCodewords; + private readonly sbyte[] codewords; + + private DataBlock(int numDataCodewords, sbyte[] codewords) + { + this.numDataCodewords = numDataCodewords; + this.codewords = codewords; + } + + /// + ///

When QR Codes use multiple data blocks, they are actually interleaved. + /// 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.

+ ///
+ /// bytes as read directly from the QR Code + /// version of the QR Code + /// error-correction level of the QR Code + /// DataBlocks containing original bytes, "de-interleaved" from representation in the + /// QR Code + internal static DataBlock[] getDataBlocks(sbyte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel) + { + + if (rawCodewords.Length != version.TotalCodewords) { - get - { - return numDataCodewords; - } - + throw new System.ArgumentException(); } - internal sbyte[] Codewords + + // Figure out the number and size of data blocks used by this version and + // error correction level + Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); + + // First count the total number of data blocks + int totalBlocks = 0; + Version.ECB[] ecBlockArray = ecBlocks.ECBlocks2; + foreach (Version.ECB ecBlock in ecBlockArray) { - get - { - return codewords; - } - + totalBlocks += ecBlock.Count; } - - //UPGRADE_NOTE: Final was removed from the declaration of 'numDataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int numDataCodewords; - //UPGRADE_NOTE: Final was removed from the declaration of 'codewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte[] codewords; - - private DataBlock(int numDataCodewords, sbyte[] codewords) + + // Now establish DataBlocks of the appropriate size and number of data codewords + DataBlock[] result = new DataBlock[totalBlocks]; + int numResultBlocks = 0; + foreach (Version.ECB ecBlock in ecBlockArray) { - this.numDataCodewords = numDataCodewords; - this.codewords = codewords; + for (int i = 0; i < ecBlock.Count; i++) + { + int numDataCodewords = ecBlock.DataCodewords; + int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; + result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[numBlockCodewords]); + } } - - ///

When QR Codes use multiple data blocks, they are actually interleaved. - /// 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.

- /// - ///
- /// bytes as read directly from the QR Code - /// - /// version of the QR Code - /// - /// error-correction level of the QR Code - /// - /// {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the - /// QR Code - /// - internal static DataBlock[] getDataBlocks(sbyte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel) + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + int shorterBlocksTotalCodewords = result[0].codewords.Length; + int longerBlocksStartAt = result.Length - 1; + while (longerBlocksStartAt >= 0) { - - if (rawCodewords.Length != version.TotalCodewords) - { - throw new System.ArgumentException(); - } - - // Figure out the number and size of data blocks used by this version and - // error correction level - Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); - - // First count the total number of data blocks - int totalBlocks = 0; - Version.ECB[] ecBlockArray = ecBlocks.getECBlocks(); - for (int i = 0; i < ecBlockArray.Length; i++) - { - totalBlocks += ecBlockArray[i].Count; - } - - // Now establish DataBlocks of the appropriate size and number of data codewords - DataBlock[] result = new DataBlock[totalBlocks]; - int numResultBlocks = 0; - for (int j = 0; j < ecBlockArray.Length; j++) - { - Version.ECB ecBlock = ecBlockArray[j]; - for (int i = 0; i < ecBlock.Count; i++) - { - int numDataCodewords = ecBlock.DataCodewords; - int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; - result[numResultBlocks++] = new DataBlock(numDataCodewords, new sbyte[numBlockCodewords]); - } - } - - // All blocks have the same amount of data, except that the last n - // (where n may be 0) have 1 more byte. Figure out where these start. - int shorterBlocksTotalCodewords = result[0].codewords.Length; - int longerBlocksStartAt = result.Length - 1; - while (longerBlocksStartAt >= 0) - { - int numCodewords = result[longerBlocksStartAt].codewords.Length; - if (numCodewords == shorterBlocksTotalCodewords) - { - break; - } - longerBlocksStartAt--; - } - longerBlocksStartAt++; - - int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock; - // The last elements of result may be 1 element longer; - // first fill out as many elements as all of them have - int rawCodewordsOffset = 0; - for (int i = 0; i < shorterBlocksNumDataCodewords; i++) - { - for (int j = 0; j < numResultBlocks; j++) - { - result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; - } - } - // Fill out the last data block in the longer ones - for (int j = longerBlocksStartAt; j < numResultBlocks; j++) - { - result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; - } - // Now add in error correction blocks - int max = result[0].codewords.Length; - for (int i = shorterBlocksNumDataCodewords; i < max; i++) - { - for (int j = 0; j < numResultBlocks; j++) - { - int iOffset = j < longerBlocksStartAt?i:i + 1; - result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; - } - } - return result; + int numCodewords = result[longerBlocksStartAt].codewords.Length; + if (numCodewords == shorterBlocksTotalCodewords) + { + break; + } + longerBlocksStartAt--; } + longerBlocksStartAt++; + + int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock; + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) + { + for (int j = 0; j < numResultBlocks; j++) + { + result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for (int j = longerBlocksStartAt; j < numResultBlocks; j++) + { + result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; + } + // Now add in error correction blocks + int max = result[0].codewords.Length; + for (int i = shorterBlocksNumDataCodewords; i < max; i++) + { + for (int j = 0; j < numResultBlocks; j++) + { + int iOffset = j < longerBlocksStartAt ? i : i + 1; + result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; + } + } + return result; + } + + internal int NumDataCodewords + { + get + { + return numDataCodewords; + } + } + + internal sbyte[] Codewords + { + get + { + return codewords; + } + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/decoder/DataMask.cs b/csharp/qrcode/decoder/DataMask.cs index e2ecaa094..f96180999 100755 --- a/csharp/qrcode/decoder/DataMask.cs +++ b/csharp/qrcode/decoder/DataMask.cs @@ -1,24 +1,26 @@ /* -* 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. -*/ -using System; -using BitMatrix = com.google.zxing.common.BitMatrix; + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - ///

Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations + + using BitMatrix = com.google.zxing.common.BitMatrix; + + ///

+ ///

Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations /// of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, /// including areas used for finder patterns, timing patterns, etc. These areas should be unused /// after the point they are unmasked anyway.

@@ -26,132 +28,143 @@ namespace com.google.zxing.qrcode.decoder ///

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position /// and j is row position. In fact, as the text says, i is row position and j is column position.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - abstract class DataMask + internal abstract class DataMask { - - /// See ISO 18004:2006 6.8.1 - //UPGRADE_NOTE: Final was removed from the declaration of 'DATA_MASKS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly DataMask[] DATA_MASKS = new DataMask[]{new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111()}; - - private DataMask() + + /// + /// See ISO 18004:2006 6.8.1 + /// + private static readonly DataMask[] DATA_MASKS = {new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111()}; + + private DataMask() + { + } + + /// + ///

Implementations of this method reverse the data masking process applied to a QR Code and + /// make its bits ready to read.

+ ///
+ /// representation of QR Code bits + /// dimension of QR Code, represented by bits, being unmasked + internal void unmaskBitMatrix(BitMatrix bits, int dimension) + { + for (int i = 0; i < dimension; i++) { - } - - ///

Implementations of this method reverse the data masking process applied to a QR Code and - /// make its bits ready to read.

- /// - ///
- /// representation of QR Code bits - /// - /// dimension of QR Code, represented by bits, being unmasked - /// - internal void unmaskBitMatrix(BitMatrix bits, int dimension) - { - for (int i = 0; i < dimension; i++) + for (int j = 0; j < dimension; j++) + { + if (isMasked(i, j)) { - for (int j = 0; j < dimension; j++) - { - if (isMasked(i, j)) - { - bits.flip(j, i); - } - } + bits.flip(j, i); } + } } - - internal abstract bool isMasked(int i, int j); - - /// a value between 0 and 7 indicating one of the eight possible - /// data mask patterns a QR Code may use - /// - /// {@link DataMask} encapsulating the data mask pattern - /// - internal static DataMask forReference(int reference) + } + + internal abstract bool isMasked(int i, int j); + + /// a value between 0 and 7 indicating one of the eight possible + /// data mask patterns a QR Code may use + /// DataMask encapsulating the data mask pattern + static internal DataMask forReference(int reference) + { + if (reference < 0 || reference > 7) { - if (reference < 0 || reference > 7) - { - throw new System.ArgumentException(); - } - return DATA_MASKS[reference]; + throw new System.ArgumentException(); } - - /// 000: mask bits for which (x + y) mod 2 == 0 - private class DataMask000:DataMask + return DATA_MASKS[reference]; + } + + /// + /// 000: mask bits for which (x + y) mod 2 == 0 + /// + private sealed class DataMask000 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return ((i + j) & 0x01) == 0; - } + return ((i + j) & 0x01) == 0; } - - /// 001: mask bits for which x mod 2 == 0 - private class DataMask001:DataMask + } + + /// + /// 001: mask bits for which x mod 2 == 0 + /// + private sealed class DataMask001 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return (i & 0x01) == 0; - } + return (i & 0x01) == 0; } - - /// 010: mask bits for which y mod 3 == 0 - private class DataMask010:DataMask + } + + /// + /// 010: mask bits for which y mod 3 == 0 + /// + private sealed class DataMask010 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return j % 3 == 0; - } + return j % 3 == 0; } - - /// 011: mask bits for which (x + y) mod 3 == 0 - private class DataMask011:DataMask + } + + /// + /// 011: mask bits for which (x + y) mod 3 == 0 + /// + private sealed class DataMask011 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return (i + j) % 3 == 0; - } + return (i + j) % 3 == 0; } - - /// 100: mask bits for which (x/2 + y/3) mod 2 == 0 - private class DataMask100:DataMask + } + + /// + /// 100: mask bits for which (x/2 + y/3) mod 2 == 0 + /// + private sealed class DataMask100 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return (((SupportClass.URShift(i, 1)) + (j / 3)) & 0x01) == 0; - } + return ((((int)((uint)i >> 1)) + (j / 3)) & 0x01) == 0; } - - /// 101: mask bits for which xy mod 2 + xy mod 3 == 0 - private class DataMask101:DataMask + } + + /// + /// 101: mask bits for which xy mod 2 + xy mod 3 == 0 + /// + private sealed class DataMask101 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - int temp = i * j; - return (temp & 0x01) + (temp % 3) == 0; - } + int temp = i * j; + return (temp & 0x01) + (temp % 3) == 0; } - - /// 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 - private class DataMask110:DataMask + } + + /// + /// 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + /// + private sealed class DataMask110 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - int temp = i * j; - return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; - } + int temp = i * j; + return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; } - - /// 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 - private class DataMask111:DataMask + } + + /// + /// 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + /// + private sealed class DataMask111 : DataMask + { + internal override bool isMasked(int i, int j) { - internal override bool isMasked(int i, int j) - { - return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; - } + return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; } + } } + } \ No newline at end of file diff --git a/csharp/qrcode/decoder/DecodedBitStreamParser.cs b/csharp/qrcode/decoder/DecodedBitStreamParser.cs index ce3776cf8..1ddc35a87 100755 --- a/csharp/qrcode/decoder/DecodedBitStreamParser.cs +++ b/csharp/qrcode/decoder/DecodedBitStreamParser.cs @@ -1,437 +1,442 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using BitSource = com.google.zxing.common.BitSource; -using CharacterSetECI = com.google.zxing.common.CharacterSetECI; -using DecoderResult = com.google.zxing.common.DecoderResult; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - ///

QR Codes can encode text as bits in one of several modes, and can use multiple modes + + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using BitSource = com.google.zxing.common.BitSource; + using CharacterSetECI = com.google.zxing.common.CharacterSetECI; + using DecoderResult = com.google.zxing.common.DecoderResult; + using StringUtils = com.google.zxing.common.StringUtils; + using com.google.zxing.common; + + + ///

+ ///

QR Codes can encode text as bits in one of several modes, and can use multiple modes /// in one QR Code. This class decodes the bits back into text.

/// ///

See ISO 18004:2006, 6.4.3 - 6.4.7

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class DecodedBitStreamParser + internal sealed class DecodedBitStreamParser { - - /// See ISO 18004:2006, 6.4.4 Table 5 - //UPGRADE_NOTE: Final was removed from the declaration of 'ALPHANUMERIC_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly char[] ALPHANUMERIC_CHARS = new char[]{'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 const System.String SHIFT_JIS = "SJIS"; - private const System.String EUC_JP = "EUC_JP"; - private static bool ASSUME_SHIFT_JIS; - private const System.String UTF8 = "UTF-8"; - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Commented & Added - private const System.String ISO88591 = "ISO-8859-1"; - - private DecodedBitStreamParser() + + /// + /// See ISO 18004:2006, 6.4.4 Table 5 + /// + private static readonly char[] ALPHANUMERIC_CHARS = {'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 const int GB2312_SUBSET = 1; + + private DecodedBitStreamParser() + { + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static com.google.zxing.common.DecoderResult decode(byte[] bytes, Version version, ErrorCorrectionLevel ecLevel, java.util.Map hints) throws com.google.zxing.FormatException + internal static DecoderResult decode(sbyte[] bytes, Version version, ErrorCorrectionLevel ecLevel, IDictionary hints) + { + BitSource bits = new BitSource(bytes); + StringBuilder result = new StringBuilder(50); + IList byteSegments = new List(1); + try { - } - - internal static DecoderResult decode(sbyte[] bytes, Version version, ErrorCorrectionLevel ecLevel) - { - BitSource bits = new BitSource(bytes); - System.Text.StringBuilder result = new System.Text.StringBuilder(50); - CharacterSetECI currentCharacterSetECI = null; - bool fc1InEffect = false; - System.Collections.ArrayList byteSegments = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(1)); - Mode mode; - do + CharacterSetECI currentCharacterSetECI = null; + bool fc1InEffect = false; + Mode mode; + do + { + // While still another segment to read... + if (bits.available() < 4) { - // While still another segment to read... - if (bits.available() < 4) - { - // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here - mode = Mode.TERMINATOR; - } - else - { - try - { - mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits - } - catch (System.ArgumentException) - { - throw ReaderException.Instance; - } - } - if (!mode.Equals(Mode.TERMINATOR)) - { - if (mode.Equals(Mode.FNC1_FIRST_POSITION) || mode.Equals(Mode.FNC1_SECOND_POSITION)) - { - // We do little with FNC1 except alter the parsed result a bit according to the spec - fc1InEffect = true; - } - else if (mode.Equals(Mode.STRUCTURED_APPEND)) - { - // not really supported; all we do is ignore it - // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue - bits.readBits(16); - } - else if (mode.Equals(Mode.ECI)) - { - // Count doesn't apply to ECI - int value_Renamed = parseECIValue(bits); - currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value_Renamed); - if (currentCharacterSetECI == null) - { - throw ReaderException.Instance; - } - } - else - { - // How many characters will follow, encoded in this mode? - int count = bits.readBits(mode.getCharacterCountBits(version)); - if (mode.Equals(Mode.NUMERIC)) - { - decodeNumericSegment(bits, result, count); - } - else if (mode.Equals(Mode.ALPHANUMERIC)) - { - decodeAlphanumericSegment(bits, result, count, fc1InEffect); - } - else if (mode.Equals(Mode.BYTE)) - { - decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments); - } - else if (mode.Equals(Mode.KANJI)) - { - decodeKanjiSegment(bits, result, count); - } - else - { - throw ReaderException.Instance; - } - } - } - } - while (!mode.Equals(Mode.TERMINATOR)); - - return new DecoderResult(bytes, result.ToString(), (byteSegments.Count == 0)?null:byteSegments, ecLevel); - } - - private static void decodeKanjiSegment(BitSource bits, System.Text.StringBuilder result, int count) - { - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as Shift_JIS afterwards - sbyte[] buffer = new sbyte[2 * count]; - int offset = 0; - while (count > 0) - { - // Each 13 bits encodes a 2-byte character - int twoBytes = bits.readBits(13); - int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); - if (assembledTwoBytes < 0x01F00) - { - // In the 0x8140 to 0x9FFC range - assembledTwoBytes += 0x08140; - } - else - { - // In the 0xE040 to 0xEBBF range - assembledTwoBytes += 0x0C140; - } - buffer[offset] = (sbyte) (assembledTwoBytes >> 8); - buffer[offset + 1] = (sbyte) assembledTwoBytes; - offset += 2; - count--; - } - // Shift_JIS may not be supported in some environments: - try - { - //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'" - result.Append(System.Text.Encoding.GetEncoding(SHIFT_JIS).GetString(SupportClass.ToByteArray(buffer))); - } - catch (System.IO.IOException) - { - throw ReaderException.Instance; - } - } - - private static void decodeByteSegment(BitSource bits, System.Text.StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, System.Collections.ArrayList byteSegments) - { - sbyte[] readBytes = new sbyte[count]; - if (count << 3 > bits.available()) - { - throw ReaderException.Instance; - } - for (int i = 0; i < count; i++) - { - readBytes[i] = (sbyte) bits.readBits(8); - } - System.String encoding; - if (currentCharacterSetECI == null) - { - // The spec isn't clear on this mode; see - // section 6.4.5: t does not say which encoding to assuming - // upon decoding. I have seen ISO-8859-1 used as well as - // Shift_JIS -- without anything like an ECI designator to - // give a hint. - encoding = guessEncoding(readBytes); + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + mode = Mode.TERMINATOR; } else { - encoding = currentCharacterSetECI.EncodingName; + mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits } - try + if (mode != Mode.TERMINATOR) { - //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'" - result.Append(System.Text.Encoding.GetEncoding(encoding).GetString(SupportClass.ToByteArray(readBytes))); - } - catch (System.IO.IOException) - { - throw ReaderException.Instance; - } - byteSegments.Add(SupportClass.ToByteArray(readBytes)); - } - - private static void decodeAlphanumericSegment(BitSource bits, System.Text.StringBuilder result, int count, bool fc1InEffect) - { - // Read two characters at a time - int start = result.Length; - while (count > 1) - { - int nextTwoCharsBits = bits.readBits(11); - result.Append(ALPHANUMERIC_CHARS[nextTwoCharsBits / 45]); - result.Append(ALPHANUMERIC_CHARS[nextTwoCharsBits % 45]); - count -= 2; - } - if (count == 1) - { - // special case: one character left - result.Append(ALPHANUMERIC_CHARS[bits.readBits(6)]); - } - // See section 6.4.8.1, 6.4.8.2 - if (fc1InEffect) - { - // We need to massage the result a bit if in an FNC1 mode: - for (int i = start; i < result.Length; i++) + if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION) + { + // We do little with FNC1 except alter the parsed result a bit according to the spec + fc1InEffect = true; + } + else if (mode == Mode.STRUCTURED_APPEND) + { + if (bits.available() < 16) { - if (result[i] == '%') - { - if (i < result.Length - 1 && result[i + 1] == '%') - { - // %% is rendered as % - result.Remove(i + 1, 1); - } - else - { - // In alpha mode, % should be converted to FNC1 separator 0x1D - result[i] = (char) 0x1D; - } - } + throw FormatException.FormatInstance; } - } - } - - private static void decodeNumericSegment(BitSource bits, System.Text.StringBuilder result, int count) - { - // Read three digits at a time - while (count >= 3) - { - // Each 10 bits encodes three digits - int threeDigitsBits = bits.readBits(10); - if (threeDigitsBits >= 1000) + // not really supported; all we do is ignore it + // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue + bits.readBits(16); + } + else if (mode == Mode.ECI) + { + // Count doesn't apply to ECI + int value = parseECIValue(bits); + currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); + if (currentCharacterSetECI == null) { - throw ReaderException.Instance; + throw FormatException.FormatInstance; } - result.Append(ALPHANUMERIC_CHARS[threeDigitsBits / 100]); - result.Append(ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]); - result.Append(ALPHANUMERIC_CHARS[threeDigitsBits % 10]); - count -= 3; - } - if (count == 2) - { - // Two digits left over to read, encoded in 7 bits - int twoDigitsBits = bits.readBits(7); - if (twoDigitsBits >= 100) + } + else + { + // First handle Hanzi mode which does not start with character count + if (mode == Mode.HANZI) { - throw ReaderException.Instance; - } - result.Append(ALPHANUMERIC_CHARS[twoDigitsBits / 10]); - result.Append(ALPHANUMERIC_CHARS[twoDigitsBits % 10]); - } - else if (count == 1) - { - // One digit left over to read - int digitBits = bits.readBits(4); - if (digitBits >= 10) - { - throw ReaderException.Instance; - } - result.Append(ALPHANUMERIC_CHARS[digitBits]); - } - } - - private static System.String guessEncoding(sbyte[] bytes) - { - if (ASSUME_SHIFT_JIS) - { - return SHIFT_JIS; - } - // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 - if (bytes.Length > 3 && bytes[0] == (sbyte) SupportClass.Identity(0xEF) && bytes[1] == (sbyte) SupportClass.Identity(0xBB) && bytes[2] == (sbyte) SupportClass.Identity(0xBF)) - { - return UTF8; - } - // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, - // which should be by far the most common encodings. ISO-8859-1 - // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS - // uses this as a first byte of a two-byte character. If we see this - // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. - // If we see something else in that second byte, we'll make the risky guess - // that it's UTF-8. - int length = bytes.Length; - bool canBeISO88591 = true; - bool canBeShiftJIS = true; - int maybeDoubleByteCount = 0; - int maybeSingleByteKatakanaCount = 0; - bool sawLatin1Supplement = false; - bool lastWasPossibleDoubleByteStart = false; - for (int i = 0; i < length && (canBeISO88591 || canBeShiftJIS); i++) - { - int value_Renamed = bytes[i] & 0xFF; - if ((value_Renamed == 0xC2 || value_Renamed == 0xC3) && i < length - 1) - { - // This is really a poor hack. The slightly more exotic characters people might want to put in - // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings - // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF]. - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue <= 0xBF && ((value_Renamed == 0xC2 && nextValue >= 0xA0) || (value_Renamed == 0xC3 && nextValue >= 0x80))) - { - sawLatin1Supplement = true; - } - } - if (value_Renamed >= 0x7F && value_Renamed <= 0x9F) - { - canBeISO88591 = false; - } - if (value_Renamed >= 0xA1 && value_Renamed <= 0xDF) - { - // count the number of characters that might be a Shift_JIS single-byte Katakana character - if (!lastWasPossibleDoubleByteStart) - { - maybeSingleByteKatakanaCount++; - } - } - if (!lastWasPossibleDoubleByteStart && ((value_Renamed >= 0xF0 && value_Renamed <= 0xFF) || value_Renamed == 0x80 || value_Renamed == 0xA0)) - { - canBeShiftJIS = false; - } - if (((value_Renamed >= 0x81 && value_Renamed <= 0x9F) || (value_Renamed >= 0xE0 && value_Renamed <= 0xEF))) - { - // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid - // second byte. - if (lastWasPossibleDoubleByteStart) - { - // If we just checked this and the last byte for being a valid double-byte - // char, don't check starting on this byte. If this and the last byte - // formed a valid pair, then this shouldn't be checked to see if it starts - // a double byte pair of course. - lastWasPossibleDoubleByteStart = false; - } - else - { - // ... otherwise do check to see if this plus the next byte form a valid - // double byte pair encoding a character. - lastWasPossibleDoubleByteStart = true; - if (i >= bytes.Length - 1) - { - canBeShiftJIS = false; - } - else - { - int nextValue = bytes[i + 1] & 0xFF; - if (nextValue < 0x40 || nextValue > 0xFC) - { - canBeShiftJIS = false; - } - else - { - maybeDoubleByteCount++; - } - // There is some conflicting information out there about which bytes can follow which in - // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice. - } - } + //chinese mode contains a sub set indicator right after mode indicator + int subset = bits.readBits(4); + int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); + if (subset == GB2312_SUBSET) + { + decodeHanziSegment(bits, result, countHanzi); + } } else { - lastWasPossibleDoubleByteStart = false; + // "Normal" QR code modes: + // How many characters will follow, encoded in this mode? + int count = bits.readBits(mode.getCharacterCountBits(version)); + if (mode == Mode.NUMERIC) + { + decodeNumericSegment(bits, result, count); + } + else if (mode == Mode.ALPHANUMERIC) + { + decodeAlphanumericSegment(bits, result, count, fc1InEffect); + } + else if (mode == Mode.BYTE) + { + decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints); + } + else if (mode == Mode.KANJI) + { + decodeKanjiSegment(bits, result, count); + } + else + { + throw FormatException.FormatInstance; + } } + } } - // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is: - // - If we saw - // - at least three byte that starts a double-byte value (bytes that are rare in ISO-8859-1), or - // - over 5% of bytes that could be single-byte Katakana (also rare in ISO-8859-1), - // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS - if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) - { - return SHIFT_JIS; - } - // Otherwise, we default to ISO-8859-1 unless we know it can't be - if (!sawLatin1Supplement && canBeISO88591) - { - return ISO88591; - } - // Otherwise, we take a wild guess with UTF-8 - return UTF8; + } while (mode != Mode.TERMINATOR); } - - private static int parseECIValue(BitSource bits) + catch (System.ArgumentException iae) { - int firstByte = bits.readBits(8); - if ((firstByte & 0x80) == 0) - { - // just one byte - return firstByte & 0x7F; - } - else if ((firstByte & 0xC0) == 0x80) - { - // two bytes - int secondByte = bits.readBits(8); - return ((firstByte & 0x3F) << 8) | secondByte; - } - else if ((firstByte & 0xE0) == 0xC0) - { - // three bytes - int secondThirdBytes = bits.readBits(16); - return ((firstByte & 0x1F) << 16) | secondThirdBytes; - } - throw new System.ArgumentException("Bad ECI bits starting with byte " + firstByte); + // from readBits() calls + throw FormatException.FormatInstance; } - static DecodedBitStreamParser() + + return new DecoderResult(bytes, result.ToString(), byteSegments.Count == 0 ? null : byteSegments, ecLevel == null ? null : ecLevel.ToString()); + } + + /// + /// See specification GBT 18284-2000 + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeHanziSegment(com.google.zxing.common.BitSource bits, StringBuilder result, int count) throws com.google.zxing.FormatException + private static void decodeHanziSegment(BitSource bits, StringBuilder result, int count) + { + // Don't crash trying to read more bits than we have available. + if (count * 13 > bits.available()) { - { - // Redivivus.in Java to c# Porting update - // 30/01/2010 - // Commented & Added - //System.String platformDefault = System_Renamed.getProperty("file.encoding"); - //ASSUME_SHIFT_JIS = SHIFT_JIS.ToUpper().Equals(platformDefault.ToUpper()) || EUC_JP.ToUpper().Equals(platformDefault.ToUpper()); - ASSUME_SHIFT_JIS = false; - } + throw FormatException.FormatInstance; } + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as GB2312 afterwards + sbyte[] buffer = new sbyte[2 * count]; + int offset = 0; + while (count > 0) + { + // Each 13 bits encodes a 2-byte character + int twoBytes = bits.readBits(13); + int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); + if (assembledTwoBytes < 0x003BF) + { + // In the 0xA1A1 to 0xAAFE range + assembledTwoBytes += 0x0A1A1; + } + else + { + // In the 0xB0A1 to 0xFAFE range + assembledTwoBytes += 0x0A6A1; + } + buffer[offset] = (sbyte)((assembledTwoBytes >> 8) & 0xFF); + buffer[offset + 1] = (sbyte)(assembledTwoBytes & 0xFF); + offset += 2; + count--; + } + + try + { + + //result.Append(new string(buffer, StringUtils.GB2312)); + result.Append(GetEncodedStringFromBuffer(buffer, StringUtils.GB2312)); + } + catch (System.IO.IOException) + { + throw FormatException.FormatInstance; + } + } + + private static string GetEncodedStringFromBuffer(sbyte[] buffer, string encoding) + { + byte[] bytes = buffer.ToBytes(); + Encoding en = Encoding.GetEncoding(encoding); + return en.GetString(bytes); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeKanjiSegment(com.google.zxing.common.BitSource bits, StringBuilder result, int count) throws com.google.zxing.FormatException + private static void decodeKanjiSegment(BitSource bits, StringBuilder result, int count) + { + // Don't crash trying to read more bits than we have available. + if (count * 13 > bits.available()) + { + throw FormatException.FormatInstance; + } + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + sbyte[] buffer = new sbyte[2 * count]; + int offset = 0; + while (count > 0) + { + // Each 13 bits encodes a 2-byte character + int twoBytes = bits.readBits(13); + int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); + if (assembledTwoBytes < 0x01F00) + { + // In the 0x8140 to 0x9FFC range + assembledTwoBytes += 0x08140; + } + else + { + // In the 0xE040 to 0xEBBF range + assembledTwoBytes += 0x0C140; + } + buffer[offset] = (sbyte)(assembledTwoBytes >> 8); + buffer[offset + 1] = (sbyte) assembledTwoBytes; + offset += 2; + count--; + } + // Shift_JIS may not be supported in some environments: + try + { + //result.Append(new string(buffer, StringUtils.SHIFT_JIS)); + result.Append(GetEncodedStringFromBuffer(buffer, StringUtils.SHIFT_JIS)); + } + catch (System.IO.IOException) + { + throw FormatException.FormatInstance; + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeByteSegment(com.google.zxing.common.BitSource bits, StringBuilder result, int count, com.google.zxing.common.CharacterSetECI currentCharacterSetECI, java.util.Collection byteSegments, java.util.Map hints) throws com.google.zxing.FormatException + private static void decodeByteSegment(BitSource bits, StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, ICollection byteSegments, IDictionary hints) + { + // Don't crash trying to read more bits than we have available. + if (count << 3 > bits.available()) + { + throw FormatException.FormatInstance; + } + + sbyte[] readBytes = new sbyte[count]; + for (int i = 0; i < count; i++) + { + readBytes[i] = (sbyte) bits.readBits(8); + } + string encoding; + if (currentCharacterSetECI == null) + { + // The spec isn't clear on this mode; see + // section 6.4.5: t does not say which encoding to assuming + // upon decoding. I have seen ISO-8859-1 used as well as + // Shift_JIS -- without anything like an ECI designator to + // give a hint. + encoding = StringUtils.guessEncoding(readBytes, hints); + } + else + { + encoding = currentCharacterSetECI.name(); + } + try + { + //result.Append(new string(readBytes, encoding)); + result.Append(GetEncodedStringFromBuffer(readBytes, encoding)); + } + catch (System.IO.IOException) + { + throw FormatException.FormatInstance; + } + byteSegments.Add(readBytes); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static char toAlphaNumericChar(int value) throws com.google.zxing.FormatException + private static char toAlphaNumericChar(int value) + { + if (value >= ALPHANUMERIC_CHARS.Length) + { + throw FormatException.FormatInstance; + } + return ALPHANUMERIC_CHARS[value]; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeAlphanumericSegment(com.google.zxing.common.BitSource bits, StringBuilder result, int count, boolean fc1InEffect) throws com.google.zxing.FormatException + private static void decodeAlphanumericSegment(BitSource bits, StringBuilder result, int count, bool fc1InEffect) + { + // Read two characters at a time + int start = result.Length; + while (count > 1) + { + if (bits.available() < 11) + { + throw FormatException.FormatInstance; + } + int nextTwoCharsBits = bits.readBits(11); + result.Append(toAlphaNumericChar(nextTwoCharsBits / 45)); + result.Append(toAlphaNumericChar(nextTwoCharsBits % 45)); + count -= 2; + } + if (count == 1) + { + // special case: one character left + if (bits.available() < 6) + { + throw FormatException.FormatInstance; + } + result.Append(toAlphaNumericChar(bits.readBits(6))); + } + // See section 6.4.8.1, 6.4.8.2 + if (fc1InEffect) + { + // We need to massage the result a bit if in an FNC1 mode: + for (int i = start; i < result.Length; i++) + { + if (result[i] == '%') + { + if (i < result.Length - 1 && result[i + 1] == '%') + { + // %% is rendered as % + result.Remove(i + 1, 1); + } + else + { + // In alpha mode, % should be converted to FNC1 separator 0x1D + result[i] = (char) 0x1D; + } + } + } + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void decodeNumericSegment(com.google.zxing.common.BitSource bits, StringBuilder result, int count) throws com.google.zxing.FormatException + private static void decodeNumericSegment(BitSource bits, StringBuilder result, int count) + { + // Read three digits at a time + while (count >= 3) + { + // Each 10 bits encodes three digits + if (bits.available() < 10) + { + throw FormatException.FormatInstance; + } + int threeDigitsBits = bits.readBits(10); + if (threeDigitsBits >= 1000) + { + throw FormatException.FormatInstance; + } + result.Append(toAlphaNumericChar(threeDigitsBits / 100)); + result.Append(toAlphaNumericChar((threeDigitsBits / 10) % 10)); + result.Append(toAlphaNumericChar(threeDigitsBits % 10)); + count -= 3; + } + if (count == 2) + { + // Two digits left over to read, encoded in 7 bits + if (bits.available() < 7) + { + throw FormatException.FormatInstance; + } + int twoDigitsBits = bits.readBits(7); + if (twoDigitsBits >= 100) + { + throw FormatException.FormatInstance; + } + result.Append(toAlphaNumericChar(twoDigitsBits / 10)); + result.Append(toAlphaNumericChar(twoDigitsBits % 10)); + } + else if (count == 1) + { + // One digit left over to read + if (bits.available() < 4) + { + throw FormatException.FormatInstance; + } + int digitBits = bits.readBits(4); + if (digitBits >= 10) + { + throw FormatException.FormatInstance; + } + result.Append(toAlphaNumericChar(digitBits)); + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int parseECIValue(com.google.zxing.common.BitSource bits) throws com.google.zxing.FormatException + private static int parseECIValue(BitSource bits) + { + int firstByte = bits.readBits(8); + if ((firstByte & 0x80) == 0) + { + // just one byte + return firstByte & 0x7F; + } + if ((firstByte & 0xC0) == 0x80) + { + // two bytes + int secondByte = bits.readBits(8); + return ((firstByte & 0x3F) << 8) | secondByte; + } + if ((firstByte & 0xE0) == 0xC0) + { + // three bytes + int secondThirdBytes = bits.readBits(16); + return ((firstByte & 0x1F) << 16) | secondThirdBytes; + } + throw FormatException.FormatInstance; + } + } -} + +} \ No newline at end of file diff --git a/csharp/qrcode/decoder/Decoder.cs b/csharp/qrcode/decoder/Decoder.cs index bd6321aee..5c2e9ca6c 100755 --- a/csharp/qrcode/decoder/Decoder.cs +++ b/csharp/qrcode/decoder/Decoder.cs @@ -1,153 +1,173 @@ +using System.Collections.Generic; + /* -* 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. -*/ -using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DecoderResult = com.google.zxing.common.DecoderResult; -using GF256 = com.google.zxing.common.reedsolomon.GF256; -using ReedSolomonDecoder = com.google.zxing.common.reedsolomon.ReedSolomonDecoder; -using ReedSolomonException = com.google.zxing.common.reedsolomon.ReedSolomonException; + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - ///

The main class which implements QR Code decoding -- as opposed to locating and extracting + + using ChecksumException = com.google.zxing.ChecksumException; + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DecoderResult = com.google.zxing.common.DecoderResult; + using GenericGF = com.google.zxing.common.reedsolomon.GenericGF; + using ReedSolomonDecoder = com.google.zxing.common.reedsolomon.ReedSolomonDecoder; + using ReedSolomonException = com.google.zxing.common.reedsolomon.ReedSolomonException; + + + ///

+ ///

The main class which implements QR Code decoding -- as opposed to locating and extracting /// the QR Code from an image.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Decoder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'rsDecoder '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ReedSolomonDecoder rsDecoder; - - public Decoder() + + private readonly ReedSolomonDecoder rsDecoder; + + public Decoder() + { + rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(boolean[][] image) throws com.google.zxing.ChecksumException, com.google.zxing.FormatException + public DecoderResult decode(bool[][] image) + { + return decode(image, null); + } + + /// + ///

Convenience method that can decode a QR Code represented as a 2D array of booleans. + /// "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black QR Code modules + /// text and bytes encoded within the QR Code + /// if the QR Code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(boolean[][] image, java.util.Map hints) throws com.google.zxing.ChecksumException, com.google.zxing.FormatException + public DecoderResult decode(bool[][] image, IDictionary hints) + { + int dimension = image.Length; + BitMatrix bits = new BitMatrix(dimension); + for (int i = 0; i < dimension; i++) { - rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD); + for (int j = 0; j < dimension; j++) + { + if (image[i][j]) + { + bits.set(j, i); + } + } } - - ///

Convenience method that can decode a QR Code represented as a 2D array of booleans. - /// "true" is taken to mean a black module.

- /// - ///
- /// booleans representing white/black QR Code modules - /// - /// text and bytes encoded within the QR Code - /// - /// ReaderException if the QR Code cannot be decoded - public DecoderResult decode(bool[][] image) + return decode(bits, hints); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(com.google.zxing.common.BitMatrix bits) throws com.google.zxing.ChecksumException, com.google.zxing.FormatException + public DecoderResult decode(BitMatrix bits) + { + return decode(bits, null); + } + + /// + ///

Decodes a QR Code represented as a . A 1 or "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black QR Code modules + /// text and bytes encoded within the QR Code + /// if the QR Code cannot be decoded + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DecoderResult decode(com.google.zxing.common.BitMatrix bits, java.util.Map hints) throws com.google.zxing.FormatException, com.google.zxing.ChecksumException + public DecoderResult decode(BitMatrix bits, IDictionary hints) + { + + // Construct a parser and read version, error-correction level + BitMatrixParser parser = new BitMatrixParser(bits); + Version version = parser.readVersion(); + ErrorCorrectionLevel ecLevel = parser.readFormatInformation().ErrorCorrectionLevel; + + // Read codewords + sbyte[] codewords = parser.readCodewords(); + // Separate into data blocks + DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); + + // Count total number of data bytes + int totalBytes = 0; + foreach (DataBlock dataBlock in dataBlocks) { - int dimension = image.Length; - BitMatrix bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - for (int j = 0; j < dimension; j++) - { - if (image[i][j]) - { - bits.set_Renamed(j, i); - } - } - } - return decode(bits); + totalBytes += dataBlock.NumDataCodewords; } - - ///

Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.

- /// - ///
- /// booleans representing white/black QR Code modules - /// - /// text and bytes encoded within the QR Code - /// - /// ReaderException if the QR Code cannot be decoded - public DecoderResult decode(BitMatrix bits) + sbyte[] resultBytes = new sbyte[totalBytes]; + int resultOffset = 0; + + // Error-correct and copy data blocks together into a stream of bytes + foreach (DataBlock dataBlock in dataBlocks) { - - // Construct a parser and read version, error-correction level - BitMatrixParser parser = new BitMatrixParser(bits); - Version version = parser.readVersion(); - ErrorCorrectionLevel ecLevel = parser.readFormatInformation().ErrorCorrectionLevel; - - // Read codewords - sbyte[] codewords = parser.readCodewords(); - // Separate into data blocks - DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); - - // Count total number of data bytes - int totalBytes = 0; - for (int i = 0; i < dataBlocks.Length; i++) - { - totalBytes += dataBlocks[i].NumDataCodewords; - } - sbyte[] resultBytes = new sbyte[totalBytes]; - int resultOffset = 0; - - // Error-correct and copy data blocks together into a stream of bytes - for (int j = 0; j < dataBlocks.Length; j++) - { - DataBlock dataBlock = dataBlocks[j]; - sbyte[] codewordBytes = dataBlock.Codewords; - int numDataCodewords = dataBlock.NumDataCodewords; - correctErrors(codewordBytes, numDataCodewords); - for (int i = 0; i < numDataCodewords; i++) - { - resultBytes[resultOffset++] = codewordBytes[i]; - } - } - - // Decode the contents of that stream of bytes - return DecodedBitStreamParser.decode(resultBytes, version, ecLevel); + sbyte[] codewordBytes = dataBlock.Codewords; + int numDataCodewords = dataBlock.NumDataCodewords; + correctErrors(codewordBytes, numDataCodewords); + for (int i = 0; i < numDataCodewords; i++) + { + resultBytes[resultOffset++] = codewordBytes[i]; + } } - - ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to - /// correct the errors in-place using Reed-Solomon error correction.

- /// - ///
- /// data and error correction codewords - /// - /// number of codewords that are data bytes - /// - /// ReaderException if error correction fails - private void correctErrors(sbyte[] codewordBytes, int numDataCodewords) + + // Decode the contents of that stream of bytes + return DecodedBitStreamParser.decode(resultBytes, version, ecLevel, hints); + } + + /// + ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to + /// correct the errors in-place using Reed-Solomon error correction.

+ ///
+ /// data and error correction codewords + /// number of codewords that are data bytes + /// if error correction fails +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private void correctErrors(byte[] codewordBytes, int numDataCodewords) throws com.google.zxing.ChecksumException + private void correctErrors(sbyte[] codewordBytes, int numDataCodewords) + { + int numCodewords = codewordBytes.Length; + // First read into an array of ints + int[] codewordsInts = new int[numCodewords]; + for (int i = 0; i < numCodewords; i++) { - int numCodewords = codewordBytes.Length; - // First read into an array of ints - int[] codewordsInts = new int[numCodewords]; - for (int i = 0; i < numCodewords; i++) - { - codewordsInts[i] = codewordBytes[i] & 0xFF; - } - int numECCodewords = codewordBytes.Length - numDataCodewords; - try - { - rsDecoder.decode(codewordsInts, numECCodewords); - } - catch (ReedSolomonException) - { - throw ReaderException.Instance; - } - // 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 (int i = 0; i < numDataCodewords; i++) - { - codewordBytes[i] = (sbyte) codewordsInts[i]; - } + codewordsInts[i] = codewordBytes[i] & 0xFF; } + int numECCodewords = codewordBytes.Length - numDataCodewords; + try + { + rsDecoder.decode(codewordsInts, numECCodewords); + } + catch (ReedSolomonException rse) + { + throw ChecksumException.ChecksumInstance; + } + // 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 (int i = 0; i < numDataCodewords; i++) + { + codewordBytes[i] = (sbyte) codewordsInts[i]; + } + } + } -} + +} \ No newline at end of file diff --git a/csharp/qrcode/decoder/ErrorCorrectionLevel.cs b/csharp/qrcode/decoder/ErrorCorrectionLevel.cs index 1b65cc95d..1926ddb20 100755 --- a/csharp/qrcode/decoder/ErrorCorrectionLevel.cs +++ b/csharp/qrcode/decoder/ErrorCorrectionLevel.cs @@ -1,102 +1,84 @@ /* -* 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. -*/ + * 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. + */ + using System; + namespace com.google.zxing.qrcode.decoder { - - ///

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + + ///

+ ///

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels /// defined by the QR code standard.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class ErrorCorrectionLevel { - public int Bits - { - get - { - return bits; - } - - } - public System.String Name - { - get - { - return name; - } - - } - - // No, we can't use an enum here. J2ME doesn't support it. - - /// L = ~7% correction - //UPGRADE_NOTE: Final was removed from the declaration of 'L '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L"); - /// M = ~15% correction - //UPGRADE_NOTE: Final was removed from the declaration of 'M '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M"); - /// Q = ~25% correction - //UPGRADE_NOTE: Final was removed from the declaration of 'Q '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q"); - /// H = ~30% correction - //UPGRADE_NOTE: Final was removed from the declaration of 'H '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H"); - - //UPGRADE_NOTE: Final was removed from the declaration of 'FOR_BITS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly ErrorCorrectionLevel[] FOR_BITS = new ErrorCorrectionLevel[]{M, L, H, Q}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'ordinal '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int ordinal_Renamed_Field; - //UPGRADE_NOTE: Final was removed from the declaration of 'bits '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int bits; - //UPGRADE_NOTE: Final was removed from the declaration of 'name '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String name; - - private ErrorCorrectionLevel(int ordinal, int bits, System.String name) - { - this.ordinal_Renamed_Field = ordinal; - this.bits = bits; - this.name = name; - } - - public int ordinal() - { - return ordinal_Renamed_Field; - } - - public override System.String ToString() - { - return name; - } - - /// int containing the two bits encoding a QR Code's error correction level - /// - /// {@link ErrorCorrectionLevel} representing the encoded error correction level - /// - public static ErrorCorrectionLevel forBits(int bits) - { - if (bits < 0 || bits >= FOR_BITS.Length) - { - throw new System.ArgumentException(); - } - return FOR_BITS[bits]; - } - } + + /// L = ~7% correction + public static readonly ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L"); + /// M = ~15% correction + public static readonly ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M"); + /// Q = ~25% correction + public static readonly ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q"); + /// H = ~30% correction + public static readonly ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H"); + + private static readonly ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q}; + + private int ordinal_Renamed_Field; + private int bits; + private System.String name; + + ErrorCorrectionLevel(int ordinal, int bits, System.String name) + { + this.ordinal_Renamed_Field = ordinal; + this.bits = bits; + this.name = name; + } + + public int Bits + { + get {return bits;} + } + + public int ordinal() + { + return ordinal_Renamed_Field; + } + + public override System.String ToString() + { + return name; + } + + /// int containing the two bits encoding a QR Code's error correction level + /// + /// ErrorCorrectionLevel representing the encoded error correction level + /// + public static ErrorCorrectionLevel forBits(int bits) + { + if (bits < 0 || bits >= FOR_BITS.Length) + { + throw new System.ArgumentException(); + } + return FOR_BITS[bits]; + } + + +} + } \ No newline at end of file diff --git a/csharp/qrcode/decoder/FormatInformation.cs b/csharp/qrcode/decoder/FormatInformation.cs index cf820d620..d268527a0 100755 --- a/csharp/qrcode/decoder/FormatInformation.cs +++ b/csharp/qrcode/decoder/FormatInformation.cs @@ -1,144 +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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - ///

Encapsulates a QR Code's format information, including the data mask used and + + ///

+ ///

Encapsulates a QR Code's format information, including the data mask used and /// error correction level.

/// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - /// - /// - /// - /// - sealed class FormatInformation + /// @author Sean Owen
+ /// + /// + internal sealed class FormatInformation { - internal ErrorCorrectionLevel ErrorCorrectionLevel + + private const int FORMAT_INFO_MASK_QR = 0x5412; + + /// + /// See ISO 18004:2006, Annex C, Table C.1 + /// + private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = {new int[] {0x5412, 0x00}, new int[] {0x5125, 0x01}, new int[] {0x5E7C, 0x02}, new int[] {0x5B4B, 0x03}, new int[] {0x45F9, 0x04}, new int[] {0x40CE, 0x05}, new int[] {0x4F97, 0x06}, new int[] {0x4AA0, 0x07}, new int[] {0x77C4, 0x08}, new int[] {0x72F3, 0x09}, new int[] {0x7DAA, 0x0A}, new int[] {0x789D, 0x0B}, new int[] {0x662F, 0x0C}, new int[] {0x6318, 0x0D}, new int[] {0x6C41, 0x0E}, new int[] {0x6976, 0x0F}, new int[] {0x1689, 0x10}, new int[] {0x13BE, 0x11}, new int[] {0x1CE7, 0x12}, new int[] {0x19D0, 0x13}, new int[] {0x0762, 0x14}, new int[] {0x0255, 0x15}, new int[] {0x0D0C, 0x16}, new int[] {0x083B, 0x17}, new int[] {0x355F, 0x18}, new int[] {0x3068, 0x19}, new int[] {0x3F31, 0x1A}, new int[] {0x3A06, 0x1B}, new int[] {0x24B4, 0x1C}, new int[] {0x2183, 0x1D}, new int[] {0x2EDA, 0x1E}, new int[] {0x2BED, 0x1F}}; + + /// + /// Offset i holds the number of 1 bits in the binary representation of i + /// + private static readonly int[] BITS_SET_IN_HALF_BYTE = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; + + private readonly ErrorCorrectionLevel errorCorrectionLevel; + private readonly sbyte dataMask; + + private FormatInformation(int formatInfo) + { + // Bits 3,4 + errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); + // Bottom 3 bits + dataMask = (sbyte)(formatInfo & 0x07); + } + + internal static int numBitsDiffering(int a, int b) + { + a ^= b; // a now has a 1 bit exactly where its bit differs with b's + // Count bits set quickly with a series of lookups: + return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 4 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 8 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 12 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 16 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 20 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 24 & 0x0F))] + BITS_SET_IN_HALF_BYTE[((int)((uint)a >> 28 & 0x0F))]; + } + + /// format info indicator, with mask still applied + /// second copy of same info; both are checked at the same time + /// to establish best match + /// information about the format it specifies, or {@code null} + /// if doesn't seem to match any known pattern + internal static FormatInformation decodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) + { + FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); + if (formatInfo != null) { - get + return formatInfo; + } + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR); + } + + private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo1, int maskedFormatInfo2) + { + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + int bestDifference = int.MaxValue; + int bestFormatInfo = 0; + foreach (int[] decodeInfo in FORMAT_INFO_DECODE_LOOKUP) + { + int targetInfo = decodeInfo[0]; + if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) + { + // Found an exact match + return new FormatInformation(decodeInfo[1]); + } + int bitsDifference = numBitsDiffering(maskedFormatInfo1, targetInfo); + if (bitsDifference < bestDifference) + { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + if (maskedFormatInfo1 != maskedFormatInfo2) + { + // also try the other option + bitsDifference = numBitsDiffering(maskedFormatInfo2, targetInfo); + if (bitsDifference < bestDifference) { - return errorCorrectionLevel; + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; } - + } } - internal sbyte DataMask + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits + // differing means we found a match + if (bestDifference <= 3) { - get - { - return dataMask; - } - + return new FormatInformation(bestFormatInfo); } - - private const int FORMAT_INFO_MASK_QR = 0x5412; - - /// See ISO 18004:2006, Annex C, Table C.1 - //UPGRADE_NOTE: Final was removed from the declaration of 'FORMAT_INFO_DECODE_LOOKUP'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = new int[][]{new int[]{0x5412, 0x00}, new int[]{0x5125, 0x01}, new int[]{0x5E7C, 0x02}, new int[]{0x5B4B, 0x03}, new int[]{0x45F9, 0x04}, new int[]{0x40CE, 0x05}, new int[]{0x4F97, 0x06}, new int[]{0x4AA0, 0x07}, new int[]{0x77C4, 0x08}, new int[]{0x72F3, 0x09}, new int[]{0x7DAA, 0x0A}, new int[]{0x789D, 0x0B}, new int[]{0x662F, 0x0C}, new int[]{0x6318, 0x0D}, new int[]{0x6C41, 0x0E}, new int[]{0x6976, 0x0F}, new int[]{0x1689, 0x10}, new int[]{0x13BE, 0x11}, new int[]{0x1CE7, 0x12}, new int[]{0x19D0, 0x13}, new int[]{0x0762, 0x14}, new int[]{0x0255, 0x15}, new int[]{0x0D0C, 0x16}, new int[]{0x083B, 0x17}, new int[]{0x355F, 0x18}, new int[]{0x3068, 0x19}, new int[]{0x3F31, 0x1A}, new int[]{0x3A06, 0x1B}, new int[]{0x24B4, 0x1C}, new int[]{0x2183, 0x1D}, new int[]{0x2EDA, 0x1E}, new int[]{0x2BED, 0x1F}}; - - /// Offset i holds the number of 1 bits in the binary representation of i - //UPGRADE_NOTE: Final was removed from the declaration of 'BITS_SET_IN_HALF_BYTE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] BITS_SET_IN_HALF_BYTE = new int[]{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'errorCorrectionLevel '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ErrorCorrectionLevel errorCorrectionLevel; - //UPGRADE_NOTE: Final was removed from the declaration of 'dataMask '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private sbyte dataMask; - - private FormatInformation(int formatInfo) + return null; + } + + internal ErrorCorrectionLevel ErrorCorrectionLevel + { + get + { + return errorCorrectionLevel; + } + } + + internal sbyte DataMask + { + get + { + return dataMask; + } + } + + public override int GetHashCode() + { + return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask; + } + + public override bool Equals(object o) + { + if (!(o is FormatInformation)) { - // Bits 3,4 - errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); - // Bottom 3 bits - dataMask = (sbyte) (formatInfo & 0x07); - } - - internal static int numBitsDiffering(int a, int b) - { - a ^= b; // a now has a 1 bit exactly where its bit differs with b's - // Count bits set quickly with a series of lookups: - return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 28) & 0x0F)]; - } - - /// format info indicator, with mask still applied - /// - /// information about the format it specifies, or null - /// if doesn't seem to match any known pattern - /// - internal static FormatInformation decodeFormatInformation(int maskedFormatInfo) - { - FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo); - if (formatInfo != null) - { - return formatInfo; - } - // Should return null, but, some QR codes apparently - // do not mask this info. Try again by actually masking the pattern - // first - return doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR); - } - - private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo) - { - // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing - int bestDifference = System.Int32.MaxValue; - int bestFormatInfo = 0; - for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.Length; i++) - { - int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; - int targetInfo = decodeInfo[0]; - if (targetInfo == maskedFormatInfo) - { - // Found an exact match - return new FormatInformation(decodeInfo[1]); - } - int bitsDifference = numBitsDiffering(maskedFormatInfo, targetInfo); - if (bitsDifference < bestDifference) - { - bestFormatInfo = decodeInfo[1]; - bestDifference = bitsDifference; - } - } - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits - // differing means we found a match - if (bestDifference <= 3) - { - return new FormatInformation(bestFormatInfo); - } - return null; - } - - public override int GetHashCode() - { - return (errorCorrectionLevel.ordinal() << 3) | (int) dataMask; - } - - public override bool Equals(System.Object o) - { - if (!(o is FormatInformation)) - { - return false; - } - FormatInformation other = (FormatInformation) o; - return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; + return false; } + FormatInformation other = (FormatInformation) o; + return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/decoder/Mode.cs b/csharp/qrcode/decoder/Mode.cs index 86843f846..b26465bbb 100755 --- a/csharp/qrcode/decoder/Mode.cs +++ b/csharp/qrcode/decoder/Mode.cs @@ -1,158 +1,144 @@ /* -* 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. -*/ + * 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. + */ + using System; + namespace com.google.zxing.qrcode.decoder { - - ///

See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which - /// data can be encoded to bits in the QR code standard.

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class Mode - { - public int Bits - { - get - { - return bits; - } - - } - public System.String Name - { - get - { - return name; - } - - } - - // No, we can't use an enum here. J2ME doesn't support it. - - //UPGRADE_NOTE: Final was removed from the declaration of 'TERMINATOR '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode TERMINATOR = new Mode(new int[]{0, 0, 0}, 0x00, "TERMINATOR"); // Not really a mode... - //UPGRADE_NOTE: Final was removed from the declaration of 'NUMERIC '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode NUMERIC = new Mode(new int[]{10, 12, 14}, 0x01, "NUMERIC"); - //UPGRADE_NOTE: Final was removed from the declaration of 'ALPHANUMERIC '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode ALPHANUMERIC = new Mode(new int[]{9, 11, 13}, 0x02, "ALPHANUMERIC"); - //UPGRADE_NOTE: Final was removed from the declaration of 'STRUCTURED_APPEND '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode STRUCTURED_APPEND = new Mode(new int[]{0, 0, 0}, 0x03, "STRUCTURED_APPEND"); // Not supported - //UPGRADE_NOTE: Final was removed from the declaration of 'BYTE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode BYTE = new Mode(new int[]{8, 16, 16}, 0x04, "BYTE"); - //UPGRADE_NOTE: Final was removed from the declaration of 'ECI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply - //UPGRADE_NOTE: Final was removed from the declaration of 'KANJI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode KANJI = new Mode(new int[]{8, 10, 12}, 0x08, "KANJI"); - //UPGRADE_NOTE: Final was removed from the declaration of 'FNC1_FIRST_POSITION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION"); - //UPGRADE_NOTE: Final was removed from the declaration of 'FNC1_SECOND_POSITION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION"); - - //UPGRADE_NOTE: Final was removed from the declaration of 'characterCountBitsForVersions '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] characterCountBitsForVersions; - //UPGRADE_NOTE: Final was removed from the declaration of 'bits '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int bits; - //UPGRADE_NOTE: Final was removed from the declaration of 'name '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.String name; - - private Mode(int[] characterCountBitsForVersions, int bits, System.String name) - { - this.characterCountBitsForVersions = characterCountBitsForVersions; - this.bits = bits; - this.name = name; - } - - /// four bits encoding a QR Code data mode - /// - /// {@link Mode} encoded by these bits - /// - /// IllegalArgumentException if bits do not correspond to a known mode - public static Mode forBits(int bits) - { - switch (bits) - { - - case 0x0: - return TERMINATOR; - - case 0x1: - return NUMERIC; - - case 0x2: - return ALPHANUMERIC; - - case 0x3: - return STRUCTURED_APPEND; - - case 0x4: - return BYTE; - - case 0x5: - return FNC1_FIRST_POSITION; - - case 0x7: - return ECI; - - case 0x8: - return KANJI; - - case 0x9: - return FNC1_SECOND_POSITION; - - default: - throw new System.ArgumentException(); - - } - } - - /// version in question - /// - /// number of bits used, in this QR Code symbol {@link Version}, to encode the - /// count of characters that will follow encoded in this {@link Mode} - /// - public int getCharacterCountBits(Version version) - { - if (characterCountBitsForVersions == null) - { - throw new System.ArgumentException("Character count doesn't apply to this mode"); - } - int number = version.VersionNumber; - int offset; - if (number <= 9) - { - offset = 0; - } - else if (number <= 26) - { - offset = 1; - } - else - { - offset = 2; - } - return characterCountBitsForVersions[offset]; - } - - public override System.String ToString() - { - return name; - } - } + + /// + ///

See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which + /// data can be encoded to bits in the QR code standard.

+ /// + /// @author Sean Owen + ///
+ public class Mode + { + private Mode() + { + + } + + private class InnerMode : Mode + { + private readonly int[] characterCountBitsForVersions; + private readonly int bits; + + public InnerMode(int[] characterCountBitsForVersions, int bits) + { + this.characterCountBitsForVersions = characterCountBitsForVersions; + this.bits = bits; + } + + public override int Bits + { + get { return bits; } + } + + /// version in question + /// number of bits used, in this QR Code symbol , to encode the + /// count of characters that will follow encoded in this Mode + public override int getCharacterCountBits(Version version) + { + int number = version.VersionNumber; + int offset; + if (number <= 9) + { + offset = 0; + } + else if (number <= 26) + { + offset = 1; + } + else + { + offset = 2; + } + return characterCountBitsForVersions[offset]; + } + } + + public virtual int getCharacterCountBits(Version version) + { + throw new NotImplementedException(); + } + + public virtual int Bits + { + get + { + throw new NotImplementedException(); + } + } + public static Mode TERMINATOR = new InnerMode(new int[] { 0, 0, 0 }, 0x00); // Not really a mode... + + + public static Mode NUMERIC = new InnerMode(new int[] { 10, 12, 14 }, 0x01); + public static Mode ALPHANUMERIC = new InnerMode(new int[] { 9, 11, 13 }, 0x02); + public static Mode STRUCTURED_APPEND = new InnerMode(new int[] { 0, 0, 0 }, 0x03); // Not supported + + public static Mode BYTE = new InnerMode(new int[] { 8, 16, 16 }, 0x04); + public static Mode ECI = new InnerMode(new int[] { 0, 0, 0 }, 0x07); // character counts don't apply + + public static Mode KANJI = new InnerMode(new int[] { 8, 10, 12 }, 0x08); + public static Mode FNC1_FIRST_POSITION = new InnerMode(new int[] { 0, 0, 0 }, 0x05); + public static Mode FNC1_SECOND_POSITION = new InnerMode(new int[] { 0, 0, 0 }, 0x09); + /// + /// See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. + public static Mode HANZI = new InnerMode(new int[] { 8, 10, 12 }, 0x0D); + + + + /// four bits encoding a QR Code data mode + /// Mode encoded by these bits + /// if bits do not correspond to a known mode + public static Mode forBits(int bits) + { + switch (bits) + { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x3: + return STRUCTURED_APPEND; + case 0x4: + return BYTE; + case 0x5: + return FNC1_FIRST_POSITION; + case 0x7: + return ECI; + case 0x8: + return KANJI; + case 0x9: + return FNC1_SECOND_POSITION; + case 0xD: + // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + return HANZI; + default: + throw new System.ArgumentException(); + } + } + + /// version in question + /// number of bits used, in this QR Code symbol , to encode the + /// count of characters that will follow encoded in this Mode + + + } } \ No newline at end of file diff --git a/csharp/qrcode/decoder/Version.cs b/csharp/qrcode/decoder/Version.cs index 853119405..225e30bed 100755 --- a/csharp/qrcode/decoder/Version.cs +++ b/csharp/qrcode/decoder/Version.cs @@ -1,320 +1,312 @@ -/* -* 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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using BitMatrix = com.google.zxing.common.BitMatrix; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.decoder { - - /// See ISO 18004:2006 Annex D + + using FormatException = com.google.zxing.FormatException; + using BitMatrix = com.google.zxing.common.BitMatrix; + + /// + /// See ISO 18004:2006 Annex D /// + /// @author Sean Owen /// - /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class Version { - public int VersionNumber + + /// + /// See ISO 18004:2006 Annex D. + /// Element i represents the raw version bits that specify version i + 7 + /// + private static readonly int[] VERSION_DECODE_INFO = {0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69}; + + private static readonly Version[] VERSIONS = buildVersions(); + + private readonly int versionNumber; + private readonly int[] alignmentPatternCenters; + private readonly ECBlocks[] ecBlocks; + private readonly int totalCodewords; + + private Version(int versionNumber, int[] alignmentPatternCenters, params ECBlocks[] ecBlocks) + { + this.versionNumber = versionNumber; + this.alignmentPatternCenters = alignmentPatternCenters; + this.ecBlocks = ecBlocks; + int total = 0; + int ecCodewords = ecBlocks[0].ECCodewordsPerBlock; + ECB[] ecbArray = ecBlocks[0].ECBlocks2; + foreach (ECB ecBlock in ecbArray) + { + total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); + } + this.totalCodewords = total; + } + + public int VersionNumber + { + get + { + return versionNumber; + } + } + + public int[] AlignmentPatternCenters + { + get + { + return alignmentPatternCenters; + } + } + + public int TotalCodewords + { + get + { + return totalCodewords; + } + } + + public int DimensionForVersion + { + get + { + return 17 + 4 * versionNumber; + } + } + + public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) + { + return ecBlocks[ecLevel.ordinal()]; + } + + /// + ///

Deduces version information purely from QR Code dimensions.

+ ///
+ /// dimension in modules + /// Version for a QR Code of that dimension + /// if dimension is not 1 mod 4 +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public static Version getProvisionalVersionForDimension(int dimension) throws com.google.zxing.FormatException + public static Version getProvisionalVersionForDimension(int dimension) + { + if (dimension % 4 != 1) + { + throw FormatException.FormatInstance; + } + try + { + return getVersionForNumber((dimension - 17) >> 2); + } + catch (System.ArgumentException iae) + { + throw FormatException.FormatInstance; + } + } + + public static Version getVersionForNumber(int versionNumber) + { + if (versionNumber < 1 || versionNumber > 40) + { + throw new System.ArgumentException(); + } + return VERSIONS[versionNumber - 1]; + } + + public static Version decodeVersionInformation(int versionBits) + { + int bestDifference = int.MaxValue; + int bestVersion = 0; + for (int i = 0; i < VERSION_DECODE_INFO.Length; i++) + { + int targetVersion = VERSION_DECODE_INFO[i]; + // Do the version info bits match exactly? done. + if (targetVersion == versionBits) + { + return getVersionForNumber(i + 7); + } + // Otherwise see if this is the closest to a real version info bit string + // we have seen so far + int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); + if (bitsDifference < bestDifference) + { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + // We can tolerate up to 3 bits of error since no two version info codewords will + // differ in less than 8 bits. + if (bestDifference <= 3) + { + return getVersionForNumber(bestVersion); + } + // If we didn't find a close enough match, fail + return null; + } + + /// + /// See ISO 18004:2006 Annex E + /// + internal BitMatrix buildFunctionPattern() + { + int dimension = DimensionForVersion; + BitMatrix bitMatrix = new BitMatrix(dimension); + + // Top left finder pattern + separator + format + bitMatrix.setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + bitMatrix.setRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + bitMatrix.setRegion(0, dimension - 8, 9, 8); + + // Alignment patterns + int max = alignmentPatternCenters.Length; + for (int x = 0; x < max; x++) + { + int i = alignmentPatternCenters[x] - 2; + for (int y = 0; y < max; y++) + { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) + { + // No alignment patterns near the three finder paterns + continue; + } + bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5); + } + } + + // Vertical timing pattern + bitMatrix.setRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + bitMatrix.setRegion(9, 6, dimension - 17, 1); + + if (versionNumber > 6) + { + // Version info, top right + bitMatrix.setRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + bitMatrix.setRegion(0, dimension - 11, 6, 3); + } + + return bitMatrix; + } + + /// + ///

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.

+ ///
+ public sealed class ECBlocks + { + private readonly int ecCodewordsPerBlock; + private readonly ECB[] ecBlocks; + + internal ECBlocks(int ecCodewordsPerBlock, params ECB[] ecBlocks) + { + this.ecCodewordsPerBlock = ecCodewordsPerBlock; + this.ecBlocks = ecBlocks; + } + + public int ECCodewordsPerBlock { get { - return versionNumber; + return ecCodewordsPerBlock; } - } - public int[] AlignmentPatternCenters + + public int NumBlocks { get { - return alignmentPatternCenters; + int total = 0; + foreach (ECB ecBlock in ecBlocks) + { + total += ecBlock.Count; + } + return total; } - } - public int TotalCodewords + + public int TotalECCodewords { get { - return totalCodewords; + return ecCodewordsPerBlock * NumBlocks; } - } - public int DimensionForVersion + + public ECB[] ECBlocks2 { get { - return 17 + 4 * versionNumber; + return ecBlocks; } - } - - /// See ISO 18004:2006 Annex D. - /// Element i represents the raw version bits that specify version i + 7 - /// - //UPGRADE_NOTE: Final was removed from the declaration of 'VERSION_DECODE_INFO'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] VERSION_DECODE_INFO = new int[]{0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'VERSIONS '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly Version[] VERSIONS = buildVersions(); - - //UPGRADE_NOTE: Final was removed from the declaration of 'versionNumber '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int versionNumber; - //UPGRADE_NOTE: Final was removed from the declaration of 'alignmentPatternCenters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] alignmentPatternCenters; - //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ECBlocks[] ecBlocks; - //UPGRADE_NOTE: Final was removed from the declaration of 'totalCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int totalCodewords; - - private Version(int versionNumber, int[] alignmentPatternCenters, ECBlocks ecBlocks1, ECBlocks ecBlocks2, ECBlocks ecBlocks3, ECBlocks ecBlocks4) + } + + /// + ///

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 QR code version's format.

+ ///
+ public sealed class ECB + { + private readonly int count; + private readonly int dataCodewords; + + internal ECB(int count, int dataCodewords) { - this.versionNumber = versionNumber; - this.alignmentPatternCenters = alignmentPatternCenters; - this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4}; - int total = 0; - int ecCodewords = ecBlocks1.ECCodewordsPerBlock; - ECB[] ecbArray = ecBlocks1.getECBlocks(); - for (int i = 0; i < ecbArray.Length; i++) - { - ECB ecBlock = ecbArray[i]; - total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); - } - this.totalCodewords = total; + this.count = count; + this.dataCodewords = dataCodewords; } - - public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) + + public int Count { - return ecBlocks[ecLevel.ordinal()]; + get + { + return count; + } } - - ///

Deduces version information purely from QR Code dimensions.

- /// - ///
- /// dimension in modules - /// - /// {@link Version} for a QR Code of that dimension - /// - /// ReaderException if dimension is not 1 mod 4 - public static Version getProvisionalVersionForDimension(int dimension) + + public int DataCodewords { - if (dimension % 4 != 1) + get { - throw ReaderException.Instance; - } - try - { - return getVersionForNumber((dimension - 17) >> 2); - } - catch (System.ArgumentException) - { - throw ReaderException.Instance; + return dataCodewords; } } - - public static Version getVersionForNumber(int versionNumber) - { - if (versionNumber < 1 || versionNumber > 40) - { - throw new System.ArgumentException(); - } - return VERSIONS[versionNumber - 1]; - } - - internal static Version decodeVersionInformation(int versionBits) - { - int bestDifference = System.Int32.MaxValue; - int bestVersion = 0; - for (int i = 0; i < VERSION_DECODE_INFO.Length; i++) - { - int targetVersion = VERSION_DECODE_INFO[i]; - // Do the version info bits match exactly? done. - if (targetVersion == versionBits) - { - return getVersionForNumber(i + 7); - } - // Otherwise see if this is the closest to a real version info bit string - // we have seen so far - int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); - if (bitsDifference < bestDifference) - { - bestVersion = i + 7; - bestDifference = bitsDifference; - } - } - // We can tolerate up to 3 bits of error since no two version info codewords will - // differ in less than 4 bits. - if (bestDifference <= 3) - { - return getVersionForNumber(bestVersion); - } - // If we didn't find a close enough match, fail - return null; - } - - /// See ISO 18004:2006 Annex E - internal BitMatrix buildFunctionPattern() - { - int dimension = DimensionForVersion; - BitMatrix bitMatrix = new BitMatrix(dimension); - - // Top left finder pattern + separator + format - bitMatrix.setRegion(0, 0, 9, 9); - // Top right finder pattern + separator + format - bitMatrix.setRegion(dimension - 8, 0, 8, 9); - // Bottom left finder pattern + separator + format - bitMatrix.setRegion(0, dimension - 8, 9, 8); - - // Alignment patterns - int max = alignmentPatternCenters.Length; - for (int x = 0; x < max; x++) - { - int i = alignmentPatternCenters[x] - 2; - for (int y = 0; y < max; y++) - { - if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) - { - // No alignment patterns near the three finder paterns - continue; - } - bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5); - } - } - - // Vertical timing pattern - bitMatrix.setRegion(6, 9, 1, dimension - 17); - // Horizontal timing pattern - bitMatrix.setRegion(9, 6, dimension - 17, 1); - - if (versionNumber > 6) - { - // Version info, top right - bitMatrix.setRegion(dimension - 11, 0, 3, 6); - // Version info, bottom left - bitMatrix.setRegion(0, dimension - 11, 6, 3); - } - - return bitMatrix; - } - - ///

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.

- ///
- public sealed class ECBlocks - { - public int ECCodewordsPerBlock - { - get - { - return ecCodewordsPerBlock; - } - - } - public int NumBlocks - { - get - { - int total = 0; - for (int i = 0; i < ecBlocks.Length; i++) - { - total += ecBlocks[i].Count; - } - return total; - } - - } - public int TotalECCodewords - { - get - { - return ecCodewordsPerBlock * NumBlocks; - } - - } - //UPGRADE_NOTE: Final was removed from the declaration of 'ecCodewordsPerBlock '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int ecCodewordsPerBlock; - //UPGRADE_NOTE: Final was removed from the declaration of 'ecBlocks '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ECB[] ecBlocks; - - internal ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) - { - this.ecCodewordsPerBlock = ecCodewordsPerBlock; - this.ecBlocks = new ECB[]{ecBlocks}; - } - - internal ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) - { - this.ecCodewordsPerBlock = ecCodewordsPerBlock; - this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2}; - } - - public ECB[] getECBlocks() - { - return ecBlocks; - } - } - - ///

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 QR code version's format.

- ///
- public sealed class ECB - { - public int Count - { - get - { - return count; - } - - } - public int DataCodewords - { - get - { - return dataCodewords; - } - - } - //UPGRADE_NOTE: Final was removed from the declaration of 'count '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int count; - //UPGRADE_NOTE: Final was removed from the declaration of 'dataCodewords '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int dataCodewords; - - internal ECB(int count, int dataCodewords) - { - this.count = count; - this.dataCodewords = dataCodewords; - } - } - - public override System.String ToString() - { - return System.Convert.ToString(versionNumber); - } - - /// See ISO 18004:2006 6.5.1 Table 9 - private static Version[] buildVersions() - { - return new Version[]{new Version(1, new int[]{}, new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), new Version(2, new int[]{6, 18}, new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), new Version(3, new int[]{6, 22}, new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), new Version(4, new int[]{6, 26}, new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), new Version(5, new int[]{6, 30}, new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), new Version(6, new int[]{6, 34}, new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), new Version(7, new int[]{6, 22, 38}, new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), new Version(8, new int[]{6, 24, 42}, new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), new Version(9, new int[]{6, 26, 46}, new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), new Version(10, new int[]{6, 28, 50}, new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))), new Version(11, new int[]{6, 30, 54}, new ECBlocks(20, new ECB(4, 81)), - new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), new Version(12, new int[]{6, 32, 58}, new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), new Version(13, new int[]{6, 34, 62}, new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), new Version(14, new int[]{6, 26, 46, 66}, new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), new Version(15, new int[]{6, 26, 48, 70}, new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), new Version(16, new int[]{6, 26, 50, 74}, new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), new Version(17, new int[]{6, 30, 54, 78}, new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), new Version(18, new int[]{6, 30, 56, 82}, new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), new Version(19, new int[]{6, 30, 58, 86}, new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), - new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), new Version(20, new int[]{6, 34, 62, 90}, new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), new Version(21, new int[]{6, 28, 50, 72, 94}, new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), new Version(22, new int[]{6, 26, 50, 74, 98}, new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), new Version(23, new int[]{6, 30, 54, 74, 102}, new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), new Version(24, new int[]{6, 28, 54, 80, 106}, new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), new Version(25, new int[]{6, 32, 58, 84, 110}, new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), new Version(26, new int[]{6, 30, 58, 86, 114}, new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), new Version(27, new int[]{6, 34, 62, 90, 118}, new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), - new ECB(28, 16))), new Version(28, new int[]{6, 26, 50, 74, 98, 122}, new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), new Version(29, new int[]{6, 30, 54, 78, 102, 126}, new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), new Version(30, new int[]{6, 26, 52, 78, 104, 130}, new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), new Version(31, new int[]{6, 30, 56, 82, 108, 134}, new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), new Version(32, new int[]{6, 34, 60, 86, 112, 138}, new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), new Version(33, new int[]{6, 30, 58, 86, 114, 142}, new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), new Version(34, new int[]{6, 34, 62, 90, 118, 146}, new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new - ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16)))}; - } + } + + public override string ToString() + { + return Convert.ToString(versionNumber); + } + + /// + /// See ISO 18004:2006 6.5.1 Table 9 + /// + private static Version[] buildVersions() + { + return new Version[]{new Version(1, new int[]{}, new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), new Version(2, new int[]{6, 18}, new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), new Version(3, new int[]{6, 22}, new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), new Version(4, new int[]{6, 26}, new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), new Version(5, new int[]{6, 30}, new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), new Version(6, new int[]{6, 34}, new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), new Version(7, new int[]{6, 22, 38}, new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), new Version(8, new int[]{6, 24, 42}, new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), new Version(9, new int[]{6, 26, 46}, new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), new Version(10, new int[]{6, 28, 50}, new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))), new Version(11, new int[]{6, 30, 54}, new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), new Version(12, new int[]{6, 32, 58}, new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), new Version(13, new int[]{6, 34, 62}, new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), new Version(14, new int[]{6, 26, 46, 66}, new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), new Version(15, new int[]{6, 26, 48, 70}, new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), new Version(16, new int[]{6, 26, 50, 74}, new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), new Version(17, new int[]{6, 30, 54, 78}, new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), new Version(18, new int[]{6, 30, 56, 82}, new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), new Version(19, new int[]{6, 30, 58, 86}, new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), new Version(20, new int[]{6, 34, 62, 90}, new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), new Version(21, new int[]{6, 28, 50, 72, 94}, new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), new Version(22, new int[]{6, 26, 50, 74, 98}, new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), new Version(23, new int[]{6, 30, 54, 78, 102}, new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), new Version(24, new int[]{6, 28, 54, 80, 106}, new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), new Version(25, new int[]{6, 32, 58, 84, 110}, new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), new Version(26, new int[]{6, 30, 58, 86, 114}, new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), new Version(27, new int[]{6, 34, 62, 90, 118}, new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))), new Version(28, new int[]{6, 26, 50, 74, 98, 122}, new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), new Version(29, new int[]{6, 30, 54, 78, 102, 126}, new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), new Version(30, new int[]{6, 26, 52, 78, 104, 130}, new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), new Version(31, new int[]{6, 30, 56, 82, 108, 134}, new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), new Version(32, new int[]{6, 34, 60, 86, 112, 138}, new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), new Version(33, new int[]{6, 30, 58, 86, 114, 142}, new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), new Version(34, new int[]{6, 34, 62, 90, 118, 146}, new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16)))}; + } + } -} + +} \ No newline at end of file diff --git a/csharp/qrcode/detector/AlignmentPattern.cs b/csharp/qrcode/detector/AlignmentPattern.cs index e4066572f..9bc8bce31 100755 --- a/csharp/qrcode/detector/AlignmentPattern.cs +++ b/csharp/qrcode/detector/AlignmentPattern.cs @@ -1,53 +1,67 @@ -/* -* 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. -*/ using System; -using ResultPoint = com.google.zxing.ResultPoint; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

Encapsulates an alignment pattern, which are the smaller square patterns found in + + using ResultPoint = com.google.zxing.ResultPoint; + + ///

+ ///

Encapsulates an alignment pattern, which are the smaller square patterns found in /// all but the simplest QR Codes.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class AlignmentPattern:ResultPoint + public sealed class AlignmentPattern : com.google.zxing.ResultPoint { - - //UPGRADE_NOTE: Final was removed from the declaration of 'estimatedModuleSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float estimatedModuleSize; - - internal AlignmentPattern(float posX, float posY, float estimatedModuleSize):base(posX, posY) + + private readonly float estimatedModuleSize; + + internal AlignmentPattern(float posX, float posY, float estimatedModuleSize) : base(posX, posY) + { + this.estimatedModuleSize = estimatedModuleSize; + } + + /// + ///

Determines if this alignment pattern "about equals" an alignment pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ internal bool aboutEquals(float moduleSize, float i, float j) + { + if (Math.Abs(i - Y) <= moduleSize && Math.Abs(j - X) <= moduleSize) { - this.estimatedModuleSize = estimatedModuleSize; - } - - ///

Determines if this alignment pattern "about equals" an alignment pattern at the stated - /// position and size -- meaning, it is at nearly the same center with nearly the same size.

- ///
- internal bool aboutEquals(float moduleSize, float i, float j) - { - if (System.Math.Abs(i - Y) <= moduleSize && System.Math.Abs(j - X) <= moduleSize) - { - float moduleSizeDiff = System.Math.Abs(moduleSize - estimatedModuleSize); - return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; - } - return false; + float moduleSizeDiff = Math.Abs(moduleSize - estimatedModuleSize); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize; } + return false; + } + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. + /// + internal AlignmentPattern combineEstimate(float i, float j, float newModuleSize) + { + float combinedX = (X + j) / 2.0f; + float combinedY = (Y + i) / 2.0f; + float combinedModuleSize = (estimatedModuleSize + newModuleSize) / 2.0f; + return new AlignmentPattern(combinedX, combinedY, combinedModuleSize); + } + } } \ No newline at end of file diff --git a/csharp/qrcode/detector/AlignmentPatternFinder.cs b/csharp/qrcode/detector/AlignmentPatternFinder.cs index 44aca1552..4f52a0ede 100755 --- a/csharp/qrcode/detector/AlignmentPatternFinder.cs +++ b/csharp/qrcode/detector/AlignmentPatternFinder.cs @@ -1,339 +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. -*/ using System; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultPointCallback = com.google.zxing.ResultPointCallback; -using BitMatrix = com.google.zxing.common.BitMatrix; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder + + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitMatrix = com.google.zxing.common.BitMatrix; + + + ///

+ ///

This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder /// patterns but are smaller and appear at regular intervals throughout the image.

/// ///

At the moment this only looks for the bottom-right alignment pattern.

/// - ///

This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, + ///

This is mostly a simplified copy of . It is copied, /// pasted and stripped down here for maximum performance but does unfortunately duplicate /// some code.

/// - ///

This class is thread-safe but not reentrant. Each thread must allocate its own object. + ///

This class is thread-safe but not reentrant. Each thread must allocate its own object.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class AlignmentPatternFinder + internal sealed class AlignmentPatternFinder { - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix image; - //UPGRADE_NOTE: Final was removed from the declaration of 'possibleCenters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList possibleCenters; - //UPGRADE_NOTE: Final was removed from the declaration of 'startX '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int startX; - //UPGRADE_NOTE: Final was removed from the declaration of 'startY '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int startY; - //UPGRADE_NOTE: Final was removed from the declaration of 'width '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int width; - //UPGRADE_NOTE: Final was removed from the declaration of 'height '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int height; - //UPGRADE_NOTE: Final was removed from the declaration of 'moduleSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float moduleSize; - //UPGRADE_NOTE: Final was removed from the declaration of 'crossCheckStateCount '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] crossCheckStateCount; - //UPGRADE_NOTE: Final was removed from the declaration of 'resultPointCallback '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPointCallback resultPointCallback; - - ///

Creates a finder that will look in a portion of the whole image.

- /// - ///
- /// image to search - /// - /// left column from which to start searching - /// - /// top row from which to start searching - /// - /// width of region to search - /// - /// height of region to search - /// - /// estimated module size so far - /// - internal AlignmentPatternFinder(BitMatrix image, int startX, int startY, int width, int height, float moduleSize, ResultPointCallback resultPointCallback) + + private readonly BitMatrix image; + private readonly IList possibleCenters; + private readonly int startX; + private readonly int startY; + private readonly int width; + private readonly int height; + private readonly float moduleSize; + private readonly int[] crossCheckStateCount; + private readonly ResultPointCallback resultPointCallback; + + /// + ///

Creates a finder that will look in a portion of the whole image.

+ ///
+ /// image to search + /// left column from which to start searching + /// top row from which to start searching + /// width of region to search + /// height of region to search + /// estimated module size so far + internal AlignmentPatternFinder(BitMatrix image, int startX, int startY, int width, int height, float moduleSize, ResultPointCallback resultPointCallback) + { + this.image = image; + this.possibleCenters = new List(5); + this.startX = startX; + this.startY = startY; + this.width = width; + this.height = height; + this.moduleSize = moduleSize; + this.crossCheckStateCount = new int[3]; + this.resultPointCallback = resultPointCallback; + } + + /// + ///

This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since + /// it's pretty performance-critical and so is written to be fast foremost.

+ ///
+ /// if found + /// if not found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: AlignmentPattern find() throws com.google.zxing.NotFoundException + internal AlignmentPattern find() + { + int startX = this.startX; + int height = this.height; + int maxJ = startX + width; + int middleI = startY + (height >> 1); + // We are looking for black/white/black modules in 1:1:1 ratio; + // this tracks the number of black/white/black modules seen so far + int[] stateCount = new int[3]; + for (int iGen = 0; iGen < height; iGen++) { - this.image = image; - this.possibleCenters = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(5)); - this.startX = startX; - this.startY = startY; - this.width = width; - this.height = height; - this.moduleSize = moduleSize; - this.crossCheckStateCount = new int[3]; - this.resultPointCallback = resultPointCallback; - } - - ///

This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since - /// it's pretty performance-critical and so is written to be fast foremost.

- /// - ///
- /// {@link AlignmentPattern} if found - /// - /// ReaderException if not found - internal AlignmentPattern find() - { - int startX = this.startX; - int height = this.height; - int maxJ = startX + width; - int middleI = startY + (height >> 1); - // We are looking for black/white/black modules in 1:1:1 ratio; - // this tracks the number of black/white/black modules seen so far - int[] stateCount = new int[3]; - for (int iGen = 0; iGen < height; iGen++) + // Search from middle outwards + int i = middleI + ((iGen & 0x01) == 0 ? (iGen + 1) >> 1 : -((iGen + 1) >> 1)); + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + int j = startX; + // Burn off leading white pixels before anything else; if we start in the middle of + // a white run, it doesn't make sense to count its length, since we don't know if the + // white run continued to the left of the start point + while (j < maxJ && !image.get(j, i)) + { + j++; + } + int currentState = 0; + while (j < maxJ) + { + if (image.get(j, i)) { - // Search from middle outwards - int i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1)); - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - int j = startX; - // Burn off leading white pixels before anything else; if we start in the middle of - // a white run, it doesn't make sense to count its length, since we don't know if the - // white run continued to the left of the start point - while (j < maxJ && !image.get_Renamed(j, i)) + // Black pixel + if (currentState == 1) // Counting black pixels + { + stateCount[currentState]++; + } // Counting white pixels + else + { + if (currentState == 2) // A winner? { - j++; - } - int currentState = 0; - while (j < maxJ) - { - if (image.get_Renamed(j, i)) - { - // Black pixel - if (currentState == 1) - { - // Counting black pixels - stateCount[currentState]++; - } - else - { - // Counting white pixels - if (currentState == 2) - { - // A winner? - if (foundPatternCross(stateCount)) - { - // Yes - AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j); - if (confirmed != null) - { - return confirmed; - } - } - stateCount[0] = stateCount[2]; - stateCount[1] = 1; - stateCount[2] = 0; - currentState = 1; - } - else - { - stateCount[++currentState]++; - } - } - } - else - { - // White pixel - if (currentState == 1) - { - // Counting black pixels - currentState++; - } - stateCount[currentState]++; - } - j++; - } - if (foundPatternCross(stateCount)) - { - AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (foundPatternCross(stateCount)) // Yes + { + AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, j); if (confirmed != null) { - return confirmed; + return confirmed; } + } + stateCount[0] = stateCount[2]; + stateCount[1] = 1; + stateCount[2] = 0; + currentState = 1; } - } - - // Hmm, nothing we saw was observed and confirmed twice. If we had - // any guess at all, return it. - if (!(possibleCenters.Count == 0)) - { - return (AlignmentPattern) possibleCenters[0]; - } - - throw ReaderException.Instance; - } - - /// Given a count of black/white/black pixels just seen and an end position, - /// figures the location of the center of this black/white/black run. - /// - private static float centerFromEnd(int[] stateCount, int end) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (float) (end - stateCount[2]) - stateCount[1] / 2.0f; - } - - /// count of black/white/black pixels just read - /// - /// true iff the proportions of the counts is close enough to the 1/1/1 ratios - /// used by alignment patterns to be considered a match - /// - private bool foundPatternCross(int[] stateCount) - { - float moduleSize = this.moduleSize; - float maxVariance = moduleSize / 2.0f; - for (int i = 0; i < 3; i++) - { - if (System.Math.Abs(moduleSize - stateCount[i]) >= maxVariance) + else { - return false; + stateCount[++currentState]++; } + } + } // White pixel + else + { + if (currentState == 1) // Counting black pixels + { + currentState++; + } + stateCount[currentState]++; } - return true; + j++; + } + if (foundPatternCross(stateCount)) + { + AlignmentPattern confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (confirmed != null) + { + return confirmed; + } + } + } - - ///

After a horizontal scan finds a potential alignment pattern, this method - /// "cross-checks" by scanning down vertically through the center of the possible - /// alignment pattern to see if the same proportion is detected.

- /// - ///
- /// row where an alignment pattern was detected - /// - /// center of the section that appears to cross an alignment pattern - /// - /// maximum reasonable number of modules that should be - /// observed in any reading state, based on the results of the horizontal scan - /// - /// vertical center of alignment pattern, or {@link Float#NaN} if not found - /// - private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) + + // Hmm, nothing we saw was observed and confirmed twice. If we had + // any guess at all, return it. + if (possibleCenters.Count > 0) { - BitMatrix image = this.image; - - int maxI = image.Height; - int[] stateCount = crossCheckStateCount; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - - // Start counting up from center - int i = startI; - while (i >= 0 && image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount) - { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) - { - return System.Single.NaN; - } - while (i >= 0 && !image.get_Renamed(centerJ, i) && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return System.Single.NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount) - { - stateCount[1]++; - i++; - } - if (i == maxI || stateCount[1] > maxCount) - { - return System.Single.NaN; - } - while (i < maxI && !image.get_Renamed(centerJ, i) && stateCount[2] <= maxCount) - { - stateCount[2]++; - i++; - } - if (stateCount[2] > maxCount) - { - return System.Single.NaN; - } - - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - if (5 * System.Math.Abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) - { - return System.Single.NaN; - } - - return foundPatternCross(stateCount)?centerFromEnd(stateCount, i):System.Single.NaN; + return possibleCenters[0]; } - - ///

This is called when a horizontal scan finds a possible alignment pattern. It will - /// cross check with a vertical scan, and if successful, will see if this pattern had been - /// found on a previous horizontal scan. If so, we consider it confirmed and conclude we have - /// found the alignment pattern.

- /// - ///
- /// reading state module counts from horizontal scan - /// - /// row where alignment pattern may be found - /// - /// end of possible alignment pattern in row - /// - /// {@link AlignmentPattern} if we have found the same pattern twice, or null if not - /// - private AlignmentPattern handlePossibleCenter(int[] stateCount, int i, int j) + + throw NotFoundException.NotFoundInstance; + } + + /// + /// Given a count of black/white/black pixels just seen and an end position, + /// figures the location of the center of this black/white/black run. + /// + private static float centerFromEnd(int[] stateCount, int end) + { + return (float)(end - stateCount[2]) - stateCount[1] / 2.0f; + } + + /// count of black/white/black pixels just read + /// true iff the proportions of the counts is close enough to the 1/1/1 ratios + /// used by alignment patterns to be considered a match + private bool foundPatternCross(int[] stateCount) + { + float moduleSize = this.moduleSize; + float maxVariance = moduleSize / 2.0f; + for (int i = 0; i < 3; i++) { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - float centerJ = centerFromEnd(stateCount, j); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1], stateCountTotal); - if (!System.Single.IsNaN(centerI)) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float estimatedModuleSize = (float) (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; - int max = possibleCenters.Count; - for (int index = 0; index < max; index++) - { - AlignmentPattern center = (AlignmentPattern) possibleCenters[index]; - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) - { - return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - } - } - // Hadn't found this before; save it - ResultPoint point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - possibleCenters.Add(point); - if (resultPointCallback != null) - { - resultPointCallback.foundPossibleResultPoint(point); - } - } - return null; + if (Math.Abs(moduleSize - stateCount[i]) >= maxVariance) + { + return false; + } } + return true; + } + + /// + ///

After a horizontal scan finds a potential alignment pattern, this method + /// "cross-checks" by scanning down vertically through the center of the possible + /// alignment pattern to see if the same proportion is detected.

+ ///
+ /// row where an alignment pattern was detected + /// center of the section that appears to cross an alignment pattern + /// maximum reasonable number of modules that should be + /// observed in any reading state, based on the results of the horizontal scan + /// vertical center of alignment pattern, or if not found + private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) + { + BitMatrix image = this.image; + + int maxI = image.Height; + int[] stateCount = crossCheckStateCount; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + + // Start counting up from center + int i = startI; + while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) + { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) + { + return float.NaN; + } + while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) + { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) + { + return float.NaN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) + { + stateCount[1]++; + i++; + } + if (i == maxI || stateCount[1] > maxCount) + { + return float.NaN; + } + while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) + { + stateCount[2]++; + i++; + } + if (stateCount[2] > maxCount) + { + return float.NaN; + } + + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) + { + return float.NaN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : float.NaN; + } + + /// + ///

This is called when a horizontal scan finds a possible alignment pattern. It will + /// cross check with a vertical scan, and if successful, will see if this pattern had been + /// found on a previous horizontal scan. If so, we consider it confirmed and conclude we have + /// found the alignment pattern.

+ ///
+ /// reading state module counts from horizontal scan + /// row where alignment pattern may be found + /// end of possible alignment pattern in row + /// if we have found the same pattern twice, or null if not + private AlignmentPattern handlePossibleCenter(int[] stateCount, int i, int j) + { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1], stateCountTotal); + if (!float.IsNaN(centerI)) + { + float estimatedModuleSize = (float)(stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; + foreach (AlignmentPattern center in possibleCenters) + { + // Look for about the same center and module size: + if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) + { + return center.combineEstimate(centerI, centerJ, estimatedModuleSize); + } + } + // Hadn't found this before; save it + AlignmentPattern point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); + possibleCenters.Add(point); + if (resultPointCallback != null) + { + resultPointCallback.foundPossibleResultPoint(point); + } + } + return null; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/detector/Detector.cs b/csharp/qrcode/detector/Detector.cs index 0a013e1f1..8fe3091e7 100755 --- a/csharp/qrcode/detector/Detector.cs +++ b/csharp/qrcode/detector/Detector.cs @@ -1,420 +1,417 @@ -/* -* 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. -*/ using System; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultPointCallback = com.google.zxing.ResultPointCallback; -using BitMatrix = com.google.zxing.common.BitMatrix; -using DetectorResult = com.google.zxing.common.DetectorResult; -using GridSampler = com.google.zxing.common.GridSampler; -using PerspectiveTransform = com.google.zxing.common.PerspectiveTransform; -using Version = com.google.zxing.qrcode.decoder.Version; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

Encapsulates logic that can detect a QR Code in an image, even if the QR Code + + using DecodeHintType = com.google.zxing.DecodeHintType; + using FormatException = com.google.zxing.FormatException; + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitMatrix = com.google.zxing.common.BitMatrix; + using DetectorResult = com.google.zxing.common.DetectorResult; + using GridSampler = com.google.zxing.common.GridSampler; + using PerspectiveTransform = com.google.zxing.common.PerspectiveTransform; + using MathUtils = com.google.zxing.common.detector.MathUtils; + using Version = com.google.zxing.qrcode.decoder.Version; + + + ///

+ ///

Encapsulates logic that can detect a QR Code in an image, even if the QR Code /// is rotated or skewed, or partially obscured.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public class Detector { - virtual protected internal BitMatrix Image + + private readonly BitMatrix image; + private ResultPointCallback resultPointCallback; + + public Detector(BitMatrix image) + { + this.image = image; + } + + protected internal BitMatrix Image + { + get + { + return image; + } + } + + protected internal ResultPointCallback ResultPointCallback + { + get + { + return resultPointCallback; + } + } + + /// + ///

Detects a QR Code in an image, simply.

+ ///
+ /// encapsulating results of detecting a QR Code + /// if no QR Code can be found +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public com.google.zxing.common.DetectorResult detect() throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public virtual DetectorResult detect() + { + return detect(null); + } + + /// + ///

Detects a QR Code in an image, simply.

+ ///
+ /// optional hints to detector + /// encapsulating results of detecting a QR Code + /// if QR Code cannot be found + /// if a QR Code cannot be decoded +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public final com.google.zxing.common.DetectorResult detect(java.util.Map hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + public DetectorResult detect(IDictionary hints) + { + + //resultPointCallback = hints == null ? null : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + ResultPointCallback resultPointCallback = null; + if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) + { + resultPointCallback = (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; + } + + FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback); + FinderPatternInfo info = finder.find(hints); + + return processFinderPatternInfo(info); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected final com.google.zxing.common.DetectorResult processFinderPatternInfo(FinderPatternInfo info) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException + protected internal DetectorResult processFinderPatternInfo(FinderPatternInfo info) + { + + FinderPattern topLeft = info.TopLeft; + FinderPattern topRight = info.TopRight; + FinderPattern bottomLeft = info.BottomLeft; + + float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); + if (moduleSize < 1.0f) { - get - { - return image; - } - + throw NotFoundException.NotFoundInstance; } - virtual protected internal ResultPointCallback ResultPointCallback + int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); + Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); + int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; + + AlignmentPattern alignmentPattern = null; + // Anything above version 1 has an alignment pattern + if (provisionalVersion.AlignmentPatternCenters.Length > 0) { - get + + // Guess where a "bottom right" finder pattern would have been + float bottomRightX = topRight.X - topLeft.X + bottomLeft.X; + float bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; + + // Estimate that alignment pattern is closer by 3 modules + // from "bottom right" to known top left location + float correctionToTopLeft = 1.0f - 3.0f / (float) modulesBetweenFPCenters; + int estAlignmentX = (int)(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); + int estAlignmentY = (int)(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); + + // Kind of arbitrary -- expand search radius before giving up + for (int i = 4; i <= 16; i <<= 1) + { + try { - return resultPointCallback; + alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float) i); + break; } - + catch (NotFoundException re) + { + // try next round + } + } + // If we didn't find alignment pattern... well try anyway without it } - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix image; - private ResultPointCallback resultPointCallback; - - public Detector(BitMatrix image) + + PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + + BitMatrix bits = sampleGrid(image, transform, dimension); + + ResultPoint[] points; + if (alignmentPattern == null) { - this.image = image; + points = new ResultPoint[]{bottomLeft, topLeft, topRight}; } - - ///

Detects a QR Code in an image, simply.

- /// - ///
- /// {@link DetectorResult} encapsulating results of detecting a QR Code - /// - /// ReaderException if no QR Code can be found - public virtual DetectorResult detect() + else { - return detect(null); + points = new ResultPoint[]{bottomLeft, topLeft, topRight, alignmentPattern}; } - - ///

Detects a QR Code in an image, simply.

- /// - ///
- /// optional hints to detector - /// - /// {@link DetectorResult} encapsulating results of detecting a QR Code - /// - /// ReaderException if no QR Code can be found - public virtual DetectorResult detect(System.Collections.Hashtable hints) + return new DetectorResult(bits, points); + } + + private static PerspectiveTransform createTransform(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) + { + float dimMinusThree = (float) dimension - 3.5f; + float bottomRightX; + float bottomRightY; + float sourceBottomRightX; + float sourceBottomRightY; + if (alignmentPattern != null) { - - resultPointCallback = hints == null?null:(ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - - FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback); - FinderPatternInfo info = finder.find(hints); - - return processFinderPatternInfo(info); + bottomRightX = alignmentPattern.X; + bottomRightY = alignmentPattern.Y; + sourceBottomRightX = dimMinusThree - 3.0f; + sourceBottomRightY = sourceBottomRightX; } - - protected internal virtual DetectorResult processFinderPatternInfo(FinderPatternInfo info) + else { - - FinderPattern topLeft = info.TopLeft; - FinderPattern topRight = info.TopRight; - FinderPattern bottomLeft = info.BottomLeft; - - float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); - if (moduleSize < 1.0f) - { - throw ReaderException.Instance; - } - int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); - Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); - int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; - - AlignmentPattern alignmentPattern = null; - // Anything above version 1 has an alignment pattern - if (provisionalVersion.AlignmentPatternCenters.Length > 0) - { - - // Guess where a "bottom right" finder pattern would have been - float bottomRightX = topRight.X - topLeft.X + bottomLeft.X; - float bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; - - // Estimate that alignment pattern is closer by 3 modules - // from "bottom right" to known top left location - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float correctionToTopLeft = 1.0f - 3.0f / (float) modulesBetweenFPCenters; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int estAlignmentX = (int) (topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int estAlignmentY = (int) (topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); - - // Kind of arbitrary -- expand search radius before giving up - for (int i = 4; i <= 16; i <<= 1) - { - try - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float) i); - break; - } - catch (ReaderException) - { - // try next round - } - } - // If we didn't find alignment pattern... well try anyway without it - } - - PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); - - BitMatrix bits = sampleGrid(image, transform, dimension); - - ResultPoint[] points; - if (alignmentPattern == null) - { - points = new ResultPoint[]{bottomLeft, topLeft, topRight}; - } - else - { - points = new ResultPoint[]{bottomLeft, topLeft, topRight, alignmentPattern}; - } - return new DetectorResult(bits, points); + // Don't have an alignment pattern, just make up the bottom-right point + bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; + bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; + sourceBottomRightX = dimMinusThree; + sourceBottomRightY = dimMinusThree; } - - public virtual PerspectiveTransform createTransform(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) + + return PerspectiveTransform.quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.common.BitMatrix sampleGrid(com.google.zxing.common.BitMatrix image, com.google.zxing.common.PerspectiveTransform transform, int dimension) throws com.google.zxing.NotFoundException + private static BitMatrix sampleGrid(BitMatrix image, PerspectiveTransform transform, int dimension) + { + + GridSampler sampler = GridSampler.Instance; + return sampler.sampleGrid(image, dimension, dimension, transform); + } + + /// + ///

Computes the dimension (number of modules on a size) of the QR Code based on the position + /// of the finder patterns and estimated module size.

+ ///
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int computeDimension(com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint topRight, com.google.zxing.ResultPoint bottomLeft, float moduleSize) throws com.google.zxing.NotFoundException + private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize) + { + int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); + int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); + int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; + switch (dimension & 0x03) // mod 4 { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float dimMinusThree = (float) dimension - 3.5f; - float bottomRightX; - float bottomRightY; - float sourceBottomRightX; - float sourceBottomRightY; - if (alignmentPattern != null) - { - bottomRightX = alignmentPattern.X; - bottomRightY = alignmentPattern.Y; - sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; - } - else - { - // Don't have an alignment pattern, just make up the bottom-right point - bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; - bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; - sourceBottomRightX = sourceBottomRightY = dimMinusThree; - } - - PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); - - return transform; + case 0: + dimension++; + break; + // 1? do nothing + case 2: + dimension--; + break; + case 3: + throw NotFoundException.NotFoundInstance; } - - private static BitMatrix sampleGrid(BitMatrix image, PerspectiveTransform transform, int dimension) + return dimension; + } + + /// + ///

Computes an average estimated module size based on estimated derived from the positions + /// of the three finder patterns.

+ ///
+ protected internal float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft) + { + // Take the average + return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; + } + + /// + ///

Estimates module size based on two finder patterns -- it uses + /// to figure the + /// width of each, measuring along the axis between their centers.

+ ///
+ private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) + { + float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int) pattern.X, (int) pattern.Y, (int) otherPattern.X, (int) otherPattern.Y); + float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int) otherPattern.X, (int) otherPattern.Y, (int) pattern.X, (int) pattern.Y); + if (float.IsNaN(moduleSizeEst1)) { - - GridSampler sampler = GridSampler.Instance; - return sampler.sampleGrid(image, dimension, transform); + return moduleSizeEst2 / 7.0f; } - - ///

Computes the dimension (number of modules on a size) of the QR Code based on the position - /// of the finder patterns and estimated module size.

- ///
- protected internal static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize) + if (float.IsNaN(moduleSizeEst2)) { - int tltrCentersDimension = round(ResultPoint.distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); - int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; - switch (dimension & 0x03) - { - - // mod 4 - case 0: - dimension++; - break; - // 1? do nothing - - case 2: - dimension--; - break; - - case 3: - throw ReaderException.Instance; - } - return dimension; + return moduleSizeEst1 / 7.0f; } - - ///

Computes an average estimated module size based on estimated derived from the positions - /// of the three finder patterns.

- ///
- protected internal virtual float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft) + // Average them, and divide by 7 since we've counted the width of 3 black modules, + // and 1 white and 1 black module on either side. Ergo, divide sum by 14. + return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; + } + + /// + /// See ; computes the total width of + /// a finder pattern by looking for a black-white-black run from the center in the direction + /// of another point (another finder pattern center), and in the opposite direction too.

+ ///
+ private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) + { + + float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); + + // Now count other way -- don't run off image though of course + float scale = 1.0f; + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { - // Take the average - return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; + scale = (float) fromX / (float)(fromX - otherToX); + otherToX = 0; } - - ///

Estimates module size based on two finder patterns -- it uses - /// {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the - /// width of each, measuring along the axis between their centers.

- ///
- private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) + else if (otherToX >= image.Width) { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int) pattern.X, (int) pattern.Y, (int) otherPattern.X, (int) otherPattern.Y); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int) otherPattern.X, (int) otherPattern.Y, (int) pattern.X, (int) pattern.Y); - if (System.Single.IsNaN(moduleSizeEst1)) - { - return moduleSizeEst2 / 7.0f; - } - if (System.Single.IsNaN(moduleSizeEst2)) - { - return moduleSizeEst1 / 7.0f; - } - // Average them, and divide by 7 since we've counted the width of 3 black modules, - // and 1 white and 1 black module on either side. Ergo, divide sum by 14. - return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; + scale = (float)(image.Width - 1 - fromX) / (float)(otherToX - fromX); + otherToX = image.Width - 1; } - - /// See {@link #sizeOfBlackWhiteBlackRun(int, int, int, int)}; computes the total width of - /// a finder pattern by looking for a black-white-black run from the center in the direction - /// of another point (another finder pattern center), and in the opposite direction too.

- ///
- private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) + int otherToY = (int)(fromY - (toY - fromY) * scale); + + scale = 1.0f; + if (otherToY < 0) { - - float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); - - // Now count other way -- don't run off image though of course - float scale = 1.0f; - int otherToX = fromX - (toX - fromX); - if (otherToX < 0) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - scale = (float) fromX / (float) (fromX - otherToX); - otherToX = 0; - } - else if (otherToX >= image.Width) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - scale = (float) (image.Width - 1 - fromX) / (float) (otherToX - fromX); - otherToX = image.Width - 1; - } - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int otherToY = (int) (fromY - (toY - fromY) * scale); - - scale = 1.0f; - if (otherToY < 0) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - scale = (float) fromY / (float) (fromY - otherToY); - otherToY = 0; - } - else if (otherToY >= image.Height) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - scale = (float) (image.Height - 1 - fromY) / (float) (otherToY - fromY); - otherToY = image.Height - 1; - } - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - otherToX = (int) (fromX + (otherToX - fromX) * scale); - - result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - return result - 1.0f; // -1 because we counted the middle pixel twice + scale = (float) fromY / (float)(fromY - otherToY); + otherToY = 0; } - - ///

This method traces a line from a point in the image, in the direction towards another point. - /// It begins in a black region, and keeps going until it finds white, then black, then white again. - /// It reports the distance from the start to this point.

- /// - ///

This is used when figuring out how wide a finder pattern is, when the finder pattern - /// may be skewed or rotated.

- ///
- private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) + else if (otherToY >= image.Height) { - // Mild variant of Bresenham's algorithm; - // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - bool steep = System.Math.Abs(toY - fromY) > System.Math.Abs(toX - fromX); - if (steep) - { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = System.Math.Abs(toX - fromX); - int dy = System.Math.Abs(toY - fromY); - int error = - dx >> 1; - int ystep = fromY < toY?1:- 1; - int xstep = fromX < toX?1:- 1; - int state = 0; // In black pixels, looking for white, first or second time - for (int x = fromX, y = fromY; x != toX; x += xstep) - { - - int realX = steep?y:x; - int realY = steep?x:y; - if (state == 1) - { - // In white pixels, looking for black - if (image.get_Renamed(realX, realY)) - { - state++; - } - } - else - { - if (!image.get_Renamed(realX, realY)) - { - state++; - } - } - - if (state == 3) - { - // Found black, white, black, and stumbled back onto white; done - int diffX = x - fromX; - int diffY = y - fromY; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (float) System.Math.Sqrt((double) (diffX * diffX + diffY * diffY)); - } - error += dy; - if (error > 0) - { - if (y == toY) - { - break; - } - y += ystep; - error -= dx; - } - } - int diffX2 = toX - fromX; - int diffY2 = toY - fromY; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (float) System.Math.Sqrt((double) (diffX2 * diffX2 + diffY2 * diffY2)); + scale = (float)(image.Height - 1 - fromY) / (float)(otherToY - fromY); + otherToY = image.Height - 1; } - - ///

Attempts to locate an alignment pattern in a limited region of the image, which is - /// guessed to contain it. This method uses {@link AlignmentPattern}.

- /// - ///
- /// estimated module size so far - /// - /// x coordinate of center of area probably containing alignment pattern - /// - /// y coordinate of above - /// - /// number of pixels in all directions to search from the center - /// - /// {@link AlignmentPattern} if found, or null otherwise - /// - /// ReaderException if an unexpected error occurs during detection - protected internal virtual AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, float allowanceFactor) + otherToX = (int)(fromX + (otherToX - fromX) * scale); + + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + + // Middle pixel is double-counted this way; subtract 1 + return result - 1.0f; + } + + /// + ///

This method traces a line from a point in the image, in the direction towards another point. + /// It begins in a black region, and keeps going until it finds white, then black, then white again. + /// It reports the distance from the start to this point.

+ /// + ///

This is used when figuring out how wide a finder pattern is, when the finder pattern + /// may be skewed or rotated.

+ ///
+ private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) + { + // Mild variant of Bresenham's algorithm; + // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + bool steep = Math.Abs(toY - fromY) > Math.Abs(toX - fromX); + if (steep) { - // Look for an alignment pattern (3 modules in size) around where it - // should be - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - int allowance = (int) (allowanceFactor * overallEstModuleSize); - int alignmentAreaLeftX = System.Math.Max(0, estAlignmentX - allowance); - int alignmentAreaRightX = System.Math.Min(image.Width - 1, estAlignmentX + allowance); - if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) - { - throw ReaderException.Instance; - } - - int alignmentAreaTopY = System.Math.Max(0, estAlignmentY - allowance); - int alignmentAreaBottomY = System.Math.Min(image.Height - 1, estAlignmentY + allowance); - - AlignmentPatternFinder alignmentFinder = new AlignmentPatternFinder(image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, resultPointCallback); - return alignmentFinder.find(); + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; } - - /// Ends up being a bit faster than Math.round(). This merely rounds its argument to the nearest int, - /// where x.5 rounds up. - /// - private static int round(float d) + + int dx = Math.Abs(toX - fromX); + int dy = Math.Abs(toY - fromY); + int error = -dx >> 1; + int xstep = fromX < toX ? 1 : -1; + int ystep = fromY < toY ? 1 : -1; + + // In black pixels, looking for white, first or second time. + int state = 0; + // Loop up until x == toX, but not beyond + int xLimit = toX + xstep; + for (int x = fromX, y = fromY; x != xLimit; x += xstep) { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (int) (d + 0.5f); + int realX = steep ? y : x; + int realY = steep ? x : y; + + // Does current pixel mean we have moved white to black or vice versa? + // Scanning black in state 0,2 and white in state 1, so if we find the wrong + // color, advance to next state or end if we are in state 2 already + if ((state == 1) == image.get(realX, realY)) + { + if (state == 2) + { + return MathUtils.distance(x, y, fromX, fromY); + } + state++; + } + + error += dy; + if (error > 0) + { + if (y == toY) + { + break; + } + y += ystep; + error -= dx; + } } + // Found black-white-black; give the benefit of the doubt that the next pixel outside the image + // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a + // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. + if (state == 2) + { + return MathUtils.distance(toX + xstep, toY, fromX, fromY); + } + // else we didn't find even black-white-black; no estimate is really possible + return float.NaN; + } + + /// + ///

Attempts to locate an alignment pattern in a limited region of the image, which is + /// guessed to contain it. This method uses .

+ ///
+ /// estimated module size so far + /// x coordinate of center of area probably containing alignment pattern + /// y coordinate of above + /// number of pixels in all directions to search from the center + /// if found, or null otherwise + /// if an unexpected error occurs during detection +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: protected final AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, float allowanceFactor) throws com.google.zxing.NotFoundException + protected internal AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, float allowanceFactor) + { + // Look for an alignment pattern (3 modules in size) around where it + // should be + int allowance = (int)(allowanceFactor * overallEstModuleSize); + int alignmentAreaLeftX = Math.Max(0, estAlignmentX - allowance); + int alignmentAreaRightX = Math.Min(image.Width - 1, estAlignmentX + allowance); + if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) + { + throw NotFoundException.NotFoundInstance; + } + + int alignmentAreaTopY = Math.Max(0, estAlignmentY - allowance); + int alignmentAreaBottomY = Math.Min(image.Height - 1, estAlignmentY + allowance); + if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) + { + throw NotFoundException.NotFoundInstance; + } + + AlignmentPatternFinder alignmentFinder = new AlignmentPatternFinder(image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, resultPointCallback); + return alignmentFinder.find(); + } + } -} + +} \ No newline at end of file diff --git a/csharp/qrcode/detector/FinderPattern.cs b/csharp/qrcode/detector/FinderPattern.cs index 8b01a4734..8ca11c5a8 100755 --- a/csharp/qrcode/detector/FinderPattern.cs +++ b/csharp/qrcode/detector/FinderPattern.cs @@ -1,77 +1,98 @@ -/* -* 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. -*/ using System; -using ResultPoint = com.google.zxing.ResultPoint; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

Encapsulates a finder pattern, which are the three square patterns found in + + using ResultPoint = com.google.zxing.ResultPoint; + + ///

+ ///

Encapsulates a finder pattern, which are the three square patterns found in /// the corners of QR Codes. It also encapsulates a count of similar finder patterns, /// as a convenience to the finder's bookkeeping.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class FinderPattern:ResultPoint + public sealed class FinderPattern : com.google.zxing.ResultPoint { - public float EstimatedModuleSize + + private readonly float estimatedModuleSize; + private int count; + + internal FinderPattern(float posX, float posY, float estimatedModuleSize) : this(posX, posY, estimatedModuleSize, 1) + { + } + + private FinderPattern(float posX, float posY, float estimatedModuleSize, int count) : base(posX, posY) + { + this.estimatedModuleSize = estimatedModuleSize; + this.count = count; + } + + public float EstimatedModuleSize + { + get + { + return estimatedModuleSize; + } + } + + internal int Count + { + get + { + return count; + } + } + + internal void incrementCount() + { + this.count++; + } + + /// + ///

Determines if this finder pattern "about equals" a finder pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ internal bool aboutEquals(float moduleSize, float i, float j) + { + if (Math.Abs(i - Y) <= moduleSize && Math.Abs(j - X) <= moduleSize) { - get - { - return estimatedModuleSize; - } - - } - internal int Count - { - get - { - return count; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'estimatedModuleSize '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private float estimatedModuleSize; - private int count; - - internal FinderPattern(float posX, float posY, float estimatedModuleSize):base(posX, posY) - { - this.estimatedModuleSize = estimatedModuleSize; - this.count = 1; - } - - internal void incrementCount() - { - this.count++; - } - - ///

Determines if this finder pattern "about equals" a finder pattern at the stated - /// position and size -- meaning, it is at nearly the same center with nearly the same size.

- ///
- internal bool aboutEquals(float moduleSize, float i, float j) - { - if (System.Math.Abs(i - Y) <= moduleSize && System.Math.Abs(j - X) <= moduleSize) - { - float moduleSizeDiff = System.Math.Abs(moduleSize - estimatedModuleSize); - return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; - } - return false; + float moduleSizeDiff = Math.Abs(moduleSize - estimatedModuleSize); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize; } + return false; + } + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing a weighted average + /// based on count. + /// + internal FinderPattern combineEstimate(float i, float j, float newModuleSize) + { + int combinedCount = count + 1; + float combinedX = (count * X + j) / combinedCount; + float combinedY = (count * Y + i) / combinedCount; + float combinedModuleSize = (count * estimatedModuleSize + newModuleSize) / combinedCount; + return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount); + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/detector/FinderPatternFinder.cs b/csharp/qrcode/detector/FinderPatternFinder.cs index 9ba804971..17a224266 100755 --- a/csharp/qrcode/detector/FinderPatternFinder.cs +++ b/csharp/qrcode/detector/FinderPatternFinder.cs @@ -1,646 +1,675 @@ -/* -* 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. -*/ using System; -using DecodeHintType = com.google.zxing.DecodeHintType; -using ReaderException = com.google.zxing.ReaderException; -using ResultPoint = com.google.zxing.ResultPoint; -using ResultPointCallback = com.google.zxing.ResultPointCallback; -using Collections = com.google.zxing.common.Collections; -using Comparator = com.google.zxing.common.Comparator; -using BitMatrix = com.google.zxing.common.BitMatrix; +using System.Collections.Generic; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

This class attempts to find finder patterns in a QR Code. Finder patterns are the square + + using DecodeHintType = com.google.zxing.DecodeHintType; + using NotFoundException = com.google.zxing.NotFoundException; + using ResultPoint = com.google.zxing.ResultPoint; + using ResultPointCallback = com.google.zxing.ResultPointCallback; + using BitMatrix = com.google.zxing.common.BitMatrix; + + + ///

+ ///

This class attempts to find finder patterns in a QR Code. Finder patterns are the square /// markers at three corners of a QR Code.

/// ///

This class is thread-safe but not reentrant. Each thread must allocate its own object. /// + /// @author Sean Owen ///

- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public class FinderPatternFinder { - virtual protected internal BitMatrix Image + + private const int CENTER_QUORUM = 2; + protected internal const int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center + protected internal const int MAX_MODULES = 57; // support up to version 10 for mobile clients + private const int INTEGER_MATH_SHIFT = 8; + + private readonly BitMatrix image; + private readonly List possibleCenters; + private bool hasSkipped; + private readonly int[] crossCheckStateCount; + private readonly ResultPointCallback resultPointCallback; + + /// + ///

Creates a finder that will search the image for three finder patterns.

+ ///
+ /// image to search + public FinderPatternFinder(BitMatrix image) : this(image, null) + { + } + + public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) + { + this.image = image; + this.possibleCenters = new List(); + this.crossCheckStateCount = new int[5]; + this.resultPointCallback = resultPointCallback; + } + + protected internal BitMatrix Image + { + get + { + return image; + } + } + + protected internal List PossibleCenters + { + get + { + return possibleCenters; + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: final FinderPatternInfo find(java.util.Map hints) throws com.google.zxing.NotFoundException + internal FinderPatternInfo find(IDictionary hints) + { + bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); + int maxI = image.Height; + int maxJ = image.Width; + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (3 * maxI) / (4 * MAX_MODULES); + if (iSkip < MIN_SKIP || tryHarder) { - get - { - return image; - } - + iSkip = MIN_SKIP; } - virtual protected internal System.Collections.ArrayList PossibleCenters + + bool done = false; + int[] stateCount = new int[5]; + for (int i = iSkip - 1; i < maxI && !done; i += iSkip) { - get + // Get a row of black/white values + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (int j = 0; j < maxJ; j++) + { + if (image.get(j, i)) { - return possibleCenters; - } - - } - private int[] CrossCheckStateCount - { - get + // Black pixel + if ((currentState & 1) == 1) // Counting white pixels + { + currentState++; + } + stateCount[currentState]++; + } // White pixel + else { - crossCheckStateCount[0] = 0; - crossCheckStateCount[1] = 0; - crossCheckStateCount[2] = 0; - crossCheckStateCount[3] = 0; - crossCheckStateCount[4] = 0; - return crossCheckStateCount; - } - - } - - private const int CENTER_QUORUM = 2; - protected internal const int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center - protected internal const int MAX_MODULES = 57; // support up to version 10 for mobile clients - private const int INTEGER_MATH_SHIFT = 8; - - //UPGRADE_NOTE: Final was removed from the declaration of 'image '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private BitMatrix image; - //UPGRADE_NOTE: Final was removed from the declaration of 'possibleCenters '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private System.Collections.ArrayList possibleCenters; - private bool hasSkipped; - //UPGRADE_NOTE: Final was removed from the declaration of 'crossCheckStateCount '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private int[] crossCheckStateCount; - //UPGRADE_NOTE: Final was removed from the declaration of 'resultPointCallback '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ResultPointCallback resultPointCallback; - - ///

Creates a finder that will search the image for three finder patterns.

- /// - ///
- /// image to search - /// - public FinderPatternFinder(BitMatrix image):this(image, null) - { - } - - public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) - { - this.image = image; - this.possibleCenters = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10)); - this.crossCheckStateCount = new int[5]; - this.resultPointCallback = resultPointCallback; - } - - internal virtual FinderPatternInfo find(System.Collections.Hashtable hints) - { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - int maxI = image.Height; - int maxJ = image.Width; - // We are looking for black/white/black/white/black modules in - // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far - - // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the - // image, and then account for the center being 3 modules in size. This gives the smallest - // number of pixels the center could be, so skip this often. When trying harder, look for all - // QR versions regardless of how dense they are. - int iSkip = (3 * maxI) / (4 * MAX_MODULES); - if (iSkip < MIN_SKIP || tryHarder) - { - iSkip = MIN_SKIP; - } - - bool done = false; - int[] stateCount = new int[5]; - for (int i = iSkip - 1; i < maxI && !done; i += iSkip) - { - // Get a row of black/white values - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - int currentState = 0; - for (int j = 0; j < maxJ; j++) + if ((currentState & 1) == 0) // Counting black pixels + { + if (currentState == 4) // A winner? { - if (image.get_Renamed(j, i)) - { - // Black pixel - if ((currentState & 1) == 1) - { - // Counting white pixels - currentState++; - } - stateCount[currentState]++; - } - else - { - // White pixel - if ((currentState & 1) == 0) - { - // Counting black pixels - if (currentState == 4) - { - // A winner? - if (foundPatternCross(stateCount)) - { - // Yes - bool confirmed = handlePossibleCenter(stateCount, i, j); - if (confirmed) - { - // Start examining every other line. Checking each line turned out to be too - // expensive and didn't improve performance. - iSkip = 2; - if (hasSkipped) - { - done = haveMultiplyConfirmedCenters(); - } - else - { - int rowSkip = findRowSkip(); - if (rowSkip > stateCount[2]) - { - // Skip rows between row of lower confirmed center - // and top of presumed third confirmed center - // but back up a bit to get a full chance of detecting - // it, entire width of center of finder pattern - - // Skip by rowSkip, but back off by stateCount[2] (size of last center - // of pattern we saw) to be conservative, and also back off by iSkip which - // is about to be re-added - i += rowSkip - stateCount[2] - iSkip; - j = maxJ - 1; - } - } - } - else - { - // Advance to next black pixel - do - { - j++; - } - while (j < maxJ && !image.get_Renamed(j, i)); - j--; // back up to that last white pixel - } - // Clear state to start looking again - currentState = 0; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - } - else - { - // No, shift counts back by two - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - } - } - else - { - stateCount[++currentState]++; - } - } - else - { - // Counting white pixels - stateCount[currentState]++; - } - } - } - if (foundPatternCross(stateCount)) - { - bool confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (foundPatternCross(stateCount)) // Yes + { + bool confirmed = handlePossibleCenter(stateCount, i, j); if (confirmed) { - iSkip = stateCount[0]; - if (hasSkipped) + // Start examining every other line. Checking each line turned out to be too + // expensive and didn't improve performance. + iSkip = 2; + if (hasSkipped) + { + done = haveMultiplyConfirmedCenters(); + } + else + { + int rowSkip = findRowSkip(); + if (rowSkip > stateCount[2]) { - // Found a third one - done = haveMultiplyConfirmedCenters(); + // Skip rows between row of lower confirmed center + // and top of presumed third confirmed center + // but back up a bit to get a full chance of detecting + // it, entire width of center of finder pattern + + // Skip by rowSkip, but back off by stateCount[2] (size of last center + // of pattern we saw) to be conservative, and also back off by iSkip which + // is about to be re-added + i += rowSkip - stateCount[2] - iSkip; + j = maxJ - 1; } - } - } - } - - FinderPattern[] patternInfo = selectBestPatterns(); - ResultPoint.orderBestPatterns(patternInfo); - - return new FinderPatternInfo(patternInfo); - } - - /// Given a count of black/white/black/white/black pixels just seen and an end position, - /// figures the location of the center of this run. - /// - private static float centerFromEnd(int[] stateCount, int end) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (float) (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; - } - - /// count of black/white/black/white/black pixels just read - /// - /// true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios - /// used by finder patterns to be considered a match - /// - protected internal static bool foundPatternCross(int[] stateCount) - { - int totalModuleSize = 0; - for (int i = 0; i < 5; i++) - { - int count = stateCount[i]; - if (count == 0) - { - return false; - } - totalModuleSize += count; - } - if (totalModuleSize < 7) - { - return false; - } - int moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7; - int maxVariance = moduleSize / 2; - // Allow less than 50% variance from 1-1-3-1-1 proportions - return System.Math.Abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && System.Math.Abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && System.Math.Abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && System.Math.Abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && System.Math.Abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance; - } - - ///

After a horizontal scan finds a potential finder pattern, this method - /// "cross-checks" by scanning down vertically through the center of the possible - /// finder pattern to see if the same proportion is detected.

- /// - ///
- /// row where a finder pattern was detected - /// - /// center of the section that appears to cross a finder pattern - /// - /// maximum reasonable number of modules that should be - /// observed in any reading state, based on the results of the horizontal scan - /// - /// vertical center of finder pattern, or {@link Float#NaN} if not found - /// - private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) - { - BitMatrix image = this.image; - - int maxI = image.Height; - int[] stateCount = CrossCheckStateCount; - - // Start counting up from center - int i = startI; - while (i >= 0 && image.get_Renamed(centerJ, i)) - { - stateCount[2]++; - i--; - } - if (i < 0) - { - return System.Single.NaN; - } - while (i >= 0 && !image.get_Renamed(centerJ, i) && stateCount[1] <= maxCount) - { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) - { - return System.Single.NaN; - } - while (i >= 0 && image.get_Renamed(centerJ, i) && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return System.Single.NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image.get_Renamed(centerJ, i)) - { - stateCount[2]++; - i++; - } - if (i == maxI) - { - return System.Single.NaN; - } - while (i < maxI && !image.get_Renamed(centerJ, i) && stateCount[3] < maxCount) - { - stateCount[3]++; - i++; - } - if (i == maxI || stateCount[3] >= maxCount) - { - return System.Single.NaN; - } - while (i < maxI && image.get_Renamed(centerJ, i) && stateCount[4] < maxCount) - { - stateCount[4]++; - i++; - } - if (stateCount[4] >= maxCount) - { - return System.Single.NaN; - } - - // If we found a finder-pattern-like section, but its size is more than 40% different than - // the original, assume it's a false positive - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - if (5 * System.Math.Abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) - { - return System.Single.NaN; - } - - return foundPatternCross(stateCount)?centerFromEnd(stateCount, i):System.Single.NaN; - } - - ///

Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, - /// except it reads horizontally instead of vertically. This is used to cross-cross - /// check a vertical cross check and locate the real center of the alignment pattern.

- ///
- private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal) - { - BitMatrix image = this.image; - - int maxJ = image.Width; - int[] stateCount = CrossCheckStateCount; - - int j = startJ; - while (j >= 0 && image.get_Renamed(j, centerI)) - { - stateCount[2]++; - j--; - } - if (j < 0) - { - return System.Single.NaN; - } - while (j >= 0 && !image.get_Renamed(j, centerI) && stateCount[1] <= maxCount) - { - stateCount[1]++; - j--; - } - if (j < 0 || stateCount[1] > maxCount) - { - return System.Single.NaN; - } - while (j >= 0 && image.get_Renamed(j, centerI) && stateCount[0] <= maxCount) - { - stateCount[0]++; - j--; - } - if (stateCount[0] > maxCount) - { - return System.Single.NaN; - } - - j = startJ + 1; - while (j < maxJ && image.get_Renamed(j, centerI)) - { - stateCount[2]++; - j++; - } - if (j == maxJ) - { - return System.Single.NaN; - } - while (j < maxJ && !image.get_Renamed(j, centerI) && stateCount[3] < maxCount) - { - stateCount[3]++; - j++; - } - if (j == maxJ || stateCount[3] >= maxCount) - { - return System.Single.NaN; - } - while (j < maxJ && image.get_Renamed(j, centerI) && stateCount[4] < maxCount) - { - stateCount[4]++; - j++; - } - if (stateCount[4] >= maxCount) - { - return System.Single.NaN; - } - - // If we found a finder-pattern-like section, but its size is significantly different than - // the original, assume it's a false positive - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - if (5 * System.Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) - { - return System.Single.NaN; - } - - return foundPatternCross(stateCount)?centerFromEnd(stateCount, j):System.Single.NaN; - } - - ///

This is called when a horizontal scan finds a possible alignment pattern. It will - /// cross check with a vertical scan, and if successful, will, ah, cross-cross-check - /// with another horizontal scan. This is needed primarily to locate the real horizontal - /// center of the pattern in cases of extreme skew.

- /// - ///

If that succeeds the finder pattern location is added to a list that tracks - /// the number of times each location has been nearly-matched as a finder pattern. - /// Each additional find is more evidence that the location is in fact a finder - /// pattern center - /// - ///

- /// reading state module counts from horizontal scan - /// - /// row where finder pattern may be found - /// - /// end of possible finder pattern in row - /// - /// true if a finder pattern candidate was found this time - /// - protected internal virtual bool handlePossibleCenter(int[] stateCount, int i, int j) - { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - float centerJ = centerFromEnd(stateCount, j); - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2], stateCountTotal); - if (!System.Single.IsNaN(centerI)) - { - // Re-cross check - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal); - if (!System.Single.IsNaN(centerJ)) - { - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float estimatedModuleSize = (float) stateCountTotal / 7.0f; - bool found = false; - int max = possibleCenters.Count; - for (int index = 0; index < max; index++) - { - FinderPattern center = (FinderPattern) possibleCenters[index]; - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) - { - center.incrementCount(); - found = true; - break; - } - } - if (!found) - { - ResultPoint point = new FinderPattern(centerJ, centerI, estimatedModuleSize); - possibleCenters.Add(point); - if (resultPointCallback != null) - { - resultPointCallback.foundPossibleResultPoint(point); - } - } - return true; - } - } - return false; - } - - /// number of rows we could safely skip during scanning, based on the first - /// two finder patterns that have been located. In some cases their position will - /// allow us to infer that the third pattern must lie below a certain point farther - /// down in the image. - /// - private int findRowSkip() - { - int max = possibleCenters.Count; - if (max <= 1) - { - return 0; - } - FinderPattern firstConfirmedCenter = null; - for (int i = 0; i < max; i++) - { - FinderPattern center = (FinderPattern) possibleCenters[i]; - if (center.Count >= CENTER_QUORUM) - { - if (firstConfirmedCenter == null) - { - firstConfirmedCenter = center; + } } else { - // We have two confirmed centers - // How far down can we skip before resuming looking for the next - // pattern? In the worst case, only the difference between the - // difference in the x / y coordinates of the two centers. - // This is the case where you find top left last. - hasSkipped = true; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return (int) (System.Math.Abs(firstConfirmedCenter.X - center.X) - System.Math.Abs(firstConfirmedCenter.Y - center.Y)) / 2; + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + continue; } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } // No, shift counts back by two + else + { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } } - } - return 0; - } - - /// true iff we have found at least 3 finder patterns that have been detected - /// at least {@link #CENTER_QUORUM} times each, and, the estimated module size of the - /// candidates is "pretty similar" - /// - private bool haveMultiplyConfirmedCenters() - { - int confirmedCount = 0; - float totalModuleSize = 0.0f; - int max = possibleCenters.Count; - for (int i = 0; i < max; i++) - { - FinderPattern pattern = (FinderPattern) possibleCenters[i]; - if (pattern.Count >= CENTER_QUORUM) + else { - confirmedCount++; - totalModuleSize += pattern.EstimatedModuleSize; + stateCount[++currentState]++; } + } // Counting white pixels + else + { + stateCount[currentState]++; + } } - if (confirmedCount < 3) + } + if (foundPatternCross(stateCount)) + { + bool confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (confirmed) { - return false; + iSkip = stateCount[0]; + if (hasSkipped) + { + // Found a third one + done = haveMultiplyConfirmedCenters(); + } } - // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" - // and that we need to keep looking. We detect this by asking if the estimated module sizes - // vary too much. We arbitrarily say that when the total deviation from average exceeds - // 5% of the total module size estimates, it's too much. - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float average = totalModuleSize / (float) max; - float totalDeviation = 0.0f; - for (int i = 0; i < max; i++) - { - FinderPattern pattern = (FinderPattern) possibleCenters[i]; - totalDeviation += System.Math.Abs(pattern.EstimatedModuleSize - average); - } - return totalDeviation <= 0.05f * totalModuleSize; + } } - - /// the 3 best {@link FinderPattern}s from our list of candidates. The "best" are - /// those that have been detected at least {@link #CENTER_QUORUM} times, and whose module - /// size differs from the average among those patterns the least - /// - /// ReaderException if 3 such finder patterns do not exist - private FinderPattern[] selectBestPatterns() + + FinderPattern[] patternInfo = selectBestPatterns(); + ResultPoint.orderBestPatterns(patternInfo); + + return new FinderPatternInfo(patternInfo); + } + + /// + /// Given a count of black/white/black/white/black pixels just seen and an end position, + /// figures the location of the center of this run. + /// + private static float centerFromEnd(int[] stateCount, int end) + { + return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; + } + + /// count of black/white/black/white/black pixels just read + /// true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios + /// used by finder patterns to be considered a match + protected internal static bool foundPatternCross(int[] stateCount) + { + int totalModuleSize = 0; + for (int i = 0; i < 5; i++) { - - int startSize = possibleCenters.Count; - if (startSize < 3) - { - // Couldn't find enough finder patterns - throw ReaderException.Instance; - } - - // Filter outlier possibilities whose module size is too different - if (startSize > 3) - { - // But we can only afford to do so if we have at least 4 possibilities to choose from - float totalModuleSize = 0.0f; - for (int i = 0; i < startSize; i++) - { - totalModuleSize += ((FinderPattern) possibleCenters[i]).EstimatedModuleSize; - } - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - float average = totalModuleSize / (float) startSize; - for (int i = 0; i < possibleCenters.Count && possibleCenters.Count > 3; i++) - { - FinderPattern pattern = (FinderPattern) possibleCenters[i]; - if (System.Math.Abs(pattern.EstimatedModuleSize - average) > 0.2f * average) - { - possibleCenters.RemoveAt(i); - i--; - } - } - } - - if (possibleCenters.Count > 3) - { - // Throw away all but those first size candidate points we found. - Collections.insertionSort(possibleCenters, new CenterComparator()); - SupportClass.SetCapacity(possibleCenters, 3); - } - - return new FinderPattern[]{(FinderPattern) possibleCenters[0], (FinderPattern) possibleCenters[1], (FinderPattern) possibleCenters[2]}; + int count = stateCount[i]; + if (count == 0) + { + return false; + } + totalModuleSize += count; } - - ///

Orders by {@link FinderPattern#getCount()}, descending.

- private class CenterComparator : Comparator + if (totalModuleSize < 7) { - public virtual int compare(System.Object center1, System.Object center2) - { - return ((FinderPattern) center2).Count - ((FinderPattern) center1).Count; - } + return false; } + int moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7; + int maxVariance = moduleSize / 2; + // Allow less than 50% variance from 1-1-3-1-1 proportions + return Math.Abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && Math.Abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && Math.Abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && Math.Abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && Math.Abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance; + } + + private int[] CrossCheckStateCount + { + get + { + crossCheckStateCount[0] = 0; + crossCheckStateCount[1] = 0; + crossCheckStateCount[2] = 0; + crossCheckStateCount[3] = 0; + crossCheckStateCount[4] = 0; + return crossCheckStateCount; + } + } + + /// + ///

After a horizontal scan finds a potential finder pattern, this method + /// "cross-checks" by scanning down vertically through the center of the possible + /// finder pattern to see if the same proportion is detected.

+ ///
+ /// row where a finder pattern was detected + /// center of the section that appears to cross a finder pattern + /// maximum reasonable number of modules that should be + /// observed in any reading state, based on the results of the horizontal scan + /// vertical center of finder pattern, or if not found + private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) + { + BitMatrix image = this.image; + + int maxI = image.Height; + int[] stateCount = CrossCheckStateCount; + + // Start counting up from center + int i = startI; + while (i >= 0 && image.get(centerJ, i)) + { + stateCount[2]++; + i--; + } + if (i < 0) + { + return float.NaN; + } + while (i >= 0 && !image.get(centerJ, i) && stateCount[1] <= maxCount) + { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) + { + return float.NaN; + } + while (i >= 0 && image.get(centerJ, i) && stateCount[0] <= maxCount) + { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) + { + return float.NaN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image.get(centerJ, i)) + { + stateCount[2]++; + i++; + } + if (i == maxI) + { + return float.NaN; + } + while (i < maxI && !image.get(centerJ, i) && stateCount[3] < maxCount) + { + stateCount[3]++; + i++; + } + if (i == maxI || stateCount[3] >= maxCount) + { + return float.NaN; + } + while (i < maxI && image.get(centerJ, i) && stateCount[4] < maxCount) + { + stateCount[4]++; + i++; + } + if (stateCount[4] >= maxCount) + { + return float.NaN; + } + + // If we found a finder-pattern-like section, but its size is more than 40% different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) + { + return float.NaN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : float.NaN; + } + + /// + ///

Like , and in fact is basically identical, + /// except it reads horizontally instead of vertically. This is used to cross-cross + /// check a vertical cross check and locate the real center of the alignment pattern.

+ ///
+ private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal) + { + BitMatrix image = this.image; + + int maxJ = image.Width; + int[] stateCount = CrossCheckStateCount; + + int j = startJ; + while (j >= 0 && image.get(j, centerI)) + { + stateCount[2]++; + j--; + } + if (j < 0) + { + return float.NaN; + } + while (j >= 0 && !image.get(j, centerI) && stateCount[1] <= maxCount) + { + stateCount[1]++; + j--; + } + if (j < 0 || stateCount[1] > maxCount) + { + return float.NaN; + } + while (j >= 0 && image.get(j, centerI) && stateCount[0] <= maxCount) + { + stateCount[0]++; + j--; + } + if (stateCount[0] > maxCount) + { + return float.NaN; + } + + j = startJ + 1; + while (j < maxJ && image.get(j, centerI)) + { + stateCount[2]++; + j++; + } + if (j == maxJ) + { + return float.NaN; + } + while (j < maxJ && !image.get(j, centerI) && stateCount[3] < maxCount) + { + stateCount[3]++; + j++; + } + if (j == maxJ || stateCount[3] >= maxCount) + { + return float.NaN; + } + while (j < maxJ && image.get(j, centerI) && stateCount[4] < maxCount) + { + stateCount[4]++; + j++; + } + if (stateCount[4] >= maxCount) + { + return float.NaN; + } + + // If we found a finder-pattern-like section, but its size is significantly different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) + { + return float.NaN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : float.NaN; + } + + /// + ///

This is called when a horizontal scan finds a possible alignment pattern. It will + /// cross check with a vertical scan, and if successful, will, ah, cross-cross-check + /// with another horizontal scan. This is needed primarily to locate the real horizontal + /// center of the pattern in cases of extreme skew.

+ /// + ///

If that succeeds the finder pattern location is added to a list that tracks + /// the number of times each location has been nearly-matched as a finder pattern. + /// Each additional find is more evidence that the location is in fact a finder + /// pattern center + ///

+ /// reading state module counts from horizontal scan + /// row where finder pattern may be found + /// end of possible finder pattern in row + /// true if a finder pattern candidate was found this time + protected internal bool handlePossibleCenter(int[] stateCount, int i, int j) + { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2], stateCountTotal); + if (!float.IsNaN(centerI)) + { + // Re-cross check + centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal); + if (!float.IsNaN(centerJ)) + { + float estimatedModuleSize = (float) stateCountTotal / 7.0f; + bool found = false; + for (int index = 0; index < possibleCenters.Count; index++) + { + FinderPattern center = possibleCenters[index]; + // Look for about the same center and module size: + if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) + { + possibleCenters[index] = center.combineEstimate(centerI, centerJ, estimatedModuleSize); + found = true; + break; + } + } + if (!found) + { + FinderPattern point = new FinderPattern(centerJ, centerI, estimatedModuleSize); + possibleCenters.Add(point); + if (resultPointCallback != null) + { + resultPointCallback.foundPossibleResultPoint(point); + } + } + return true; + } + } + return false; + } + + /// number of rows we could safely skip during scanning, based on the first + /// two finder patterns that have been located. In some cases their position will + /// allow us to infer that the third pattern must lie below a certain point farther + /// down in the image. + private int findRowSkip() + { + int max = possibleCenters.Count; + if (max <= 1) + { + return 0; + } + FinderPattern firstConfirmedCenter = null; + foreach (FinderPattern center in possibleCenters) + { + if (center.Count >= CENTER_QUORUM) + { + if (firstConfirmedCenter == null) + { + firstConfirmedCenter = center; + } + else + { + // We have two confirmed centers + // How far down can we skip before resuming looking for the next + // pattern? In the worst case, only the difference between the + // difference in the x / y coordinates of the two centers. + // This is the case where you find top left last. + hasSkipped = true; + return (int)(Math.Abs(firstConfirmedCenter.X - center.X) - Math.Abs(firstConfirmedCenter.Y - center.Y)) / 2; + } + } + } + return 0; + } + + /// true iff we have found at least 3 finder patterns that have been detected + /// at least times each, and, the estimated module size of the + /// candidates is "pretty similar" + private bool haveMultiplyConfirmedCenters() + { + int confirmedCount = 0; + float totalModuleSize = 0.0f; + int max = possibleCenters.Count; + foreach (FinderPattern pattern in possibleCenters) + { + if (pattern.Count >= CENTER_QUORUM) + { + confirmedCount++; + totalModuleSize += pattern.EstimatedModuleSize; + } + } + if (confirmedCount < 3) + { + return false; + } + // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" + // and that we need to keep looking. We detect this by asking if the estimated module sizes + // vary too much. We arbitrarily say that when the total deviation from average exceeds + // 5% of the total module size estimates, it's too much. + float average = totalModuleSize / (float) max; + float totalDeviation = 0.0f; + foreach (FinderPattern pattern in possibleCenters) + { + totalDeviation += Math.Abs(pattern.EstimatedModuleSize - average); + } + return totalDeviation <= 0.05f * totalModuleSize; + } + + /// the 3 best s from our list of candidates. The "best" are + /// those that have been detected at least times, and whose module + /// size differs from the average among those patterns the least + /// if 3 such finder patterns do not exist +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private FinderPattern[] selectBestPatterns() throws com.google.zxing.NotFoundException + private FinderPattern[] selectBestPatterns() + { + + int startSize = possibleCenters.Count; + if (startSize < 3) + { + // Couldn't find enough finder patterns + throw NotFoundException.NotFoundInstance; + } + + // Filter outlier possibilities whose module size is too different + if (startSize > 3) + { + // But we can only afford to do so if we have at least 4 possibilities to choose from + float totalModuleSize = 0.0f; + float square = 0.0f; + foreach (FinderPattern center in possibleCenters) + { + float size = center.EstimatedModuleSize; + totalModuleSize += size; + square += size * size; + } + float average = totalModuleSize / (float) startSize; + float stdDev = (float) Math.Sqrt(square / startSize - average * average); + + possibleCenters.Sort(new FurthestFromAverageComparator(average)); + + float limit = Math.Max(0.2f * average, stdDev); + + for (int i = 0; i < possibleCenters.Count && possibleCenters.Count > 3; i++) + { + FinderPattern pattern = possibleCenters[i]; + if (Math.Abs(pattern.EstimatedModuleSize - average) > limit) + { + possibleCenters.RemoveAt(i); + i--; + } + } + } + + if (possibleCenters.Count > 3) + { + // Throw away all but those first size candidate points we found. + + float totalModuleSize = 0.0f; + foreach (FinderPattern possibleCenter in possibleCenters) + { + totalModuleSize += possibleCenter.EstimatedModuleSize; + } + + float average = totalModuleSize / (float) possibleCenters.Count; + + possibleCenters.Sort(new CenterComparator(average)); + + //possibleCenters.subList(3, possibleCenters.Count).clear(); + possibleCenters.RemoveRange(3,possibleCenters.Count-3); + } + + return new FinderPattern[]{possibleCenters[0], possibleCenters[1], possibleCenters[2]}; + } + + /// + ///

Orders by furthest from average

+ ///
+ [Serializable] + private sealed class FurthestFromAverageComparator : IComparer + { + private readonly float average; + internal FurthestFromAverageComparator(float f) + { + average = f; + } + public int Compare(FinderPattern center1, FinderPattern center2) + { + float dA = Math.Abs(center2.EstimatedModuleSize - average); + float dB = Math.Abs(center1.EstimatedModuleSize - average); + return dA < dB ? - 1 : dA == dB ? 0 : 1; + } + } + + /// + ///

Orders by , descending.

+ ///
+ [Serializable] + private sealed class CenterComparator : IComparer + { + private readonly float average; + internal CenterComparator(float f) + { + average = f; + } + public int Compare(FinderPattern center1, FinderPattern center2) + { + if (center2.Count == center1.Count) + { + float dA = Math.Abs(center2.EstimatedModuleSize - average); + float dB = Math.Abs(center1.EstimatedModuleSize - average); + return dA < dB ? 1 : dA == dB ? 0 : -1; + } + else + { + return center2.Count - center1.Count; + } + } + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/detector/FinderPatternInfo.cs b/csharp/qrcode/detector/FinderPatternInfo.cs index eaa8dfa20..bdc8ecd17 100755 --- a/csharp/qrcode/detector/FinderPatternInfo.cs +++ b/csharp/qrcode/detector/FinderPatternInfo.cs @@ -1,69 +1,66 @@ /* -* 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. -*/ -using System; + * 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. + */ + namespace com.google.zxing.qrcode.detector { - - ///

Encapsulates information about finder patterns in an image, including the location of + + ///

+ ///

Encapsulates information about finder patterns in an image, including the location of /// the three finder patterns, and their estimated module size.

/// + /// @author Sean Owen ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// public sealed class FinderPatternInfo { - public FinderPattern BottomLeft - { - get - { - return bottomLeft; - } - - } - public FinderPattern TopLeft - { - get - { - return topLeft; - } - - } - public FinderPattern TopRight - { - get - { - return topRight; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'bottomLeft '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private FinderPattern bottomLeft; - //UPGRADE_NOTE: Final was removed from the declaration of 'topLeft '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private FinderPattern topLeft; - //UPGRADE_NOTE: Final was removed from the declaration of 'topRight '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private FinderPattern topRight; - - public FinderPatternInfo(FinderPattern[] patternCenters) - { - this.bottomLeft = patternCenters[0]; - this.topLeft = patternCenters[1]; - this.topRight = patternCenters[2]; - } + + private readonly FinderPattern bottomLeft; + private readonly FinderPattern topLeft; + private readonly FinderPattern topRight; + + public FinderPatternInfo(FinderPattern[] patternCenters) + { + this.bottomLeft = patternCenters[0]; + this.topLeft = patternCenters[1]; + this.topRight = patternCenters[2]; + } + + public FinderPattern BottomLeft + { + get + { + return bottomLeft; + } + } + + public FinderPattern TopLeft + { + get + { + return topLeft; + } + } + + public FinderPattern TopRight + { + get + { + return topRight; + } + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/encoder/BlockPair.cs b/csharp/qrcode/encoder/BlockPair.cs index 6f3a29824..587b8dae8 100755 --- a/csharp/qrcode/encoder/BlockPair.cs +++ b/csharp/qrcode/encoder/BlockPair.cs @@ -1,51 +1,50 @@ /* -* 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. -*/ -using System; -using ByteArray = com.google.zxing.common.ByteArray; + * 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. + */ + namespace com.google.zxing.qrcode.encoder { - - sealed class BlockPair + + internal sealed class BlockPair { - public ByteArray DataBytes - { - get - { - return dataBytes; - } - - } - public ByteArray ErrorCorrectionBytes - { - get - { - return errorCorrectionBytes; - } - - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'dataBytes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ByteArray dataBytes; - //UPGRADE_NOTE: Final was removed from the declaration of 'errorCorrectionBytes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private ByteArray errorCorrectionBytes; - - internal BlockPair(ByteArray data, ByteArray errorCorrection) - { - dataBytes = data; - errorCorrectionBytes = errorCorrection; - } + + private readonly sbyte[] dataBytes; + private readonly sbyte[] errorCorrectionBytes; + + internal BlockPair(sbyte[] data, sbyte[] errorCorrection) + { + dataBytes = data; + errorCorrectionBytes = errorCorrection; + } + + public sbyte[] DataBytes + { + get + { + return dataBytes; + } + } + + public sbyte[] ErrorCorrectionBytes + { + get + { + return errorCorrectionBytes; + } + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/encoder/Encoder.cs b/csharp/qrcode/encoder/Encoder.cs index 37568d00c..50b599641 100755 --- a/csharp/qrcode/encoder/Encoder.cs +++ b/csharp/qrcode/encoder/Encoder.cs @@ -1,642 +1,700 @@ -/* -* 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. -*/ using System; -using WriterException = com.google.zxing.WriterException; -using EncodeHintType = com.google.zxing.EncodeHintType; -using ByteArray = com.google.zxing.common.ByteArray; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -using CharacterSetECI = com.google.zxing.common.CharacterSetECI; -using GF256 = com.google.zxing.common.reedsolomon.GF256; -using ReedSolomonEncoder = com.google.zxing.common.reedsolomon.ReedSolomonEncoder; -using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -using Mode = com.google.zxing.qrcode.decoder.Mode; -using Version = com.google.zxing.qrcode.decoder.Version; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.encoder { - - /// satorux@google.com (Satoru Takabayashi) - creator - /// - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// + + using EncodeHintType = com.google.zxing.EncodeHintType; + using WriterException = com.google.zxing.WriterException; + using BitArray = com.google.zxing.common.BitArray; + using CharacterSetECI = com.google.zxing.common.CharacterSetECI; + using GenericGF = com.google.zxing.common.reedsolomon.GenericGF; + using ReedSolomonEncoder = com.google.zxing.common.reedsolomon.ReedSolomonEncoder; + using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + using Mode = com.google.zxing.qrcode.decoder.Mode; + using Version = com.google.zxing.qrcode.decoder.Version; + using com.google.zxing.common; + + + /// + /// @author satorux@google.com (Satoru Takabayashi) - creator + /// @author dswitkin@google.com (Daniel Switkin) - ported from C++ + /// public sealed class Encoder { - - // The original table is defined in the table 5 of JISX0510:2004 (p.19). - //UPGRADE_NOTE: Final was removed from the declaration of 'ALPHANUMERIC_TABLE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[] ALPHANUMERIC_TABLE = new int[]{- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, 36, - 1, - 1, - 1, 37, 38, - 1, - 1, - 1, - 1, 39, 40, - 1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, - 1, - 1, - 1, - 1, - 1, - 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 1, - 1, - 1, - 1, - 1}; - - internal const System.String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; - - private Encoder() + + // The original table is defined in the table 5 of JISX0510:2004 (p.19). + private static readonly int[] ALPHANUMERIC_TABLE = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1}; + + internal const string DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; + + private Encoder() + { + } + + // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. + // Basically it applies four rules and summate all penalties. + private static int calculateMaskPenalty(ByteMatrix matrix) + { + return MaskUtil.applyMaskPenaltyRule1(matrix) + MaskUtil.applyMaskPenaltyRule2(matrix) + MaskUtil.applyMaskPenaltyRule3(matrix) + MaskUtil.applyMaskPenaltyRule4(matrix); + } + + /// + /// Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen + /// internally by chooseMode(). On success, store the result in "qrCode". + /// + /// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for + /// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very + /// strong error correction for this purpose. + /// + /// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() + /// with which clients can specify the encoding mode. For now, we don't need the functionality. + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public static QRCode encode(String content, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel) throws com.google.zxing.WriterException + public static QRCode encode(string content, ErrorCorrectionLevel ecLevel) + { + return encode(content, ecLevel, null); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: public static QRCode encode(String content, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, java.util.Map hints) throws com.google.zxing.WriterException + public static QRCode encode(string content, ErrorCorrectionLevel ecLevel, IDictionary hints) + { + + // Determine what character encoding has been specified by the caller, if any + //string encoding = hints == null ? null : (string) hints[EncodeHintType.CHARACTER_SET]; + string encoding = null; + if (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)) + { + encoding = (string) hints[EncodeHintType.CHARACTER_SET]; + } + + if (encoding == null) { + encoding = DEFAULT_BYTE_MODE_ENCODING; } - - // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. - // Basically it applies four rules and summate all penalties. - private static int calculateMaskPenalty(ByteMatrix matrix) + + // Pick an encoding mode appropriate for the content. Note that this will not attempt to use + // multiple modes / segments even if that were more efficient. Twould be nice. + Mode mode = chooseMode(content, encoding); + + // This will store the header information, like mode and + // length, as well as "header" segments like an ECI segment. + BitArray headerBits = new BitArray(); + + // Append ECI segment if applicable + if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) { - int penalty = 0; - penalty += MaskUtil.applyMaskPenaltyRule1(matrix); - penalty += MaskUtil.applyMaskPenaltyRule2(matrix); - penalty += MaskUtil.applyMaskPenaltyRule3(matrix); - penalty += MaskUtil.applyMaskPenaltyRule4(matrix); - return penalty; + CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); + if (eci != null) + { + appendECI(eci, headerBits); + } } - - /// Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen - /// internally by chooseMode(). On success, store the result in "qrCode". - /// - /// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for - /// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very - /// strong error correction for this purpose. - /// - /// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() - /// with which clients can specify the encoding mode. For now, we don't need the functionality. - /// - public static void encode(System.String content, ErrorCorrectionLevel ecLevel, QRCode qrCode) + + // (With ECI in place,) Write the mode marker + appendModeInfo(mode, headerBits); + + // Collect data within the main segment, separately, to count its size if needed. Don't add it to + // main payload yet. + BitArray dataBits = new BitArray(); + appendBytes(content, mode, dataBits, encoding); + + // Hard part: need to know version to know how many bits length takes. But need to know how many + // bits it takes to know version. First we take a guess at version by assuming version will be + // the minimum, 1: + + int provisionalBitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(1)) + dataBits.Size; + Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); + + // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. + + int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(provisionalVersion) + dataBits.Size; + Version version = chooseVersion(bitsNeeded, ecLevel); + + BitArray headerAndDataBits = new BitArray(); + headerAndDataBits.appendBitArray(headerBits); + // Find "length" of main segment and write it + int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; + appendLengthInfo(numLetters, version, mode, headerAndDataBits); + // Put data together into the overall payload + headerAndDataBits.appendBitArray(dataBits); + + Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); + int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; + + // Terminate the bits properly. + terminateBits(numDataBytes, headerAndDataBits); + + // Interleave data bits with error correction code. + BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); + + QRCode qrCode = new QRCode(); + + qrCode.ECLevel = ecLevel; + qrCode.Mode = mode; + qrCode.Version = version; + + // Choose the mask pattern and set to "qrCode". + int dimension = version.DimensionForVersion; + ByteMatrix matrix = new ByteMatrix(dimension, dimension); + int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); + qrCode.MaskPattern = maskPattern; + + // Build the matrix and set it to "qrCode". + MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); + qrCode.Matrix = matrix; + + return qrCode; + } + + /// the code point of the table used in alphanumeric mode or + /// -1 if there is no corresponding code in the table. + internal static int getAlphanumericCode(int code) + { + if (code < ALPHANUMERIC_TABLE.Length) { - encode(content, ecLevel, null, qrCode); + return ALPHANUMERIC_TABLE[code]; } - - public static void encode(System.String content, ErrorCorrectionLevel ecLevel, System.Collections.Hashtable hints, QRCode qrCode) + return -1; + } + + public static Mode chooseMode(string content) + { + return chooseMode(content, null); + } + + /// + /// Choose the best mode by examining the content. Note that 'encoding' is used as a hint; + /// if it is Shift_JIS, and the input is only double-byte Kanji, then we return . + /// + private static Mode chooseMode(string content, string encoding) + { + if ("Shift_JIS".Equals(encoding)) { - - System.String encoding = hints == null?null:(System.String) hints[EncodeHintType.CHARACTER_SET]; - if (encoding == null) - { - encoding = DEFAULT_BYTE_MODE_ENCODING; - } - - // Step 1: Choose the mode (encoding). - Mode mode = chooseMode(content, encoding); - - // Step 2: Append "bytes" into "dataBits" in appropriate encoding. - BitVector dataBits = new BitVector(); - appendBytes(content, mode, dataBits, encoding); - // Step 3: Initialize QR code that can contain "dataBits". - int numInputBytes = dataBits.sizeInBytes(); - initQRCode(numInputBytes, ecLevel, mode, qrCode); - - // Step 4: Build another bit vector that contains header and data. - BitVector headerAndDataBits = new BitVector(); - - // Step 4.5: Append ECI message if applicable - if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) - { - CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); - if (eci != null) - { - appendECI(eci, headerAndDataBits); - } - } - - appendModeInfo(mode, headerAndDataBits); - - int numLetters = mode.Equals(Mode.BYTE)?dataBits.sizeInBytes():content.Length; - appendLengthInfo(numLetters, qrCode.Version, mode, headerAndDataBits); - headerAndDataBits.appendBitVector(dataBits); - - // Step 5: Terminate the bits properly. - terminateBits(qrCode.NumDataBytes, headerAndDataBits); - - // Step 6: Interleave data bits with error correction code. - BitVector finalBits = new BitVector(); - interleaveWithECBytes(headerAndDataBits, qrCode.NumTotalBytes, qrCode.NumDataBytes, qrCode.NumRSBlocks, finalBits); - - // Step 7: Choose the mask pattern and set to "qrCode". - ByteMatrix matrix = new ByteMatrix(qrCode.MatrixWidth, qrCode.MatrixWidth); - qrCode.MaskPattern = chooseMaskPattern(finalBits, qrCode.ECLevel, qrCode.Version, matrix); - - // Step 8. Build the matrix and set it to "qrCode". - MatrixUtil.buildMatrix(finalBits, qrCode.ECLevel, qrCode.Version, qrCode.MaskPattern, matrix); - qrCode.Matrix = matrix; - // Step 9. Make sure we have a valid QR Code. - if (!qrCode.Valid) - { - throw new WriterException("Invalid QR code: " + qrCode.ToString()); - } + // Choose Kanji mode if all input are double-byte characters + return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; } - - /// the code point of the table used in alphanumeric mode or - /// -1 if there is no corresponding code in the table. - /// - internal static int getAlphanumericCode(int code) + bool hasNumeric = false; + bool hasAlphanumeric = false; + for (int i = 0; i < content.Length; ++i) { - if (code < ALPHANUMERIC_TABLE.Length) - { - return ALPHANUMERIC_TABLE[code]; - } - return - 1; - } - - public static Mode chooseMode(System.String content) - { - return chooseMode(content, null); - } - - /// Choose the best mode by examining the content. Note that 'encoding' is used as a hint; - /// if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. - /// - public static Mode chooseMode(System.String content, System.String encoding) - { - if ("Shift_JIS".Equals(encoding)) - { - // Choose Kanji mode if all input are double-byte characters - return isOnlyDoubleByteKanji(content)?Mode.KANJI:Mode.BYTE; - } - bool hasNumeric = false; - bool hasAlphanumeric = false; - for (int i = 0; i < content.Length; ++i) - { - char c = content[i]; - if (c >= '0' && c <= '9') - { - hasNumeric = true; - } - else if (getAlphanumericCode(c) != - 1) - { - hasAlphanumeric = true; - } - else - { - return Mode.BYTE; - } - } - if (hasAlphanumeric) - { - return Mode.ALPHANUMERIC; - } - else if (hasNumeric) - { - return Mode.NUMERIC; - } + char c = content[i]; + if (c >= '0' && c <= '9') + { + hasNumeric = true; + } + else if (getAlphanumericCode(c) != -1) + { + hasAlphanumeric = true; + } + else + { return Mode.BYTE; + } } - - private static bool isOnlyDoubleByteKanji(System.String content) + if (hasAlphanumeric) { - sbyte[] bytes; - try - { - //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'" - bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(content)); - } - catch (System.IO.IOException) - { - return false; - } - int length = bytes.Length; - if (length % 2 != 0) - { - return false; - } - for (int i = 0; i < length; i += 2) - { - int byte1 = bytes[i] & 0xFF; - if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) - { - return false; - } - } - return true; + return Mode.ALPHANUMERIC; } - - private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version, ByteMatrix matrix) + if (hasNumeric) { - - int minPenalty = System.Int32.MaxValue; // Lower penalty is better. - int bestMaskPattern = - 1; - // We try all mask patterns to choose the best one. - for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) - { - MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); - int penalty = calculateMaskPenalty(matrix); - if (penalty < minPenalty) - { - minPenalty = penalty; - bestMaskPattern = maskPattern; - } - } - return bestMaskPattern; + return Mode.NUMERIC; } - - /// Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, - /// modify "qrCode". - /// - private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, QRCode qrCode) + return Mode.BYTE; + } + + private static bool isOnlyDoubleByteKanji(string content) + { + sbyte[] bytes; + try { - qrCode.ECLevel = ecLevel; - qrCode.Mode = mode; - - // In the following comments, we use numbers of Version 7-H. - for (int versionNum = 1; versionNum <= 40; versionNum++) - { - Version version = Version.getVersionForNumber(versionNum); - // numBytes = 196 - int numBytes = version.TotalCodewords; - // getNumECBytes = 130 - Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); - int numEcBytes = ecBlocks.TotalECCodewords; - // getNumRSBlocks = 5 - int numRSBlocks = ecBlocks.NumBlocks; - // getNumDataBytes = 196 - 130 = 66 - int numDataBytes = numBytes - numEcBytes; - // We want to choose the smallest version which can contain data of "numInputBytes" + some - // extra bits for the header (mode info and length info). The header can be three bytes - // (precisely 4 + 16 bits) at most. Hence we do +3 here. - if (numDataBytes >= numInputBytes + 3) - { - // Yay, we found the proper rs block info! - qrCode.Version = versionNum; - qrCode.NumTotalBytes = numBytes; - qrCode.NumDataBytes = numDataBytes; - qrCode.NumRSBlocks = numRSBlocks; - // getNumECBytes = 196 - 66 = 130 - qrCode.NumECBytes = numEcBytes; - // matrix width = 21 + 6 * 4 = 45 - qrCode.MatrixWidth = version.DimensionForVersion; - return ; - } - } - throw new WriterException("Cannot find proper rs block info (input data too big?)"); + //bytes = content.getBytes("Shift_JIS"); + Encoding en = Encoding.GetEncoding("Shift_JIS"); + bytes = en.GetBytes(content).ToSBytes(); } - - /// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). - internal static void terminateBits(int numDataBytes, BitVector bits) + catch (System.IO.IOException) { - int capacity = numDataBytes << 3; - if (bits.size() > capacity) - { - throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity); - } - // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. - // TODO: srowen says we can remove this for loop, since the 4 terminator bits are optional if - // the last byte has less than 4 bits left. So it amounts to padding the last byte with zeroes - // either way. - for (int i = 0; i < 4 && bits.size() < capacity; ++i) - { - bits.appendBit(0); - } - int numBitsInLastByte = bits.size() % 8; - // If the last byte isn't 8-bit aligned, we'll add padding bits. - if (numBitsInLastByte > 0) - { - int numPaddingBits = 8 - numBitsInLastByte; - for (int i = 0; i < numPaddingBits; ++i) - { - bits.appendBit(0); - } - } - // Should be 8-bit aligned here. - if (bits.size() % 8 != 0) - { - throw new WriterException("Number of bits is not a multiple of 8"); - } - // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). - int numPaddingBytes = numDataBytes - bits.sizeInBytes(); - for (int i = 0; i < numPaddingBytes; ++i) - { - if (i % 2 == 0) - { - bits.appendBits(0xec, 8); - } - else - { - bits.appendBits(0x11, 8); - } - } - if (bits.size() != capacity) - { - throw new WriterException("Bits size does not equal capacity"); - } + return false; } - - /// Get number of data bytes and number of error correction bytes for block id "blockID". Store - /// the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of - /// JISX0510:2004 (p.30) - /// - internal static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int[] numDataBytesInBlock, int[] numECBytesInBlock) + int length = bytes.Length; + if (length % 2 != 0) { - if (blockID >= numRSBlocks) - { - throw new WriterException("Block ID too large"); - } - // numRsBlocksInGroup2 = 196 % 5 = 1 - int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; - // numRsBlocksInGroup1 = 5 - 1 = 4 - int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; - // numTotalBytesInGroup1 = 196 / 5 = 39 - int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; - // numTotalBytesInGroup2 = 39 + 1 = 40 - int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; - // numDataBytesInGroup1 = 66 / 5 = 13 - int numDataBytesInGroup1 = numDataBytes / numRSBlocks; - // numDataBytesInGroup2 = 13 + 1 = 14 - int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; - // numEcBytesInGroup1 = 39 - 13 = 26 - int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; - // numEcBytesInGroup2 = 40 - 14 = 26 - int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; - // Sanity checks. - // 26 = 26 - if (numEcBytesInGroup1 != numEcBytesInGroup2) - { - throw new WriterException("EC bytes mismatch"); - } - // 5 = 4 + 1. - if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) - { - throw new WriterException("RS blocks mismatch"); - } - // 196 = (13 + 26) * 4 + (14 + 26) * 1 - if (numTotalBytes != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2)) - { - throw new WriterException("Total bytes mismatch"); - } - - if (blockID < numRsBlocksInGroup1) - { - numDataBytesInBlock[0] = numDataBytesInGroup1; - numECBytesInBlock[0] = numEcBytesInGroup1; - } - else - { - numDataBytesInBlock[0] = numDataBytesInGroup2; - numECBytesInBlock[0] = numEcBytesInGroup2; - } + return false; } - - /// Interleave "bits" with corresponding error correction bytes. On success, store the result in - /// "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. - /// - internal static void interleaveWithECBytes(BitVector bits, int numTotalBytes, int numDataBytes, int numRSBlocks, BitVector result) + for (int i = 0; i < length; i += 2) { - - // "bits" must have "getNumDataBytes" bytes of data. - if (bits.sizeInBytes() != numDataBytes) - { - throw new WriterException("Number of bits and data bytes does not match"); - } - - // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll - // store the divided data bytes blocks and error correction bytes blocks into "blocks". - int dataBytesOffset = 0; - int maxNumDataBytes = 0; - int maxNumEcBytes = 0; - - // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. - System.Collections.ArrayList blocks = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(numRSBlocks)); - - for (int i = 0; i < numRSBlocks; ++i) - { - int[] numDataBytesInBlock = new int[1]; - int[] numEcBytesInBlock = new int[1]; - getNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock); - - ByteArray dataBytes = new ByteArray(); - dataBytes.set_Renamed(bits.Array, dataBytesOffset, numDataBytesInBlock[0]); - ByteArray ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); - blocks.Add(new BlockPair(dataBytes, ecBytes)); - - maxNumDataBytes = System.Math.Max(maxNumDataBytes, dataBytes.size()); - maxNumEcBytes = System.Math.Max(maxNumEcBytes, ecBytes.size()); - dataBytesOffset += numDataBytesInBlock[0]; - } - if (numDataBytes != dataBytesOffset) - { - throw new WriterException("Data bytes does not match offset"); - } - - // First, place data blocks. - for (int i = 0; i < maxNumDataBytes; ++i) - { - for (int j = 0; j < blocks.Count; ++j) - { - ByteArray dataBytes = ((BlockPair) blocks[j]).DataBytes; - if (i < dataBytes.size()) - { - result.appendBits(dataBytes.at(i), 8); - } - } - } - // Then, place error correction blocks. - for (int i = 0; i < maxNumEcBytes; ++i) - { - for (int j = 0; j < blocks.Count; ++j) - { - ByteArray ecBytes = ((BlockPair) blocks[j]).ErrorCorrectionBytes; - if (i < ecBytes.size()) - { - result.appendBits(ecBytes.at(i), 8); - } - } - } - if (numTotalBytes != result.sizeInBytes()) - { - // Should be same. - throw new WriterException("Interleaving error: " + numTotalBytes + " and " + result.sizeInBytes() + " differ."); - } + int byte1 = bytes[i] & 0xFF; + if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) + { + return false; + } } - - internal static ByteArray generateECBytes(ByteArray dataBytes, int numEcBytesInBlock) + return true; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static int chooseMaskPattern(com.google.zxing.common.BitArray bits, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, com.google.zxing.qrcode.decoder.Version version, ByteMatrix matrix) throws com.google.zxing.WriterException + private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, Version version, ByteMatrix matrix) + { + + int minPenalty = int.MaxValue; // Lower penalty is better. + int bestMaskPattern = -1; + // We try all mask patterns to choose the best one. + for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { - int numDataBytes = dataBytes.size(); - int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; - for (int i = 0; i < numDataBytes; i++) - { - toEncode[i] = dataBytes.at(i); - } - new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, numEcBytesInBlock); - - ByteArray ecBytes = new ByteArray(numEcBytesInBlock); - for (int i = 0; i < numEcBytesInBlock; i++) - { - ecBytes.set_Renamed(i, toEncode[numDataBytes + i]); - } - return ecBytes; + MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); + int penalty = calculateMaskPenalty(matrix); + if (penalty < minPenalty) + { + minPenalty = penalty; + bestMaskPattern = maskPattern; + } } - - /// Append mode info. On success, store the result in "bits". - internal static void appendModeInfo(Mode mode, BitVector bits) + return bestMaskPattern; + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static com.google.zxing.qrcode.decoder.Version chooseVersion(int numInputBits, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel) throws com.google.zxing.WriterException + private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) + { + // In the following comments, we use numbers of Version 7-H. + for (int versionNum = 1; versionNum <= 40; versionNum++) { - bits.appendBits(mode.Bits, 4); + Version version = Version.getVersionForNumber(versionNum); + // numBytes = 196 + int numBytes = version.TotalCodewords; + // getNumECBytes = 130 + Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); + int numEcBytes = ecBlocks.TotalECCodewords; + // getNumDataBytes = 196 - 130 = 66 + int numDataBytes = numBytes - numEcBytes; + int totalInputBytes = (numInputBits + 7) / 8; + if (numDataBytes >= totalInputBytes) + { + return version; + } } - - - /// Append length info. On success, store the result in "bits". - internal static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector bits) + throw new WriterException("Data too big"); + } + + /// + /// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void terminateBits(int numDataBytes, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void terminateBits(int numDataBytes, BitArray bits) + { + int capacity = numDataBytes << 3; + if (bits.Size > capacity) { - int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version)); - if (numLetters > ((1 << numBits) - 1)) - { - throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1)); - } - bits.appendBits(numLetters, numBits); + throw new WriterException("data bits cannot fit in the QR Code" + bits.Size + " > " + capacity); } - - /// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". - internal static void appendBytes(System.String content, Mode mode, BitVector bits, System.String encoding) + for (int i = 0; i < 4 && bits.Size < capacity; ++i) { - if (mode.Equals(Mode.NUMERIC)) - { - appendNumericBytes(content, bits); - } - else if (mode.Equals(Mode.ALPHANUMERIC)) - { - appendAlphanumericBytes(content, bits); - } - else if (mode.Equals(Mode.BYTE)) - { - append8BitBytes(content, bits, encoding); - } - else if (mode.Equals(Mode.KANJI)) - { - appendKanjiBytes(content, bits); - } - else - { - throw new WriterException("Invalid mode: " + mode); - } + bits.appendBit(false); } - - internal static void appendNumericBytes(System.String content, BitVector bits) + // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. + // If the last byte isn't 8-bit aligned, we'll add padding bits. + int numBitsInLastByte = bits.Size & 0x07; + if (numBitsInLastByte > 0) { - int length = content.Length; - int i = 0; - while (i < length) - { - int num1 = content[i] - '0'; - if (i + 2 < length) - { - // Encode three numeric letters in ten bits. - int num2 = content[i + 1] - '0'; - int num3 = content[i + 2] - '0'; - bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); - i += 3; - } - else if (i + 1 < length) - { - // Encode two numeric letters in seven bits. - int num2 = content[i + 1] - '0'; - bits.appendBits(num1 * 10 + num2, 7); - i += 2; - } - else - { - // Encode one numeric letter in four bits. - bits.appendBits(num1, 4); - i++; - } - } + for (int i = numBitsInLastByte; i < 8; i++) + { + bits.appendBit(false); + } } - - internal static void appendAlphanumericBytes(System.String content, BitVector bits) + // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). + int numPaddingBytes = numDataBytes - bits.SizeInBytes; + for (int i = 0; i < numPaddingBytes; ++i) { - int length = content.Length; - int i = 0; - while (i < length) - { - int code1 = getAlphanumericCode(content[i]); - if (code1 == - 1) - { - throw new WriterException(); - } - if (i + 1 < length) - { - int code2 = getAlphanumericCode(content[i + 1]); - if (code2 == - 1) - { - throw new WriterException(); - } - // Encode two alphanumeric letters in 11 bits. - bits.appendBits(code1 * 45 + code2, 11); - i += 2; - } - else - { - // Encode one alphanumeric letter in six bits. - bits.appendBits(code1, 6); - i++; - } - } + bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); } - - internal static void append8BitBytes(System.String content, BitVector bits, System.String encoding) + if (bits.Size != capacity) { - sbyte[] bytes; - try - { - //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'" - bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding(encoding).GetBytes(content)); - } - catch (System.IO.IOException uee) - { - //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" - throw new WriterException(uee.ToString()); - } - for (int i = 0; i < bytes.Length; ++i) - { - bits.appendBits(bytes[i], 8); - } + throw new WriterException("Bits size does not equal capacity"); } - - internal static void appendKanjiBytes(System.String content, BitVector bits) + } + + /// + /// Get number of data bytes and number of error correction bytes for block id "blockID". Store + /// the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of + /// JISX0510:2004 (p.30) + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int[] numDataBytesInBlock, int[] numECBytesInBlock) throws com.google.zxing.WriterException + internal static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int[] numDataBytesInBlock, int[] numECBytesInBlock) + { + if (blockID >= numRSBlocks) { - sbyte[] bytes; - try - { - //UPGRADE_TODO: Method 'java.lang.String.getBytes' was converted to 'System.Text.Encoding.GetEncoding(string).GetBytes(string)' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangStringgetBytes_javalangString'" - bytes = SupportClass.ToSByteArray(System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(content)); - } - catch (System.IO.IOException uee) - { - //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" - throw new WriterException(uee.ToString()); - } - int length = bytes.Length; - for (int i = 0; i < length; i += 2) - { - int byte1 = bytes[i] & 0xFF; - int byte2 = bytes[i + 1] & 0xFF; - int code = (byte1 << 8) | byte2; - int subtracted = - 1; - if (code >= 0x8140 && code <= 0x9ffc) - { - subtracted = code - 0x8140; - } - else if (code >= 0xe040 && code <= 0xebbf) - { - subtracted = code - 0xc140; - } - if (subtracted == - 1) - { - throw new WriterException("Invalid byte sequence"); - } - int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); - bits.appendBits(encoded, 13); - } + throw new WriterException("Block ID too large"); } - - private static void appendECI(CharacterSetECI eci, BitVector bits) + // numRsBlocksInGroup2 = 196 % 5 = 1 + int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; + // numRsBlocksInGroup1 = 5 - 1 = 4 + int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; + // numTotalBytesInGroup1 = 196 / 5 = 39 + int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; + // numTotalBytesInGroup2 = 39 + 1 = 40 + int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; + // numDataBytesInGroup1 = 66 / 5 = 13 + int numDataBytesInGroup1 = numDataBytes / numRSBlocks; + // numDataBytesInGroup2 = 13 + 1 = 14 + int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; + // numEcBytesInGroup1 = 39 - 13 = 26 + int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; + // numEcBytesInGroup2 = 40 - 14 = 26 + int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; + // Sanity checks. + // 26 = 26 + if (numEcBytesInGroup1 != numEcBytesInGroup2) { - bits.appendBits(Mode.ECI.Bits, 4); - // This is correct for values up to 127, which is all we need now. - bits.appendBits(eci.Value, 8); + throw new WriterException("EC bytes mismatch"); } + // 5 = 4 + 1. + if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) + { + throw new WriterException("RS blocks mismatch"); + } + // 196 = (13 + 26) * 4 + (14 + 26) * 1 + if (numTotalBytes != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2)) + { + throw new WriterException("Total bytes mismatch"); + } + + if (blockID < numRsBlocksInGroup1) + { + numDataBytesInBlock[0] = numDataBytesInGroup1; + numECBytesInBlock[0] = numEcBytesInGroup1; + } + else + { + numDataBytesInBlock[0] = numDataBytesInGroup2; + numECBytesInBlock[0] = numEcBytesInGroup2; + } + } + + /// + /// Interleave "bits" with corresponding error correction bytes. On success, store the result in + /// "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static com.google.zxing.common.BitArray interleaveWithECBytes(com.google.zxing.common.BitArray bits, int numTotalBytes, int numDataBytes, int numRSBlocks) throws com.google.zxing.WriterException + internal static BitArray interleaveWithECBytes(BitArray bits, int numTotalBytes, int numDataBytes, int numRSBlocks) + { + + // "bits" must have "getNumDataBytes" bytes of data. + if (bits.SizeInBytes != numDataBytes) + { + throw new WriterException("Number of bits and data bytes does not match"); + } + + // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll + // store the divided data bytes blocks and error correction bytes blocks into "blocks". + int dataBytesOffset = 0; + int maxNumDataBytes = 0; + int maxNumEcBytes = 0; + + // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. + ICollection blocks = new List(numRSBlocks); + + for (int i = 0; i < numRSBlocks; ++i) + { + int[] numDataBytesInBlock = new int[1]; + int[] numEcBytesInBlock = new int[1]; + getNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock); + + int size = numDataBytesInBlock[0]; + sbyte[] dataBytes = new sbyte[size]; + bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size); + sbyte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); + blocks.Add(new BlockPair(dataBytes, ecBytes)); + + maxNumDataBytes = Math.Max(maxNumDataBytes, size); + maxNumEcBytes = Math.Max(maxNumEcBytes, ecBytes.Length); + dataBytesOffset += numDataBytesInBlock[0]; + } + if (numDataBytes != dataBytesOffset) + { + throw new WriterException("Data bytes does not match offset"); + } + + BitArray result = new BitArray(); + + // First, place data blocks. + for (int i = 0; i < maxNumDataBytes; ++i) + { + foreach (BlockPair block in blocks) + { + sbyte[] dataBytes = block.DataBytes; + if (i < dataBytes.Length) + { + result.appendBits(dataBytes[i], 8); + } + } + } + // Then, place error correction blocks. + for (int i = 0; i < maxNumEcBytes; ++i) + { + foreach (BlockPair block in blocks) + { + sbyte[] ecBytes = block.ErrorCorrectionBytes; + if (i < ecBytes.Length) + { + result.appendBits(ecBytes[i], 8); + } + } + } + if (numTotalBytes != result.SizeInBytes) // Should be same. + { + throw new WriterException("Interleaving error: " + numTotalBytes + " and " + result.SizeInBytes + " differ."); + } + + return result; + } + + internal static sbyte[] generateECBytes(sbyte[] dataBytes, int numEcBytesInBlock) + { + int numDataBytes = dataBytes.Length; + int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; + for (int i = 0; i < numDataBytes; i++) + { + toEncode[i] = dataBytes[i] & 0xFF; + } + (new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256)).encode(toEncode, numEcBytesInBlock); + + sbyte[] ecBytes = new sbyte[numEcBytesInBlock]; + for (int i = 0; i < numEcBytesInBlock; i++) + { + ecBytes[i] = (sbyte) toEncode[numDataBytes + i]; + } + return ecBytes; + } + + /// + /// Append mode info. On success, store the result in "bits". + /// + internal static void appendModeInfo(Mode mode, BitArray bits) + { + bits.appendBits(mode.Bits, 4); + } + + + /// + /// Append length info. On success, store the result in "bits". + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void appendLengthInfo(int numLetters, com.google.zxing.qrcode.decoder.Version version, com.google.zxing.qrcode.decoder.Mode mode, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void appendLengthInfo(int numLetters, Version version, Mode mode, BitArray bits) + { + int numBits = mode.getCharacterCountBits(version); + if (numLetters >= (1 << numBits)) + { + throw new WriterException(numLetters + " is bigger than " + ((1 << numBits) - 1)); + } + bits.appendBits(numLetters, numBits); + } + + /// + /// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". + /// +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void appendBytes(String content, com.google.zxing.qrcode.decoder.Mode mode, com.google.zxing.common.BitArray bits, String encoding) throws com.google.zxing.WriterException + internal static void appendBytes(string content, Mode mode, BitArray bits, string encoding) + { + if (mode == Mode.NUMERIC) + { + appendNumericBytes(content, bits); + + } + else if (mode == Mode.ALPHANUMERIC) + { +appendAlphanumericBytes(content, bits); + } + else if (mode == Mode.BYTE) + { +append8BitBytes(content, bits, encoding); + } + else if (mode == Mode.KANJI) + { + appendKanjiBytes(content, bits); + } else + { + throw new WriterException("Invalid mode: " + mode); + } + + //switch (mode) + //{ + // case NUMERIC: + // appendNumericBytes(content, bits); + // break; + // case ALPHANUMERIC: + // appendAlphanumericBytes(content, bits); + // break; + // case BYTE: + // append8BitBytes(content, bits, encoding); + // break; + // case KANJI: + // appendKanjiBytes(content, bits); + // break; + // default: + // throw new WriterException("Invalid mode: " + mode); + //} + } + + internal static void appendNumericBytes(string content, BitArray bits) + { + int length = content.Length; + int i = 0; + while (i < length) + { + int num1 = content[i] - '0'; + if (i + 2 < length) + { + // Encode three numeric letters in ten bits. + int num2 = content[i + 1] - '0'; + int num3 = content[i + 2] - '0'; + bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); + i += 3; + } + else if (i + 1 < length) + { + // Encode two numeric letters in seven bits. + int num2 = content[i + 1] - '0'; + bits.appendBits(num1 * 10 + num2, 7); + i += 2; + } + else + { + // Encode one numeric letter in four bits. + bits.appendBits(num1, 4); + i++; + } + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void appendAlphanumericBytes(CharSequence content, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void appendAlphanumericBytes(string content, BitArray bits) + { + int length = content.Length; + int i = 0; + while (i < length) + { + int code1 = getAlphanumericCode(content[i]); + if (code1 == -1) + { + throw new WriterException(); + } + if (i + 1 < length) + { + int code2 = getAlphanumericCode(content[i + 1]); + if (code2 == -1) + { + throw new WriterException(); + } + // Encode two alphanumeric letters in 11 bits. + bits.appendBits(code1 * 45 + code2, 11); + i += 2; + } + else + { + // Encode one alphanumeric letter in six bits. + bits.appendBits(code1, 6); + i++; + } + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void append8BitBytes(String content, com.google.zxing.common.BitArray bits, String encoding) throws com.google.zxing.WriterException + internal static void append8BitBytes(string content, BitArray bits, string encoding) + { + sbyte[] bytes; + try + { + //bytes = content.getBytes(encoding); + Encoding en = Encoding.GetEncoding(encoding); + bytes = en.GetBytes(content).ToSBytes(); + + } + catch (System.IO.IOException uee) + { + throw new WriterException(uee); + } + foreach (sbyte b in bytes) + { + bits.appendBits(b, 8); + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void appendKanjiBytes(String content, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void appendKanjiBytes(string content, BitArray bits) + { + sbyte[] bytes; + try + { + + //bytes = content.getBytes("Shift_JIS"); + Encoding en = Encoding.GetEncoding("Shift_JIS"); + bytes = en.GetBytes(content).ToSBytes(); + + } + catch (System.IO.IOException uee) + { + throw new WriterException(uee); + } + int length = bytes.Length; + for (int i = 0; i < length; i += 2) + { + int byte1 = bytes[i] & 0xFF; + int byte2 = bytes[i + 1] & 0xFF; + int code = (byte1 << 8) | byte2; + int subtracted = -1; + if (code >= 0x8140 && code <= 0x9ffc) + { + subtracted = code - 0x8140; + } + else if (code >= 0xe040 && code <= 0xebbf) + { + subtracted = code - 0xc140; + } + if (subtracted == -1) + { + throw new WriterException("Invalid byte sequence"); + } + int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); + bits.appendBits(encoded, 13); + } + } + + private static void appendECI(CharacterSetECI eci, BitArray bits) + { + bits.appendBits(Mode.ECI.Bits, 4); + // This is correct for values up to 127, which is all we need now. + bits.appendBits(eci.Value, 8); + } + } -} + +} \ No newline at end of file diff --git a/csharp/qrcode/encoder/MaskUtil.cs b/csharp/qrcode/encoder/MaskUtil.cs index e5611717d..22091d5a3 100755 --- a/csharp/qrcode/encoder/MaskUtil.cs +++ b/csharp/qrcode/encoder/MaskUtil.cs @@ -1,226 +1,215 @@ -/* -* 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. -*/ using System; -using ByteMatrix = com.google.zxing.common.ByteMatrix; + +/* + * 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. + */ + namespace com.google.zxing.qrcode.encoder { - - /// satorux@google.com (Satoru Takabayashi) - creator - /// - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class MaskUtil + + /// + /// @author Satoru Takabayashi + /// @author Daniel Switkin + /// @author Sean Owen + /// + internal sealed class MaskUtil { - - private MaskUtil() + + // Penalty weights from section 6.8.2.1 + private const int N1 = 3; + private const int N2 = 3; + private const int N3 = 40; + private const int N4 = 10; + + private MaskUtil() + { + // do nothing + } + + /// + /// Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + /// give penalty to them. Example: 00000 or 11111. + /// + internal static int applyMaskPenaltyRule1(ByteMatrix matrix) + { + return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); + } + + /// + /// Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + /// penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a + /// penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + /// + internal static int applyMaskPenaltyRule2(ByteMatrix matrix) + { + int penalty = 0; + sbyte[][] array = matrix.Array; + int width = matrix.Width; + int height = matrix.Height; + for (int y = 0; y < height - 1; y++) { - // do nothing - } - - // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and - // give penalty to them. Example: 00000 or 11111. - public static int applyMaskPenaltyRule1(ByteMatrix matrix) - { - return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); - } - - // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give - // penalty to them. - public static int applyMaskPenaltyRule2(ByteMatrix matrix) - { - int penalty = 0; - sbyte[][] array = matrix.Array; - int width = matrix.Width; - int height = matrix.Height; - for (int y = 0; y < height - 1; ++y) + for (int x = 0; x < width - 1; x++) + { + int value = array[y][x]; + if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { - for (int x = 0; x < width - 1; ++x) - { - int value_Renamed = array[y][x]; - if (value_Renamed == array[y][x + 1] && value_Renamed == array[y + 1][x] && value_Renamed == array[y + 1][x + 1]) - { - penalty += 3; - } - } + penalty++; } - return penalty; + } } - - // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or - // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give - // penalties twice (i.e. 40 * 2). - public static int applyMaskPenaltyRule3(ByteMatrix matrix) + return N2 * penalty; + } + + /// + /// Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or + /// 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give + /// penalties twice (i.e. 40 * 2). + /// + internal static int applyMaskPenaltyRule3(ByteMatrix matrix) + { + int penalty = 0; + sbyte[][] array = matrix.Array; + int width = matrix.Width; + int height = matrix.Height; + for (int y = 0; y < height; y++) { - int penalty = 0; - sbyte[][] array = matrix.Array; - int width = matrix.Width; - int height = matrix.Height; - for (int y = 0; y < height; ++y) + for (int x = 0; x < width; x++) + { + // Tried to simplify following conditions but failed. + if (x + 6 < width && array[y][x] == 1 && array[y][x + 1] == 0 && array[y][x + 2] == 1 && array[y][x + 3] == 1 && array[y][x + 4] == 1 && array[y][x + 5] == 0 && array[y][x + 6] == 1 && ((x + 10 < width && array[y][x + 7] == 0 && array[y][x + 8] == 0 && array[y][x + 9] == 0 && array[y][x + 10] == 0) || (x - 4 >= 0 && array[y][x - 1] == 0 && array[y][x - 2] == 0 && array[y][x - 3] == 0 && array[y][x - 4] == 0))) { - for (int x = 0; x < width; ++x) - { - // Tried to simplify following conditions but failed. - if (x + 6 < width && array[y][x] == 1 && array[y][x + 1] == 0 && array[y][x + 2] == 1 && array[y][x + 3] == 1 && array[y][x + 4] == 1 && array[y][x + 5] == 0 && array[y][x + 6] == 1 && ((x + 10 < width && array[y][x + 7] == 0 && array[y][x + 8] == 0 && array[y][x + 9] == 0 && array[y][x + 10] == 0) || (x - 4 >= 0 && array[y][x - 1] == 0 && array[y][x - 2] == 0 && array[y][x - 3] == 0 && array[y][x - 4] == 0))) - { - penalty += 40; - } - if (y + 6 < height && array[y][x] == 1 && array[y + 1][x] == 0 && array[y + 2][x] == 1 && array[y + 3][x] == 1 && array[y + 4][x] == 1 && array[y + 5][x] == 0 && array[y + 6][x] == 1 && ((y + 10 < height && array[y + 7][x] == 0 && array[y + 8][x] == 0 && array[y + 9][x] == 0 && array[y + 10][x] == 0) || (y - 4 >= 0 && array[y - 1][x] == 0 && array[y - 2][x] == 0 && array[y - 3][x] == 0 && array[y - 4][x] == 0))) - { - penalty += 40; - } - } + penalty += N3; } - return penalty; + if (y + 6 < height && array[y][x] == 1 && array[y + 1][x] == 0 && array[y + 2][x] == 1 && array[y + 3][x] == 1 && array[y + 4][x] == 1 && array[y + 5][x] == 0 && array[y + 6][x] == 1 && ((y + 10 < height && array[y + 7][x] == 0 && array[y + 8][x] == 0 && array[y + 9][x] == 0 && array[y + 10][x] == 0) || (y - 4 >= 0 && array[y - 1][x] == 0 && array[y - 2][x] == 0 && array[y - 3][x] == 0 && array[y - 4][x] == 0))) + { + penalty += N3; + } + } } - - // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give - // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples: - // - 0% => 100 - // - 40% => 20 - // - 45% => 10 - // - 50% => 0 - // - 55% => 10 - // - 55% => 20 - // - 100% => 100 - public static int applyMaskPenaltyRule4(ByteMatrix matrix) + return penalty; + } + + /// + /// Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + /// penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + /// + internal static int applyMaskPenaltyRule4(ByteMatrix matrix) + { + int numDarkCells = 0; + sbyte[][] array = matrix.Array; + int width = matrix.Width; + int height = matrix.Height; + for (int y = 0; y < height; y++) { - int numDarkCells = 0; - sbyte[][] array = matrix.Array; - int width = matrix.Width; - int height = matrix.Height; - for (int y = 0; y < height; ++y) + sbyte[] arrayY = array[y]; + for (int x = 0; x < width; x++) + { + if (arrayY[x] == 1) { - for (int x = 0; x < width; ++x) - { - if (array[y][x] == 1) - { - numDarkCells += 1; - } - } + numDarkCells++; } - int numTotalCells = matrix.Height * matrix.Width; - double darkRatio = (double) numDarkCells / numTotalCells; - //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" - return System.Math.Abs((int) (darkRatio * 100 - 50)) / 5 * 10; + } } - - // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask - // pattern conditions. - public static bool getDataMaskBit(int maskPattern, int x, int y) + int numTotalCells = matrix.Height * matrix.Width; + double darkRatio = (double) numDarkCells / numTotalCells; + int fivePercentVariances = (int)(Math.Abs(darkRatio - 0.5) * 20.0); // * 100.0 / 5.0 + return fivePercentVariances * N4; + } + + /// + /// Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + /// pattern conditions. + /// + internal static bool getDataMaskBit(int maskPattern, int x, int y) + { + int intermediate; + int temp; + switch (maskPattern) { - if (!QRCode.isValidMaskPattern(maskPattern)) - { - throw new System.ArgumentException("Invalid mask pattern"); - } - int intermediate, temp; - switch (maskPattern) - { - - case 0: - intermediate = (y + x) & 0x1; - break; - - case 1: - intermediate = y & 0x1; - break; - - case 2: - intermediate = x % 3; - break; - - case 3: - intermediate = (y + x) % 3; - break; - - case 4: - intermediate = ((SupportClass.URShift(y, 1)) + (x / 3)) & 0x1; - break; - - case 5: - temp = y * x; - intermediate = (temp & 0x1) + (temp % 3); - break; - - case 6: - temp = y * x; - intermediate = (((temp & 0x1) + (temp % 3)) & 0x1); - break; - - case 7: - temp = y * x; - intermediate = (((temp % 3) + ((y + x) & 0x1)) & 0x1); - break; - - default: - throw new System.ArgumentException("Invalid mask pattern: " + maskPattern); - - } - return intermediate == 0; + case 0: + intermediate = (y + x) & 0x1; + break; + case 1: + intermediate = y & 0x1; + break; + case 2: + intermediate = x % 3; + break; + case 3: + intermediate = (y + x) % 3; + break; + case 4: + intermediate = (((int)((uint)y >> 1)) + (x / 3)) & 0x1; + break; + case 5: + temp = y * x; + intermediate = (temp & 0x1) + (temp % 3); + break; + case 6: + temp = y * x; + intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; + break; + case 7: + temp = y * x; + intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; + break; + default: + throw new System.ArgumentException("Invalid mask pattern: " + maskPattern); } - - // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both - // vertical and horizontal orders respectively. - private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) + return intermediate == 0; + } + + /// + /// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + /// vertical and horizontal orders respectively. + /// + private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, bool isHorizontal) + { + int penalty = 0; + int iLimit = isHorizontal ? matrix.Height : matrix.Width; + int jLimit = isHorizontal ? matrix.Width : matrix.Height; + sbyte[][] array = matrix.Array; + for (int i = 0; i < iLimit; i++) { - int penalty = 0; - int numSameBitCells = 0; - int prevBit = - 1; - // Horizontal mode: - // for (int i = 0; i < matrix.height(); ++i) { - // for (int j = 0; j < matrix.width(); ++j) { - // int bit = matrix.get(i, j); - // Vertical mode: - // for (int i = 0; i < matrix.width(); ++i) { - // for (int j = 0; j < matrix.height(); ++j) { - // int bit = matrix.get(j, i); - int iLimit = isHorizontal?matrix.Height:matrix.Width; - int jLimit = isHorizontal?matrix.Width:matrix.Height; - sbyte[][] array = matrix.Array; - for (int i = 0; i < iLimit; ++i) + int numSameBitCells = 0; + int prevBit = -1; + for (int j = 0; j < jLimit; j++) + { + int bit = isHorizontal ? array[i][j] : array[j][i]; + if (bit == prevBit) { - for (int j = 0; j < jLimit; ++j) - { - int bit = isHorizontal?array[i][j]:array[j][i]; - if (bit == prevBit) - { - numSameBitCells += 1; - // Found five repetitive cells with the same color (bit). - // We'll give penalty of 3. - if (numSameBitCells == 5) - { - penalty += 3; - } - else if (numSameBitCells > 5) - { - // After five repetitive cells, we'll add the penalty one - // by one. - penalty += 1; - } - } - else - { - numSameBitCells = 1; // Include the cell itself. - prevBit = bit; - } - } - numSameBitCells = 0; // Clear at each row/column. + numSameBitCells++; } - return penalty; + else + { + if (numSameBitCells >= 5) + { + penalty += N1 + (numSameBitCells - 5); + } + numSameBitCells = 1; // Include the cell itself. + prevBit = bit; + } + } + if (numSameBitCells > 5) + { + penalty += N1 + (numSameBitCells - 5); + } } + return penalty; + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/encoder/MatrixUtil.cs b/csharp/qrcode/encoder/MatrixUtil.cs index b461a66bf..d81c02cb9 100755 --- a/csharp/qrcode/encoder/MatrixUtil.cs +++ b/csharp/qrcode/encoder/MatrixUtil.cs @@ -1,518 +1,485 @@ +using System.Collections; + /* -* 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. -*/ -using System; -using WriterException = com.google.zxing.WriterException; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + * 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. + */ + namespace com.google.zxing.qrcode.encoder { - - /// satorux@google.com (Satoru Takabayashi) - creator - /// - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class MatrixUtil + + using WriterException = com.google.zxing.WriterException; + using BitArray = com.google.zxing.common.BitArray; + using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + using Version = com.google.zxing.qrcode.decoder.Version; + + /// + /// @author satorux@google.com (Satoru Takabayashi) - creator + /// @author dswitkin@google.com (Daniel Switkin) - ported from C++ + /// + internal sealed class MatrixUtil { - - private MatrixUtil() + + private MatrixUtil() + { + // do nothing + } + + private static readonly int[][] POSITION_DETECTION_PATTERN = {new int[] {1, 1, 1, 1, 1, 1, 1}, new int[] {1, 0, 0, 0, 0, 0, 1}, new int[] {1, 0, 1, 1, 1, 0, 1}, new int[] {1, 0, 1, 1, 1, 0, 1}, new int[] {1, 0, 1, 1, 1, 0, 1}, new int[] {1, 0, 0, 0, 0, 0, 1}, new int[] {1, 1, 1, 1, 1, 1, 1}}; + + private static readonly int[][] POSITION_ADJUSTMENT_PATTERN = {new int[] {1, 1, 1, 1, 1}, new int[] {1, 0, 0, 0, 1}, new int[] {1, 0, 1, 0, 1}, new int[] {1, 0, 0, 0, 1}, new int[] {1, 1, 1, 1, 1}}; + + // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. + private static readonly int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = {new int[] {-1, -1, -1, -1, -1, -1, -1}, new int[] {6, 18, -1, -1, -1, -1, -1}, new int[] {6, 22, -1, -1, -1, -1, -1}, new int[] {6, 26, -1, -1, -1, -1, -1}, new int[] {6, 30, -1, -1, -1, -1, -1}, new int[] {6, 34, -1, -1, -1, -1, -1}, new int[] {6, 22, 38, -1, -1, -1, -1}, new int[] {6, 24, 42, -1, -1, -1, -1}, new int[] {6, 26, 46, -1, -1, -1, -1}, new int[] {6, 28, 50, -1, -1, -1, -1}, new int[] {6, 30, 54, -1, -1, -1, -1}, new int[] {6, 32, 58, -1, -1, -1, -1}, new int[] {6, 34, 62, -1, -1, -1, -1}, new int[] {6, 26, 46, 66, -1, -1, -1}, new int[] {6, 26, 48, 70, -1, -1, -1}, new int[] {6, 26, 50, 74, -1, -1, -1}, new int[] {6, 30, 54, 78, -1, -1, -1}, new int[] {6, 30, 56, 82, -1, -1, -1}, new int[] {6, 30, 58, 86, -1, -1, -1}, new int[] {6, 34, 62, 90, -1, -1, -1}, new int[] {6, 28, 50, 72, 94, -1, -1}, new int[] {6, 26, 50, 74, 98, -1, -1}, new int[] {6, 30, 54, 78, 102, -1, -1}, new int[] {6, 28, 54, 80, 106, -1, -1}, new int[] {6, 32, 58, 84, 110, -1, -1}, new int[] {6, 30, 58, 86, 114, -1, -1}, new int[] {6, 34, 62, 90, 118, -1, -1}, new int[] {6, 26, 50, 74, 98, 122, -1}, new int[] {6, 30, 54, 78, 102, 126, -1}, new int[] {6, 26, 52, 78, 104, 130, -1}, new int[] {6, 30, 56, 82, 108, 134, -1}, new int[] {6, 34, 60, 86, 112, 138, -1}, new int[] {6, 30, 58, 86, 114, 142, -1}, new int[] {6, 34, 62, 90, 118, 146, -1}, new int[] {6, 30, 54, 78, 102, 126, 150}, new int[] {6, 24, 50, 76, 102, 128, 154}, new int[] {6, 28, 54, 80, 106, 132, 158}, new int[] {6, 32, 58, 84, 110, 136, 162}, new int[] {6, 26, 54, 82, 110, 138, 166}, new int[] {6, 30, 58, 86, 114, 142, 170}}; + + // Type info cells at the left top corner. + private static readonly int[][] TYPE_INFO_COORDINATES = {new int[] {8, 0}, new int[] {8, 1}, new int[] {8, 2}, new int[] {8, 3}, new int[] {8, 4}, new int[] {8, 5}, new int[] {8, 7}, new int[] {8, 8}, new int[] {7, 8}, new int[] {5, 8}, new int[] {4, 8}, new int[] {3, 8}, new int[] {2, 8}, new int[] {1, 8}, new int[] {0, 8}}; + + // From Appendix D in JISX0510:2004 (p. 67) + private const int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + + // From Appendix C in JISX0510:2004 (p.65). + private const int TYPE_INFO_POLY = 0x537; + private const int TYPE_INFO_MASK_PATTERN = 0x5412; + + // Set all cells to -1. -1 means that the cell is empty (not set yet). + // + // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding + // with the ByteMatrix initialized all to zero. + internal static void clearMatrix(ByteMatrix matrix) + { + matrix.clear((sbyte) - 1); + } + + // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On + // success, store the result in "matrix" and return true. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void buildMatrix(com.google.zxing.common.BitArray dataBits, com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, com.google.zxing.qrcode.decoder.Version version, int maskPattern, ByteMatrix matrix) throws com.google.zxing.WriterException + internal static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, Version version, int maskPattern, ByteMatrix matrix) + { + clearMatrix(matrix); + embedBasicPatterns(version, matrix); + // Type information appear with any version. + embedTypeInfo(ecLevel, maskPattern, matrix); + // Version info appear if version >= 7. + maybeEmbedVersionInfo(version, matrix); + // Data should be embedded at end. + embedDataBits(dataBits, maskPattern, matrix); + } + + // Embed basic patterns. On success, modify the matrix and return true. + // The basic patterns are: + // - Position detection patterns + // - Timing patterns + // - Dark dot at the left bottom corner + // - Position adjustment patterns, if need be +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void embedBasicPatterns(com.google.zxing.qrcode.decoder.Version version, ByteMatrix matrix) throws com.google.zxing.WriterException + internal static void embedBasicPatterns(Version version, ByteMatrix matrix) + { + // Let's get started with embedding big squares at corners. + embedPositionDetectionPatternsAndSeparators(matrix); + // Then, embed the dark dot at the left bottom corner. + embedDarkDotAtLeftBottomCorner(matrix); + + // Position adjustment patterns appear if version >= 2. + maybeEmbedPositionAdjustmentPatterns(version, matrix); + // Timing patterns should be embedded after position adj. patterns. + embedTimingPatterns(matrix); + } + + // Embed type information. On success, modify the matrix. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void embedTypeInfo(com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) throws com.google.zxing.WriterException + internal static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) + { + BitArray typeInfoBits = new BitArray(); + makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); + + for (int i = 0; i < typeInfoBits.Size; ++i) { - // do nothing - } - - //UPGRADE_NOTE: Final was removed from the declaration of 'POSITION_DETECTION_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] POSITION_DETECTION_PATTERN = new int[][]{new int[]{1, 1, 1, 1, 1, 1, 1}, new int[]{1, 0, 0, 0, 0, 0, 1}, new int[]{1, 0, 1, 1, 1, 0, 1}, new int[]{1, 0, 1, 1, 1, 0, 1}, new int[]{1, 0, 1, 1, 1, 0, 1}, new int[]{1, 0, 0, 0, 0, 0, 1}, new int[]{1, 1, 1, 1, 1, 1, 1}}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'HORIZONTAL_SEPARATION_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] HORIZONTAL_SEPARATION_PATTERN = new int[][]{new int[]{0, 0, 0, 0, 0, 0, 0, 0}}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'VERTICAL_SEPARATION_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] VERTICAL_SEPARATION_PATTERN = new int[][]{new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}, new int[]{0}}; - - //UPGRADE_NOTE: Final was removed from the declaration of 'POSITION_ADJUSTMENT_PATTERN'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] POSITION_ADJUSTMENT_PATTERN = new int[][]{new int[]{1, 1, 1, 1, 1}, new int[]{1, 0, 0, 0, 1}, new int[]{1, 0, 1, 0, 1}, new int[]{1, 0, 0, 0, 1}, new int[]{1, 1, 1, 1, 1}}; - - // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. - //UPGRADE_NOTE: Final was removed from the declaration of 'POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = new int[][]{new int[]{- 1, - 1, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 18, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 22, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 26, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 30, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 34, - 1, - 1, - 1, - 1, - 1}, new int[]{6, 22, 38, - 1, - 1, - 1, - 1}, new int[]{6, 24, 42, - 1, - 1, - 1, - 1}, new int[]{6, 26, 46, - 1, - 1, - 1, - 1}, new int[]{6, 28, 50, - 1, - 1, - 1, - 1}, new int[]{6, 30, 54, - 1, - 1, - 1, - 1}, new int[]{6, 32, 58, - 1, - 1, - 1, - 1}, new int[]{6, 34, 62, - 1, - 1, - 1, - 1}, new int[]{6, 26, 46, 66, - 1, - 1, - 1}, new int[]{6, 26, 48, 70, - 1, - 1, - 1}, new int[]{6, 26, 50, 74, - 1, - 1, - 1}, new int[]{6, 30, 54, 78, - 1, - 1, - 1}, new int[]{6, 30, 56, 82, - 1, - 1, - 1}, new int[]{6, 30, 58, 86, - 1, - 1, - 1}, new int[]{6, 34, 62, 90, - 1, - 1, - 1}, new int[]{6, 28, 50, 72, 94, - 1, - 1}, new int[]{6, 26, 50, 74, 98, - 1, - 1}, new int[]{6, 30, 54, 78, 102, - 1, - 1}, new int[]{6, 28, 54, 80, 106, - 1, - 1}, new int[]{6, 32, 58, 84, 110, - 1, - 1}, new int[]{6, 30, 58, 86, 114, - 1, - 1}, new int[]{6, 34, 62, 90, 118, - 1, - 1}, new int[]{6, 26, 50, 74, 98, 122, - 1}, new int[]{6, 30, 54, 78, 102, 126, - 1}, new int[]{6, 26, 52, 78, 104, 130, - 1}, new int[]{6, 30, 56, 82, 108, 134, - 1}, new int[]{6, 34, 60, 86, 112, 138, - 1}, new int[]{6, 30, 58, 86, 114, 142, - 1}, new int[]{6, 34, 62, 90, 118, 146, - 1}, new int[]{6, 30, 54, 78, 102, 126, 150}, new int[]{6, 24, 50, 76, 102, 128, 154}, new int[]{6, 28, 54, 80, 106, 132, 158}, new int[]{6, 32, 58, 84, 110, 136, 162}, new int[]{6, 26, 54, 82, 110, 138, 166}, new int[]{6, 30, 58, 86, 114, 142, 170}}; - - // Type info cells at the left top corner. - //UPGRADE_NOTE: Final was removed from the declaration of 'TYPE_INFO_COORDINATES'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" - private static readonly int[][] TYPE_INFO_COORDINATES = new int[][]{new int[]{8, 0}, new int[]{8, 1}, new int[]{8, 2}, new int[]{8, 3}, new int[]{8, 4}, new int[]{8, 5}, new int[]{8, 7}, new int[]{8, 8}, new int[]{7, 8}, new int[]{5, 8}, new int[]{4, 8}, new int[]{3, 8}, new int[]{2, 8}, new int[]{1, 8}, new int[]{0, 8}}; - - // From Appendix D in JISX0510:2004 (p. 67) - private const int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 - - // From Appendix C in JISX0510:2004 (p.65). - private const int TYPE_INFO_POLY = 0x537; - private const int TYPE_INFO_MASK_PATTERN = 0x5412; - - // Set all cells to -1. -1 means that the cell is empty (not set yet). - // - // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding - // with the ByteMatrix initialized all to zero. - public static void clearMatrix(ByteMatrix matrix) - { - matrix.clear((sbyte) (- 1)); - } - - // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On - // success, store the result in "matrix" and return true. - public static void buildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version, int maskPattern, ByteMatrix matrix) - { - clearMatrix(matrix); - embedBasicPatterns(version, matrix); - // Type information appear with any version. - embedTypeInfo(ecLevel, maskPattern, matrix); - // Version info appear if version >= 7. - maybeEmbedVersionInfo(version, matrix); - // Data should be embedded at end. - embedDataBits(dataBits, maskPattern, matrix); - } - - // Embed basic patterns. On success, modify the matrix and return true. - // The basic patterns are: - // - Position detection patterns - // - Timing patterns - // - Dark dot at the left bottom corner - // - Position adjustment patterns, if need be - public static void embedBasicPatterns(int version, ByteMatrix matrix) - { - // Let's get started with embedding big squares at corners. - embedPositionDetectionPatternsAndSeparators(matrix); - // Then, embed the dark dot at the left bottom corner. - embedDarkDotAtLeftBottomCorner(matrix); - - // Position adjustment patterns appear if version >= 2. - maybeEmbedPositionAdjustmentPatterns(version, matrix); - // Timing patterns should be embedded after position adj. patterns. - embedTimingPatterns(matrix); - } - - // Embed type information. On success, modify the matrix. - public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) - { - BitVector typeInfoBits = new BitVector(); - makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); - - for (int i = 0; i < typeInfoBits.size(); ++i) - { - // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in - // "typeInfoBits". - int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i); - - // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). - int x1 = TYPE_INFO_COORDINATES[i][0]; - int y1 = TYPE_INFO_COORDINATES[i][1]; - matrix.set_Renamed(x1, y1, bit); - - if (i < 8) - { - // Right top corner. - int x2 = matrix.Width - i - 1; - int y2 = 8; - matrix.set_Renamed(x2, y2, bit); - } - else - { - // Left bottom corner. - int x2 = 8; - int y2 = matrix.Height - 7 + (i - 8); - matrix.set_Renamed(x2, y2, bit); - } - } - } - - // Embed version information if need be. On success, modify the matrix and return true. - // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. - public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix) - { - if (version < 7) - { - // Version info is necessary if version >= 7. - return ; // Don't need version info. - } - BitVector versionInfoBits = new BitVector(); - makeVersionInfoBits(version, versionInfoBits); - - int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. - for (int i = 0; i < 6; ++i) - { - for (int j = 0; j < 3; ++j) - { - // Place bits in LSB (least significant bit) to MSB order. - int bit = versionInfoBits.at(bitIndex); - bitIndex--; - // Left bottom corner. - matrix.set_Renamed(i, matrix.Height - 11 + j, bit); - // Right bottom corner. - matrix.set_Renamed(matrix.Height - 11 + j, i, bit); - } - } - } - - // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. - // For debugging purposes, it skips masking process if "getMaskPattern" is -1. - // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. - public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix) - { - int bitIndex = 0; - int direction = - 1; - // Start from the right bottom cell. - int x = matrix.Width - 1; - int y = matrix.Height - 1; - while (x > 0) - { - // Skip the vertical timing pattern. - if (x == 6) - { - x -= 1; - } - while (y >= 0 && y < matrix.Height) - { - for (int i = 0; i < 2; ++i) - { - int xx = x - i; - // Skip the cell if it's not empty. - if (!isEmpty(matrix.get_Renamed(xx, y))) - { - continue; - } - int bit; - if (bitIndex < dataBits.size()) - { - bit = dataBits.at(bitIndex); - ++bitIndex; - } - else - { - // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described - // in 8.4.9 of JISX0510:2004 (p. 24). - bit = 0; - } - - // Skip masking if mask_pattern is -1. - if (maskPattern != - 1) - { - if (MaskUtil.getDataMaskBit(maskPattern, xx, y)) - { - bit ^= 0x1; - } - } - matrix.set_Renamed(xx, y, bit); - } - y += direction; - } - direction = - direction; // Reverse the direction. - y += direction; - x -= 2; // Move to the left. - } - // All bits should be consumed. - if (bitIndex != dataBits.size()) - { - throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size()); - } - } - - // Return the position of the most significant bit set (to one) in the "value". The most - // significant bit is position 32. If there is no bit set, return 0. Examples: - // - findMSBSet(0) => 0 - // - findMSBSet(1) => 1 - // - findMSBSet(255) => 8 - public static int findMSBSet(int value_Renamed) - { - int numDigits = 0; - while (value_Renamed != 0) - { - value_Renamed = SupportClass.URShift(value_Renamed, 1); - ++numDigits; - } - return numDigits; - } - - // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH - // code is used for encoding type information and version information. - // Example: Calculation of version information of 7. - // f(x) is created from 7. - // - 7 = 000111 in 6 bits - // - f(x) = x^2 + x^2 + x^1 - // g(x) is given by the standard (p. 67) - // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 - // Multiply f(x) by x^(18 - 6) - // - f'(x) = f(x) * x^(18 - 6) - // - f'(x) = x^14 + x^13 + x^12 - // Calculate the remainder of f'(x) / g(x) - // x^2 - // __________________________________________________ - // g(x) )x^14 + x^13 + x^12 - // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 - // -------------------------------------------------- - // x^11 + x^10 + x^7 + x^4 + x^2 - // - // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 - // Encode it in binary: 110010010100 - // The return value is 0xc94 (1100 1001 0100) - // - // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit - // operations. We don't care if cofficients are positive or negative. - public static int calculateBCHCode(int value_Renamed, int poly) - { - // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 - // from 13 to make it 12. - int msbSetInPoly = findMSBSet(poly); - value_Renamed <<= msbSetInPoly - 1; - // Do the division business using exclusive-or operations. - while (findMSBSet(value_Renamed) >= msbSetInPoly) - { - value_Renamed ^= poly << (findMSBSet(value_Renamed) - msbSetInPoly); - } - // Now the "value" is the remainder (i.e. the BCH code) - return value_Renamed; - } - - // Make bit vector of type information. On success, store the result in "bits" and return true. - // Encode error correction level and mask pattern. See 8.9 of - // JISX0510:2004 (p.45) for details. - public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits) - { - if (!QRCode.isValidMaskPattern(maskPattern)) - { - throw new WriterException("Invalid mask pattern"); - } - int typeInfo = (ecLevel.Bits << 3) | maskPattern; - bits.appendBits(typeInfo, 5); - - int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); - bits.appendBits(bchCode, 10); - - BitVector maskBits = new BitVector(); - maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); - bits.xor(maskBits); - - if (bits.size() != 15) - { - // Just in case. - throw new WriterException("should not happen but we got: " + bits.size()); - } - } - - // Make bit vector of version information. On success, store the result in "bits" and return true. - // See 8.10 of JISX0510:2004 (p.45) for details. - public static void makeVersionInfoBits(int version, BitVector bits) - { - bits.appendBits(version, 6); - int bchCode = calculateBCHCode(version, VERSION_INFO_POLY); - bits.appendBits(bchCode, 12); - - if (bits.size() != 18) - { - // Just in case. - throw new WriterException("should not happen but we got: " + bits.size()); - } - } - - // Check if "value" is empty. - private static bool isEmpty(int value_Renamed) - { - return value_Renamed == - 1; - } - - // Check if "value" is valid. - private static bool isValidValue(int value_Renamed) - { - return (value_Renamed == - 1 || value_Renamed == 0 || value_Renamed == 1); // Dark (black). - } - - private static void embedTimingPatterns(ByteMatrix matrix) - { - // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical - // separation patterns (size 1). Thus, 8 = 7 + 1. - for (int i = 8; i < matrix.Width - 8; ++i) - { - int bit = (i + 1) % 2; - // Horizontal line. - if (!isValidValue(matrix.get_Renamed(i, 6))) - { - throw new WriterException(); - } - if (isEmpty(matrix.get_Renamed(i, 6))) - { - matrix.set_Renamed(i, 6, bit); - } - // Vertical line. - if (!isValidValue(matrix.get_Renamed(6, i))) - { - throw new WriterException(); - } - if (isEmpty(matrix.get_Renamed(6, i))) - { - matrix.set_Renamed(6, i, bit); - } - } - } - - // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) - private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) - { - if (matrix.get_Renamed(8, matrix.Height - 8) == 0) - { - throw new WriterException(); - } - matrix.set_Renamed(8, matrix.Height - 8, 1); - } - - private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) - { - // We know the width and height. - if (HORIZONTAL_SEPARATION_PATTERN[0].Length != 8 || HORIZONTAL_SEPARATION_PATTERN.Length != 1) - { - throw new WriterException("Bad horizontal separation pattern"); - } - for (int x = 0; x < 8; ++x) - { - if (!isEmpty(matrix.get_Renamed(xStart + x, yStart))) - { - throw new WriterException(); - } - matrix.set_Renamed(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]); - } - } - - private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) - { - // We know the width and height. - if (VERTICAL_SEPARATION_PATTERN[0].Length != 1 || VERTICAL_SEPARATION_PATTERN.Length != 7) - { - throw new WriterException("Bad vertical separation pattern"); - } - for (int y = 0; y < 7; ++y) - { - if (!isEmpty(matrix.get_Renamed(xStart, yStart + y))) - { - throw new WriterException(); - } - matrix.set_Renamed(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]); - } - } - - // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are - // almost identical, since we cannot write a function that takes 2D arrays in different sizes in - // C/C++. We should live with the fact. - private static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix matrix) - { - // We know the width and height. - if (POSITION_ADJUSTMENT_PATTERN[0].Length != 5 || POSITION_ADJUSTMENT_PATTERN.Length != 5) - { - throw new WriterException("Bad position adjustment"); - } - for (int y = 0; y < 5; ++y) - { - for (int x = 0; x < 5; ++x) - { - if (!isEmpty(matrix.get_Renamed(xStart + x, yStart + y))) - { - throw new WriterException(); - } - matrix.set_Renamed(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); - } - } - } - - private static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix matrix) - { - // We know the width and height. - if (POSITION_DETECTION_PATTERN[0].Length != 7 || POSITION_DETECTION_PATTERN.Length != 7) - { - throw new WriterException("Bad position detection pattern"); - } - for (int y = 0; y < 7; ++y) - { - for (int x = 0; x < 7; ++x) - { - if (!isEmpty(matrix.get_Renamed(xStart + x, yStart + y))) - { - throw new WriterException(); - } - matrix.set_Renamed(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); - } - } - } - - // Embed position detection patterns and surrounding vertical/horizontal separators. - private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) - { - // Embed three big squares at corners. - int pdpWidth = POSITION_DETECTION_PATTERN[0].Length; - // Left top corner. - embedPositionDetectionPattern(0, 0, matrix); + // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in + // "typeInfoBits". + bool bit = typeInfoBits.get(typeInfoBits.Size - 1 - i); + + // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). + int x1 = TYPE_INFO_COORDINATES[i][0]; + int y1 = TYPE_INFO_COORDINATES[i][1]; + matrix.set(x1, y1, bit); + + if (i < 8) + { // Right top corner. - embedPositionDetectionPattern(matrix.Width - pdpWidth, 0, matrix); + int x2 = matrix.Width - i - 1; + int y2 = 8; + matrix.set(x2, y2, bit); + } + else + { // Left bottom corner. - embedPositionDetectionPattern(0, matrix.Width - pdpWidth, matrix); - - // Embed horizontal separation patterns around the squares. - int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].Length; - // Left top corner. - embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); - // Right top corner. - embedHorizontalSeparationPattern(matrix.Width - hspWidth, hspWidth - 1, matrix); - // Left bottom corner. - embedHorizontalSeparationPattern(0, matrix.Width - hspWidth, matrix); - - // Embed vertical separation patterns around the squares. - int vspSize = VERTICAL_SEPARATION_PATTERN.Length; - // Left top corner. - embedVerticalSeparationPattern(vspSize, 0, matrix); - // Right top corner. - embedVerticalSeparationPattern(matrix.Height - vspSize - 1, 0, matrix); - // Left bottom corner. - embedVerticalSeparationPattern(vspSize, matrix.Height - vspSize, matrix); + int x2 = 8; + int y2 = matrix.Height - 7 + (i - 8); + matrix.set(x2, y2, bit); + } } - - // Embed position adjustment patterns if need be. - private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix) + } + + // Embed version information if need be. On success, modify the matrix and return true. + // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void maybeEmbedVersionInfo(com.google.zxing.qrcode.decoder.Version version, ByteMatrix matrix) throws com.google.zxing.WriterException + internal static void maybeEmbedVersionInfo(Version version, ByteMatrix matrix) + { + if (version.VersionNumber < 7) // Version info is necessary if version >= 7. { - if (version < 2) - { - // The patterns appear if version >= 2 - return ; - } - int index = version - 1; - int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; - int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].Length; - for (int i = 0; i < numCoordinates; ++i) - { - for (int j = 0; j < numCoordinates; ++j) - { - int y = coordinates[i]; - int x = coordinates[j]; - if (x == - 1 || y == - 1) - { - continue; - } - // If the cell is unset, we embed the position adjustment pattern here. - if (isEmpty(matrix.get_Renamed(x, y))) - { - // -2 is necessary since the x/y coordinates point to the center of the pattern, not the - // left top corner. - embedPositionAdjustmentPattern(x - 2, y - 2, matrix); - } - } - } + return; // Don't need version info. } + BitArray versionInfoBits = new BitArray(); + makeVersionInfoBits(version, versionInfoBits); + + int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. + for (int i = 0; i < 6; ++i) + { + for (int j = 0; j < 3; ++j) + { + // Place bits in LSB (least significant bit) to MSB order. + bool bit = versionInfoBits.get(bitIndex); + bitIndex--; + // Left bottom corner. + matrix.set(i, matrix.Height - 11 + j, bit); + // Right bottom corner. + matrix.set(matrix.Height - 11 + j, i, bit); + } + } + } + + // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. + // For debugging purposes, it skips masking process if "getMaskPattern" is -1. + // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void embedDataBits(com.google.zxing.common.BitArray dataBits, int maskPattern, ByteMatrix matrix) throws com.google.zxing.WriterException + internal static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix) + { + int bitIndex = 0; + int direction = -1; + // Start from the right bottom cell. + int x = matrix.Width - 1; + int y = matrix.Height - 1; + while (x > 0) + { + // Skip the vertical timing pattern. + if (x == 6) + { + x -= 1; + } + while (y >= 0 && y < matrix.Height) + { + for (int i = 0; i < 2; ++i) + { + int xx = x - i; + // Skip the cell if it's not empty. + if (!isEmpty(matrix.get(xx, y))) + { + continue; + } + bool bit; + if (bitIndex < dataBits.Size) + { + bit = dataBits.get(bitIndex); + ++bitIndex; + } + else + { + // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described + // in 8.4.9 of JISX0510:2004 (p. 24). + bit = false; + } + + // Skip masking if mask_pattern is -1. + if (maskPattern != -1 && MaskUtil.getDataMaskBit(maskPattern, xx, y)) + { + bit = !bit; + } + matrix.set(xx, y, bit); + } + y += direction; + } + direction = -direction; // Reverse the direction. + y += direction; + x -= 2; // Move to the left. + } + // All bits should be consumed. + if (bitIndex != dataBits.Size) + { + throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.Size); + } + } + + // Return the position of the most significant bit set (to one) in the "value". The most + // significant bit is position 32. If there is no bit set, return 0. Examples: + // - findMSBSet(0) => 0 + // - findMSBSet(1) => 1 + // - findMSBSet(255) => 8 + internal static int findMSBSet(int value) + { + int numDigits = 0; + while (value != 0) + { + value = (int)((uint)value >> 1); + ++numDigits; + } + return numDigits; + } + + // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH + // code is used for encoding type information and version information. + // Example: Calculation of version information of 7. + // f(x) is created from 7. + // - 7 = 000111 in 6 bits + // - f(x) = x^2 + x^1 + x^0 + // g(x) is given by the standard (p. 67) + // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 + // Multiply f(x) by x^(18 - 6) + // - f'(x) = f(x) * x^(18 - 6) + // - f'(x) = x^14 + x^13 + x^12 + // Calculate the remainder of f'(x) / g(x) + // x^2 + // __________________________________________________ + // g(x) )x^14 + x^13 + x^12 + // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 + // -------------------------------------------------- + // x^11 + x^10 + x^7 + x^4 + x^2 + // + // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 + // Encode it in binary: 110010010100 + // The return value is 0xc94 (1100 1001 0100) + // + // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit + // operations. We don't care if cofficients are positive or negative. + internal static int calculateBCHCode(int value, int poly) + { + // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 + // from 13 to make it 12. + int msbSetInPoly = findMSBSet(poly); + value <<= msbSetInPoly - 1; + // Do the division business using exclusive-or operations. + while (findMSBSet(value) >= msbSetInPoly) + { + value ^= poly << (findMSBSet(value) - msbSetInPoly); + } + // Now the "value" is the remainder (i.e. the BCH code) + return value; + } + + // Make bit vector of type information. On success, store the result in "bits" and return true. + // Encode error correction level and mask pattern. See 8.9 of + // JISX0510:2004 (p.45) for details. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void makeTypeInfoBits(com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ecLevel, int maskPattern, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits) + { + if (!QRCode.isValidMaskPattern(maskPattern)) + { + throw new WriterException("Invalid mask pattern"); + } + int typeInfo = (ecLevel.Bits << 3) | maskPattern; + bits.appendBits(typeInfo, 5); + + int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); + bits.appendBits(bchCode, 10); + + BitArray maskBits = new BitArray(); + maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); + bits.xor(maskBits); + + if (bits.Size != 15) // Just in case. + { + throw new WriterException("should not happen but we got: " + bits.Size); + } + } + + // Make bit vector of version information. On success, store the result in "bits" and return true. + // See 8.10 of JISX0510:2004 (p.45) for details. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: static void makeVersionInfoBits(com.google.zxing.qrcode.decoder.Version version, com.google.zxing.common.BitArray bits) throws com.google.zxing.WriterException + internal static void makeVersionInfoBits(Version version, BitArray bits) + { + bits.appendBits(version.VersionNumber, 6); + int bchCode = calculateBCHCode(version.VersionNumber, VERSION_INFO_POLY); + bits.appendBits(bchCode, 12); + + if (bits.Size != 18) // Just in case. + { + throw new WriterException("should not happen but we got: " + bits.Size); + } + } + + // Check if "value" is empty. + private static bool isEmpty(int value) + { + return value == -1; + } + + private static void embedTimingPatterns(ByteMatrix matrix) + { + // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical + // separation patterns (size 1). Thus, 8 = 7 + 1. + for (int i = 8; i < matrix.Width - 8; ++i) + { + int bit = (i + 1) % 2; + // Horizontal line. + if (isEmpty(matrix.get(i, 6))) + { + matrix.set(i, 6, bit); + } + // Vertical line. + if (isEmpty(matrix.get(6, i))) + { + matrix.set(6, i, bit); + } + } + } + + // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws com.google.zxing.WriterException + private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) + { + if (matrix.get(8, matrix.Height - 8) == 0) + { + throw new WriterException(); + } + matrix.set(8, matrix.Height - 8, 1); + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) throws com.google.zxing.WriterException + private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) + { + for (int x = 0; x < 8; ++x) + { + if (!isEmpty(matrix.get(xStart + x, yStart))) + { + throw new WriterException(); + } + matrix.set(xStart + x, yStart, 0); + } + } + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) throws com.google.zxing.WriterException + private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) + { + for (int y = 0; y < 7; ++y) + { + if (!isEmpty(matrix.get(xStart, yStart + y))) + { + throw new WriterException(); + } + matrix.set(xStart, yStart + y, 0); + } + } + + // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are + // almost identical, since we cannot write a function that takes 2D arrays in different sizes in + // C/C++. We should live with the fact. + private static void embedPositionAdjustmentPattern(int xStart, int yStart, ByteMatrix matrix) + { + for (int y = 0; y < 5; ++y) + { + for (int x = 0; x < 5; ++x) + { + matrix.set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); + } + } + } + + private static void embedPositionDetectionPattern(int xStart, int yStart, ByteMatrix matrix) + { + for (int y = 0; y < 7; ++y) + { + for (int x = 0; x < 7; ++x) + { + matrix.set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); + } + } + } + + // Embed position detection patterns and surrounding vertical/horizontal separators. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: +//ORIGINAL LINE: private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws com.google.zxing.WriterException + private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) + { + // Embed three big squares at corners. + int pdpWidth = POSITION_DETECTION_PATTERN[0].Length; + // Left top corner. + embedPositionDetectionPattern(0, 0, matrix); + // Right top corner. + embedPositionDetectionPattern(matrix.Width - pdpWidth, 0, matrix); + // Left bottom corner. + embedPositionDetectionPattern(0, matrix.Width - pdpWidth, matrix); + + // Embed horizontal separation patterns around the squares. + int hspWidth = 8; + // Left top corner. + embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); + // Right top corner. + embedHorizontalSeparationPattern(matrix.Width - hspWidth, hspWidth - 1, matrix); + // Left bottom corner. + embedHorizontalSeparationPattern(0, matrix.Width - hspWidth, matrix); + + // Embed vertical separation patterns around the squares. + int vspSize = 7; + // Left top corner. + embedVerticalSeparationPattern(vspSize, 0, matrix); + // Right top corner. + embedVerticalSeparationPattern(matrix.Height - vspSize - 1, 0, matrix); + // Left bottom corner. + embedVerticalSeparationPattern(vspSize, matrix.Height - vspSize, matrix); + } + + // Embed position adjustment patterns if need be. + private static void maybeEmbedPositionAdjustmentPatterns(Version version, ByteMatrix matrix) + { + if (version.VersionNumber < 2) // The patterns appear if version >= 2 + { + return; + } + int index = version.VersionNumber - 1; + int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; + int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].Length; + for (int i = 0; i < numCoordinates; ++i) + { + for (int j = 0; j < numCoordinates; ++j) + { + int y = coordinates[i]; + int x = coordinates[j]; + if (x == -1 || y == -1) + { + continue; + } + // If the cell is unset, we embed the position adjustment pattern here. + if (isEmpty(matrix.get(x, y))) + { + // -2 is necessary since the x/y coordinates point to the center of the pattern, not the + // left top corner. + embedPositionAdjustmentPattern(x - 2, y - 2, matrix); + } + } + } + } + } + } \ No newline at end of file diff --git a/csharp/qrcode/encoder/QRCode.cs b/csharp/qrcode/encoder/QRCode.cs index 972fd022e..5595eb1ad 100755 --- a/csharp/qrcode/encoder/QRCode.cs +++ b/csharp/qrcode/encoder/QRCode.cs @@ -1,299 +1,144 @@ +using System.Text; + /* -* 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. -*/ -using System; -using ByteMatrix = com.google.zxing.common.ByteMatrix; -using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -using Mode = com.google.zxing.qrcode.decoder.Mode; + * 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. + */ + namespace com.google.zxing.qrcode.encoder { - - /// satorux@google.com (Satoru Takabayashi) - creator - /// - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// + + using ErrorCorrectionLevel = com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + using Mode = com.google.zxing.qrcode.decoder.Mode; + using Version = com.google.zxing.qrcode.decoder.Version; + + /// + /// @author satorux@google.com (Satoru Takabayashi) - creator + /// @author dswitkin@google.com (Daniel Switkin) - ported from C++ + /// public sealed class QRCode { - public Mode Mode + + public const int NUM_MASK_PATTERNS = 8; + + private Mode mode; + private ErrorCorrectionLevel ecLevel; + private Version version; + private int maskPattern; + private ByteMatrix matrix; + + public QRCode() + { + maskPattern = -1; + } + + public Mode Mode + { + get + { + return mode; + } + set + { + mode = value; + } + } + + public ErrorCorrectionLevel ECLevel + { + get + { + return ecLevel; + } + set + { + ecLevel = value; + } + } + + public Version Version + { + get + { + return version; + } + set + { + this.version = value; + } + } + + public int MaskPattern + { + get + { + return maskPattern; + } + set + { + maskPattern = value; + } + } + + public ByteMatrix Matrix + { + get + { + return matrix; + } + set + { + matrix = value; + } + } + + public override string ToString() + { + StringBuilder result = new StringBuilder(200); + result.Append("<<\n"); + result.Append(" mode: "); + result.Append(mode); + result.Append("\n ecLevel: "); + result.Append(ecLevel); + result.Append("\n version: "); + result.Append(version); + result.Append("\n maskPattern: "); + result.Append(maskPattern); + if (matrix == null) { - // Mode of the QR Code. - - get - { - return mode; - } - - set - { - mode = value; - } - + result.Append("\n matrix: null\n"); } - public ErrorCorrectionLevel ECLevel + else { - // Error correction level of the QR Code. - - get - { - return ecLevel; - } - - set - { - ecLevel = value; - } - + result.Append("\n matrix:\n"); + result.Append(matrix.ToString()); } - public int Version - { - // Version of the QR Code. The bigger size, the bigger version. - - get - { - return version; - } - - set - { - version = value; - } - - } - public int MatrixWidth - { - // ByteMatrix width of the QR Code. - - get - { - return matrixWidth; - } - - set - { - matrixWidth = value; - } - - } - public int MaskPattern - { - // Mask pattern of the QR Code. - - get - { - return maskPattern; - } - - set - { - maskPattern = value; - } - - } - public int NumTotalBytes - { - // Number of total bytes in the QR Code. - - get - { - return numTotalBytes; - } - - set - { - numTotalBytes = value; - } - - } - public int NumDataBytes - { - // Number of data bytes in the QR Code. - - get - { - return numDataBytes; - } - - set - { - numDataBytes = value; - } - - } - public int NumECBytes - { - // Number of error correction bytes in the QR Code. - - get - { - return numECBytes; - } - - set - { - numECBytes = value; - } - - } - public int NumRSBlocks - { - // Number of Reedsolomon blocks in the QR Code. - - get - { - return numRSBlocks; - } - - set - { - numRSBlocks = value; - } - - } - public ByteMatrix Matrix - { - // ByteMatrix data of the QR Code. - - get - { - return matrix; - } - - // This takes ownership of the 2D array. - - set - { - matrix = value; - } - - } - public bool Valid - { - // Checks all the member variables are set properly. Returns true on success. Otherwise, returns - // false. - - get - { - return mode != null && ecLevel != null && version != - 1 && matrixWidth != - 1 && maskPattern != - 1 && numTotalBytes != - 1 && numDataBytes != - 1 && numECBytes != - 1 && numRSBlocks != - 1 && isValidMaskPattern(maskPattern) && numTotalBytes == numDataBytes + numECBytes && matrix != null && matrixWidth == matrix.Width && matrix.Width == matrix.Height; // Must be square. - } - - } - - public const int NUM_MASK_PATTERNS = 8; - - private Mode mode; - private ErrorCorrectionLevel ecLevel; - private int version; - private int matrixWidth; - private int maskPattern; - private int numTotalBytes; - private int numDataBytes; - private int numECBytes; - private int numRSBlocks; - private ByteMatrix matrix; - - public QRCode() - { - mode = null; - ecLevel = null; - version = - 1; - matrixWidth = - 1; - maskPattern = - 1; - numTotalBytes = - 1; - numDataBytes = - 1; - numECBytes = - 1; - numRSBlocks = - 1; - matrix = null; - } - - - // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They - // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell. - public int at(int x, int y) - { - // The value must be zero or one. - int value_Renamed = matrix.get_Renamed(x, y); - if (!(value_Renamed == 0 || value_Renamed == 1)) - { - // this is really like an assert... not sure what better exception to use? - throw new System.SystemException("Bad value"); - } - return value_Renamed; - } - - // Return debug String. - public override System.String ToString() - { - System.Text.StringBuilder result = new System.Text.StringBuilder(200); - result.Append("<<\n"); - result.Append(" mode: "); - result.Append(mode); - result.Append("\n ecLevel: "); - result.Append(ecLevel); - result.Append("\n version: "); - result.Append(version); - result.Append("\n matrixWidth: "); - result.Append(matrixWidth); - result.Append("\n maskPattern: "); - result.Append(maskPattern); - result.Append("\n numTotalBytes: "); - result.Append(numTotalBytes); - result.Append("\n numDataBytes: "); - result.Append(numDataBytes); - result.Append("\n numECBytes: "); - result.Append(numECBytes); - result.Append("\n numRSBlocks: "); - result.Append(numRSBlocks); - if (matrix == null) - { - result.Append("\n matrix: null\n"); - } - else - { - result.Append("\n matrix:\n"); - result.Append(matrix.ToString()); - } - result.Append(">>\n"); - return result.ToString(); - } - - // Check if "mask_pattern" is valid. - public static bool isValidMaskPattern(int maskPattern) - { - return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; - } - - // Return true if the all values in the matrix are binary numbers. - // - // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in - // production. I'm leaving it because it may be useful for testing. It should be removed entirely - // if ByteMatrix is changed never to contain a -1. - /* - private static boolean EverythingIsBinary(final ByteMatrix matrix) { - for (int y = 0; y < matrix.height(); ++y) { - for (int x = 0; x < matrix.width(); ++x) { - int value = matrix.get(y, x); - if (!(value == 0 || value == 1)) { - // Found non zero/one value. - return false; - } - } - } - return true; - } - */ + result.Append(">>\n"); + return result.ToString(); + } + + + + + + + // Check if "mask_pattern" is valid. + public static bool isValidMaskPattern(int maskPattern) + { + return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; + } + } + } \ No newline at end of file diff --git a/csharp/zxing.csproj b/csharp/zxing.csproj index f659f3ac7..090ba1d5b 100755 --- a/csharp/zxing.csproj +++ b/csharp/zxing.csproj @@ -1,4 +1,5 @@ - + + Local 2.0 @@ -26,10 +27,12 @@ {6431CF13-7A7B-4602-B96A-47CDA6F0B008} - 2.0 + 3.5 + v4.0 + - .\ + bin\Debug\ false 285212672 false @@ -93,6 +96,8 @@ System.Management + + System.Windows.Forms @@ -102,9 +107,14 @@ + + + + + @@ -115,16 +125,12 @@ + + - - - - - - @@ -132,6 +138,8 @@ + + @@ -140,28 +148,32 @@ + + + - - - - + - + + - - + + + + + @@ -171,7 +183,12 @@ + + + + + @@ -180,25 +197,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -214,14 +285,15 @@ - + + @@ -229,11 +301,13 @@ - + + + @@ -241,4 +315,4 @@ - + \ No newline at end of file