From 0d369f90f415cde21e78edbba5202d0f65a9c452 Mon Sep 17 00:00:00 2001 From: akwkevin Date: Fri, 23 Jul 2021 16:42:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E5=BC=95=E7=94=A8=E7=9A=84=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E5=8F=98=E6=88=90=E5=AE=89=E8=A3=85=E5=8C=85=E7=9A=84?= =?UTF-8?q?=E5=BD=A2=E5=BC=8F=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AIStudio.Wpf.ADiagram.csproj | 18 +- .../ViewModels/MainWindowViewModel.cs | 20 +- AIStudio.Wpf.ADiagram/zxing.core.dll | Bin 0 -> 554496 bytes AIStudio.Wpf.Diagram.sln | 72 -- .../Util.DiagramDesigner.csproj | 7 +- zxing.core/xx/BarcodeFormat.cs | 92 -- zxing.core/xx/BarcodeReader.Bitmap.cs | 74 -- zxing.core/xx/BarcodeReaderCustom.cs | 144 --- zxing.core/xx/BarcodeReaderGeneric.cs | 604 ------------ zxing.core/xx/BarcodeWriterGeneric.cs | 113 --- zxing.core/xx/BaseLuminanceSource.cs | 213 ---- zxing.core/xx/Binarizer.cs | 104 -- zxing.core/xx/BinaryBitmap.cs | 180 ---- zxing.core/xx/DecodeHintType.cs | 125 --- zxing.core/xx/Dimension.cs | 69 -- zxing.core/xx/EncodeHintType.cs | 131 --- zxing.core/xx/FormatException.cs | 48 - zxing.core/xx/IBarcodeReader.cs | 104 -- zxing.core/xx/IBarcodeReaderCustom.cs | 31 - zxing.core/xx/IBarcodeReaderGeneric.cs | 123 --- zxing.core/xx/IBarcodeWriter.cs | 107 -- zxing.core/xx/IBarcodeWriterGeneric.cs | 54 - zxing.core/xx/IMultipleBarcodeReader.cs | 105 -- .../xx/IMultipleBarcodeReaderGeneric.cs | 123 --- zxing.core/xx/InvertedLuminanceSource.cs | 154 --- zxing.core/xx/LuminanceSource.cs | 194 ---- zxing.core/xx/MultiFormatReader.cs | 228 ----- zxing.core/xx/MultiFormatWriter.cs | 82 -- zxing.core/xx/PlanarYUVLuminanceSource.cs | 260 ----- zxing.core/xx/RGB565LuminanceSource.cs | 61 -- zxing.core/xx/RGBLuminanceSource.cs | 314 ------ zxing.core/xx/Reader.cs | 59 -- zxing.core/xx/ReaderException.cs | 57 -- zxing.core/xx/Result.cs | 161 --- zxing.core/xx/ResultMetadataType.cs | 102 -- zxing.core/xx/ResultPoint.cs | 196 ---- zxing.core/xx/ResultPointCallback.cs | 26 - zxing.core/xx/SupportClass.cs | 175 ---- zxing.core/xx/Writer.cs | 51 - zxing.core/xx/WriterException.cs | 54 - zxing.core/xx/aztec/AztecDetectorResult.cs | 62 -- zxing.core/xx/aztec/AztecReader.cs | 123 --- zxing.core/xx/aztec/AztecResultMetadata.cs | 53 - zxing.core/xx/aztec/AztecWriter.cs | 164 ---- zxing.core/xx/aztec/decoder/Decoder.cs | 410 -------- zxing.core/xx/aztec/detector/Detector.cs | 690 ------------- zxing.core/xx/aztec/encoder/AztecCode.cs | 52 - .../xx/aztec/encoder/AztecEncodingOptions.cs | 86 -- .../xx/aztec/encoder/BinaryShiftToken.cs | 70 -- zxing.core/xx/aztec/encoder/Encoder.cs | 428 -------- .../xx/aztec/encoder/HighLevelEncoder.cs | 379 ------- zxing.core/xx/aztec/encoder/SimpleToken.cs | 48 - zxing.core/xx/aztec/encoder/State.cs | 197 ---- zxing.core/xx/aztec/encoder/Token.cs | 50 - zxing.core/xx/common/BitArray.cs | 488 --------- zxing.core/xx/common/BitMatrix.cs | 589 ----------- zxing.core/xx/common/BitSource.cs | 124 --- zxing.core/xx/common/CharacterSetECI.cs | 121 --- zxing.core/xx/common/DecoderResult.cs | 76 -- zxing.core/xx/common/DecodingOptions.cs | 485 --------- zxing.core/xx/common/DefaultGridSampler.cs | 82 -- zxing.core/xx/common/DetectorResult.cs | 39 - zxing.core/xx/common/ECI.cs | 66 -- zxing.core/xx/common/EncodingOptions.cs | 119 --- .../xx/common/GlobalHistogramBinarizer.cs | 243 ----- zxing.core/xx/common/GridSampler.cs | 197 ---- zxing.core/xx/common/HybridBinarizer.cs | 288 ------ zxing.core/xx/common/PerspectiveTransform.cs | 159 --- zxing.core/xx/common/StringUtils.cs | 262 ----- zxing.core/xx/common/detector/MathUtils.cs | 54 - .../detector/MonochromeRectangleDetector.cs | 252 ----- .../common/detector/WhiteRectangleDetector.cs | 433 -------- zxing.core/xx/common/reedsolomon/GenericGF.cs | 210 ---- .../xx/common/reedsolomon/GenericGFPoly.cs | 331 ------- .../common/reedsolomon/ReedSolomonDecoder.cs | 227 ----- .../common/reedsolomon/ReedSolomonEncoder.cs | 84 -- zxing.core/xx/datamatrix/DataMatrixReader.cs | 168 ---- zxing.core/xx/datamatrix/DataMatrixWriter.cs | 193 ---- .../xx/datamatrix/decoder/BitMatrixParser.cs | 519 ---------- zxing.core/xx/datamatrix/decoder/DataBlock.cs | 133 --- .../decoder/DecodedBitStreamParser.cs | 705 ------------- zxing.core/xx/datamatrix/decoder/Decoder.cs | 145 --- zxing.core/xx/datamatrix/decoder/Version.cs | 261 ----- zxing.core/xx/datamatrix/detector/Detector.cs | 487 --------- .../xx/datamatrix/encoder/ASCIIEncoder.cs | 95 -- .../xx/datamatrix/encoder/Base256Encoder.cs | 90 -- .../xx/datamatrix/encoder/C40Encoder.cs | 223 ----- .../encoder/DataMatrixSymbolInfo144.cs | 36 - .../encoder/DatamatrixEncodingOptions.cs | 139 --- .../xx/datamatrix/encoder/DefaultPlacement.cs | 222 ----- .../xx/datamatrix/encoder/EdifactEncoder.cs | 165 ---- .../xx/datamatrix/encoder/Encodation.cs | 31 - zxing.core/xx/datamatrix/encoder/Encoder.cs | 25 - .../xx/datamatrix/encoder/EncoderContext.cs | 186 ---- .../xx/datamatrix/encoder/ErrorCorrection.cs | 283 ------ .../xx/datamatrix/encoder/HighLevelEncoder.cs | 537 ---------- .../xx/datamatrix/encoder/SymbolInfo.cs | 258 ----- .../xx/datamatrix/encoder/SymbolShapeHint.cs | 29 - .../xx/datamatrix/encoder/TextEncoder.cs | 98 -- .../xx/datamatrix/encoder/X12Encoder.cs | 102 -- .../xx/documentation/zxing.doc.shfbproj | 79 -- .../documentation/zxing.net2.0.doc.shfbproj | 70 -- .../documentation/zxing.net3.5.doc.shfbproj | 70 -- .../documentation/zxing.portable.doc.shfbproj | 80 -- .../xx/documentation/zxing.sl4.doc.shfbproj | 70 -- .../xx/documentation/zxing.sl5.doc.shfbproj | 70 -- .../xx/documentation/zxing.unity.doc.shfbproj | 70 -- .../xx/documentation/zxing.wp7.0.doc.shfbproj | 70 -- .../xx/documentation/zxing.wp7.1.doc.shfbproj | 70 -- zxing.core/xx/imb/IMBReader.cs | 514 ---------- zxing.core/xx/maxicode/MaxiCodeReader.cs | 131 --- .../xx/maxicode/decoder/BitMatrixParser.cs | 93 -- .../decoder/DecodedBitStreamParser.cs | 218 ----- zxing.core/xx/maxicode/decoder/Decoder.cs | 124 --- zxing.core/xx/multi/ByQuadrantReader.cs | 128 --- .../xx/multi/GenericMultipleBarcodeReader.cs | 222 ----- zxing.core/xx/multi/MultipleBarcodeReader.cs | 43 - .../xx/multi/qrcode/QRCodeMultiReader.cs | 172 ---- .../xx/multi/qrcode/detector/MultiDetector.cs | 78 -- .../detector/MultiFinderPatternFinder.cs | 345 ------- zxing.core/xx/oned/CodaBarReader.cs | 412 -------- zxing.core/xx/oned/CodaBarWriter.cs | 158 --- zxing.core/xx/oned/Code128EncodingOptions.cs | 47 - zxing.core/xx/oned/Code128Reader.cs | 620 ------------ zxing.core/xx/oned/Code128Writer.cs | 233 ----- zxing.core/xx/oned/Code39Reader.cs | 433 -------- zxing.core/xx/oned/Code39Writer.cs | 119 --- zxing.core/xx/oned/Code93Reader.cs | 362 ------- zxing.core/xx/oned/EAN13Reader.cs | 168 ---- zxing.core/xx/oned/EAN13Writer.cs | 124 --- zxing.core/xx/oned/EAN8Reader.cs | 98 -- zxing.core/xx/oned/EAN8Writer.cs | 106 -- .../xx/oned/EANManufacturerOrgSupport.cs | 178 ---- zxing.core/xx/oned/ITFReader.cs | 424 -------- zxing.core/xx/oned/ITFWriter.cs | 105 -- zxing.core/xx/oned/MSIReader.cs | 356 ------- zxing.core/xx/oned/MSIWriter.cs | 101 -- zxing.core/xx/oned/MultiFormatOneDReader.cs | 148 --- zxing.core/xx/oned/MultiFormatUPCEANReader.cs | 142 --- zxing.core/xx/oned/OneDReader.cs | 369 ------- .../xx/oned/OneDimensionalCodeWriter.cs | 176 ---- zxing.core/xx/oned/PlesseyWriter.cs | 150 --- zxing.core/xx/oned/UPCAReader.cs | 118 --- zxing.core/xx/oned/UPCAWriter.cs | 94 -- zxing.core/xx/oned/UPCEANExtension2Support.cs | 122 --- zxing.core/xx/oned/UPCEANExtension5Support.cs | 208 ---- zxing.core/xx/oned/UPCEANExtensionSupport.cs | 39 - zxing.core/xx/oned/UPCEANReader.cs | 433 -------- zxing.core/xx/oned/UPCEANWriter.cs | 39 - zxing.core/xx/oned/UPCEReader.cs | 195 ---- zxing.core/xx/oned/rss/AbstractRSSReader.cs | 216 ---- zxing.core/xx/oned/rss/DataCharacter.cs | 85 -- zxing.core/xx/oned/rss/FinderPattern.cs | 86 -- zxing.core/xx/oned/rss/Pair.cs | 35 - zxing.core/xx/oned/rss/RSS14Reader.cs | 589 ----------- zxing.core/xx/oned/rss/RSSUtils.cs | 205 ---- .../xx/oned/rss/expanded/BitArrayBuilder.cs | 92 -- .../xx/oned/rss/expanded/ExpandedPair.cs | 92 -- .../xx/oned/rss/expanded/ExpandedRow.cs | 71 -- .../xx/oned/rss/expanded/RSSExpandedReader.cs | 924 ------------------ .../rss/expanded/decoders/AI013103decoder.cs | 52 - .../rss/expanded/decoders/AI01320xDecoder.cs | 63 -- .../rss/expanded/decoders/AI01392xDecoder.cs | 70 -- .../rss/expanded/decoders/AI01393xDecoder.cs | 83 -- .../expanded/decoders/AI013x0x1xDecoder.cs | 118 --- .../rss/expanded/decoders/AI013x0xDecoder.cs | 61 -- .../rss/expanded/decoders/AI01AndOtherAIs.cs | 61 -- .../oned/rss/expanded/decoders/AI01decoder.cs | 93 -- .../expanded/decoders/AI01weightDecoder.cs | 64 -- .../decoders/AbstractExpandedDecoder.cs | 114 --- .../rss/expanded/decoders/AnyAIDecoder.cs | 54 - .../expanded/decoders/BlockParsedResult.cs | 59 -- .../expanded/decoders/CurrentParsingState.cs | 95 -- .../oned/rss/expanded/decoders/DecodedChar.cs | 55 -- .../expanded/decoders/DecodedInformation.cs | 72 -- .../rss/expanded/decoders/DecodedNumeric.cs | 84 -- .../rss/expanded/decoders/DecodedObject.cs | 41 - .../oned/rss/expanded/decoders/FieldParser.cs | 305 ------ .../expanded/decoders/GeneralAppIdDecoder.cs | 564 ----------- zxing.core/xx/pdf417/PDF417Common.cs | 493 ---------- zxing.core/xx/pdf417/PDF417Reader.cs | 202 ---- zxing.core/xx/pdf417/PDF417ResultMetadata.cs | 30 - zxing.core/xx/pdf417/PDF417Writer.cs | 229 ----- .../xx/pdf417/decoder/BarcodeMetadata.cs | 40 - zxing.core/xx/pdf417/decoder/BarcodeValue.cs | 80 -- zxing.core/xx/pdf417/decoder/BoundingBox.cs | 218 ----- zxing.core/xx/pdf417/decoder/Codeword.cs | 97 -- .../pdf417/decoder/DecodedBitStreamParser.cs | 808 --------------- .../xx/pdf417/decoder/DetectionResult.cs | 379 ------- .../pdf417/decoder/DetectionResultColumn.cs | 161 --- .../DetectionResultRowIndicatorColumn.cs | 376 ------- .../pdf417/decoder/PDF417CodewordDecoder.cs | 170 ---- .../pdf417/decoder/PDF417ScanningDecoder.cs | 916 ----------------- .../xx/pdf417/decoder/ec/ErrorCorrection.cs | 241 ----- zxing.core/xx/pdf417/decoder/ec/ModulusGF.cs | 121 --- .../xx/pdf417/decoder/ec/ModulusPoly.cs | 366 ------- zxing.core/xx/pdf417/detector/Detector.cs | 429 -------- .../pdf417/detector/PDF417DetectorResult.cs | 43 - zxing.core/xx/pdf417/encoder/BarcodeMatrix.cs | 95 -- zxing.core/xx/pdf417/encoder/BarcodeRow.cs | 96 -- zxing.core/xx/pdf417/encoder/Compaction.cs | 44 - zxing.core/xx/pdf417/encoder/Dimensions.cs | 77 -- zxing.core/xx/pdf417/encoder/PDF417.cs | 840 ---------------- .../pdf417/encoder/PDF417EncodingOptions.cs | 154 --- .../pdf417/encoder/PDF417ErrorCorrection.cs | 249 ----- .../pdf417/encoder/PDF417HighLevelEncoder.cs | 775 --------------- .../presentation/BarcodeReader.Extensions.cs | 50 - zxing.core/xx/presentation/BarcodeReader.cs | 74 -- .../presentation/BarcodeWriter.Extensions.cs | 41 - zxing.core/xx/presentation/BarcodeWriter.cs | 36 - .../BarcodeWriterGeometry.Extensions.cs | 41 - .../xx/presentation/BarcodeWriterGeometry.cs | 37 - zxing.core/xx/project.json | 32 - zxing.core/xx/qrcode/QRCodeReader.cs | 258 ----- zxing.core/xx/qrcode/QRCodeWriter.cs | 141 --- .../xx/qrcode/decoder/BitMatrixParser.cs | 281 ------ zxing.core/xx/qrcode/decoder/DataBlock.cs | 146 --- zxing.core/xx/qrcode/decoder/DataMask.cs | 165 ---- .../qrcode/decoder/DecodedBitStreamParser.cs | 524 ---------- zxing.core/xx/qrcode/decoder/Decoder.cs | 195 ---- .../xx/qrcode/decoder/ErrorCorrectionLevel.cs | 109 --- .../xx/qrcode/decoder/FormatInformation.cs | 197 ---- zxing.core/xx/qrcode/decoder/Mode.cs | 179 ---- .../qrcode/decoder/QRCodeDecoderMetaData.cs | 60 -- zxing.core/xx/qrcode/decoder/Version.cs | 685 ------------- .../xx/qrcode/detector/AlignmentPattern.cs | 68 -- .../qrcode/detector/AlignmentPatternFinder.cs | 324 ------ zxing.core/xx/qrcode/detector/Detector.cs | 434 -------- .../xx/qrcode/detector/FinderPattern.cs | 107 -- .../xx/qrcode/detector/FinderPatternFinder.cs | 813 --------------- .../xx/qrcode/detector/FinderPatternInfo.cs | 74 -- zxing.core/xx/qrcode/encoder/BlockPair.cs | 40 - zxing.core/xx/qrcode/encoder/ByteMatrix.cs | 148 --- zxing.core/xx/qrcode/encoder/Encoder.cs | 758 -------------- zxing.core/xx/qrcode/encoder/MaskUtil.cs | 271 ----- zxing.core/xx/qrcode/encoder/MatrixUtil.cs | 604 ------------ zxing.core/xx/qrcode/encoder/QRCode.cs | 125 --- .../qrcode/encoder/QrCodeEncodingOptions.cs | 109 --- zxing.core/xx/renderer/IBarcodeRenderer.cs | 54 - zxing.core/xx/renderer/PixelData.cs | 119 --- zxing.core/xx/renderer/RawRenderer.cs | 168 ---- zxing.core/zxing.core/zxing.core.csproj | 2 +- 242 files changed, 25 insertions(+), 46376 deletions(-) create mode 100644 AIStudio.Wpf.ADiagram/zxing.core.dll delete mode 100644 zxing.core/xx/BarcodeFormat.cs delete mode 100644 zxing.core/xx/BarcodeReader.Bitmap.cs delete mode 100644 zxing.core/xx/BarcodeReaderCustom.cs delete mode 100644 zxing.core/xx/BarcodeReaderGeneric.cs delete mode 100644 zxing.core/xx/BarcodeWriterGeneric.cs delete mode 100644 zxing.core/xx/BaseLuminanceSource.cs delete mode 100644 zxing.core/xx/Binarizer.cs delete mode 100644 zxing.core/xx/BinaryBitmap.cs delete mode 100644 zxing.core/xx/DecodeHintType.cs delete mode 100644 zxing.core/xx/Dimension.cs delete mode 100644 zxing.core/xx/EncodeHintType.cs delete mode 100644 zxing.core/xx/FormatException.cs delete mode 100644 zxing.core/xx/IBarcodeReader.cs delete mode 100644 zxing.core/xx/IBarcodeReaderCustom.cs delete mode 100644 zxing.core/xx/IBarcodeReaderGeneric.cs delete mode 100644 zxing.core/xx/IBarcodeWriter.cs delete mode 100644 zxing.core/xx/IBarcodeWriterGeneric.cs delete mode 100644 zxing.core/xx/IMultipleBarcodeReader.cs delete mode 100644 zxing.core/xx/IMultipleBarcodeReaderGeneric.cs delete mode 100644 zxing.core/xx/InvertedLuminanceSource.cs delete mode 100644 zxing.core/xx/LuminanceSource.cs delete mode 100644 zxing.core/xx/MultiFormatReader.cs delete mode 100644 zxing.core/xx/MultiFormatWriter.cs delete mode 100644 zxing.core/xx/PlanarYUVLuminanceSource.cs delete mode 100644 zxing.core/xx/RGB565LuminanceSource.cs delete mode 100644 zxing.core/xx/RGBLuminanceSource.cs delete mode 100644 zxing.core/xx/Reader.cs delete mode 100644 zxing.core/xx/ReaderException.cs delete mode 100644 zxing.core/xx/Result.cs delete mode 100644 zxing.core/xx/ResultMetadataType.cs delete mode 100644 zxing.core/xx/ResultPoint.cs delete mode 100644 zxing.core/xx/ResultPointCallback.cs delete mode 100644 zxing.core/xx/SupportClass.cs delete mode 100644 zxing.core/xx/Writer.cs delete mode 100644 zxing.core/xx/WriterException.cs delete mode 100644 zxing.core/xx/aztec/AztecDetectorResult.cs delete mode 100644 zxing.core/xx/aztec/AztecReader.cs delete mode 100644 zxing.core/xx/aztec/AztecResultMetadata.cs delete mode 100644 zxing.core/xx/aztec/AztecWriter.cs delete mode 100644 zxing.core/xx/aztec/decoder/Decoder.cs delete mode 100644 zxing.core/xx/aztec/detector/Detector.cs delete mode 100644 zxing.core/xx/aztec/encoder/AztecCode.cs delete mode 100644 zxing.core/xx/aztec/encoder/AztecEncodingOptions.cs delete mode 100644 zxing.core/xx/aztec/encoder/BinaryShiftToken.cs delete mode 100644 zxing.core/xx/aztec/encoder/Encoder.cs delete mode 100644 zxing.core/xx/aztec/encoder/HighLevelEncoder.cs delete mode 100644 zxing.core/xx/aztec/encoder/SimpleToken.cs delete mode 100644 zxing.core/xx/aztec/encoder/State.cs delete mode 100644 zxing.core/xx/aztec/encoder/Token.cs delete mode 100644 zxing.core/xx/common/BitArray.cs delete mode 100644 zxing.core/xx/common/BitMatrix.cs delete mode 100644 zxing.core/xx/common/BitSource.cs delete mode 100644 zxing.core/xx/common/CharacterSetECI.cs delete mode 100644 zxing.core/xx/common/DecoderResult.cs delete mode 100644 zxing.core/xx/common/DecodingOptions.cs delete mode 100644 zxing.core/xx/common/DefaultGridSampler.cs delete mode 100644 zxing.core/xx/common/DetectorResult.cs delete mode 100644 zxing.core/xx/common/ECI.cs delete mode 100644 zxing.core/xx/common/EncodingOptions.cs delete mode 100644 zxing.core/xx/common/GlobalHistogramBinarizer.cs delete mode 100644 zxing.core/xx/common/GridSampler.cs delete mode 100644 zxing.core/xx/common/HybridBinarizer.cs delete mode 100644 zxing.core/xx/common/PerspectiveTransform.cs delete mode 100644 zxing.core/xx/common/StringUtils.cs delete mode 100644 zxing.core/xx/common/detector/MathUtils.cs delete mode 100644 zxing.core/xx/common/detector/MonochromeRectangleDetector.cs delete mode 100644 zxing.core/xx/common/detector/WhiteRectangleDetector.cs delete mode 100644 zxing.core/xx/common/reedsolomon/GenericGF.cs delete mode 100644 zxing.core/xx/common/reedsolomon/GenericGFPoly.cs delete mode 100644 zxing.core/xx/common/reedsolomon/ReedSolomonDecoder.cs delete mode 100644 zxing.core/xx/common/reedsolomon/ReedSolomonEncoder.cs delete mode 100644 zxing.core/xx/datamatrix/DataMatrixReader.cs delete mode 100644 zxing.core/xx/datamatrix/DataMatrixWriter.cs delete mode 100644 zxing.core/xx/datamatrix/decoder/BitMatrixParser.cs delete mode 100644 zxing.core/xx/datamatrix/decoder/DataBlock.cs delete mode 100644 zxing.core/xx/datamatrix/decoder/DecodedBitStreamParser.cs delete mode 100644 zxing.core/xx/datamatrix/decoder/Decoder.cs delete mode 100644 zxing.core/xx/datamatrix/decoder/Version.cs delete mode 100644 zxing.core/xx/datamatrix/detector/Detector.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/ASCIIEncoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/Base256Encoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/C40Encoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/DataMatrixSymbolInfo144.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/DatamatrixEncodingOptions.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/DefaultPlacement.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/EdifactEncoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/Encodation.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/Encoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/EncoderContext.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/ErrorCorrection.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/HighLevelEncoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/SymbolInfo.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/SymbolShapeHint.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/TextEncoder.cs delete mode 100644 zxing.core/xx/datamatrix/encoder/X12Encoder.cs delete mode 100644 zxing.core/xx/documentation/zxing.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.net2.0.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.net3.5.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.portable.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.sl4.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.sl5.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.unity.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.wp7.0.doc.shfbproj delete mode 100644 zxing.core/xx/documentation/zxing.wp7.1.doc.shfbproj delete mode 100644 zxing.core/xx/imb/IMBReader.cs delete mode 100644 zxing.core/xx/maxicode/MaxiCodeReader.cs delete mode 100644 zxing.core/xx/maxicode/decoder/BitMatrixParser.cs delete mode 100644 zxing.core/xx/maxicode/decoder/DecodedBitStreamParser.cs delete mode 100644 zxing.core/xx/maxicode/decoder/Decoder.cs delete mode 100644 zxing.core/xx/multi/ByQuadrantReader.cs delete mode 100644 zxing.core/xx/multi/GenericMultipleBarcodeReader.cs delete mode 100644 zxing.core/xx/multi/MultipleBarcodeReader.cs delete mode 100644 zxing.core/xx/multi/qrcode/QRCodeMultiReader.cs delete mode 100644 zxing.core/xx/multi/qrcode/detector/MultiDetector.cs delete mode 100644 zxing.core/xx/multi/qrcode/detector/MultiFinderPatternFinder.cs delete mode 100644 zxing.core/xx/oned/CodaBarReader.cs delete mode 100644 zxing.core/xx/oned/CodaBarWriter.cs delete mode 100644 zxing.core/xx/oned/Code128EncodingOptions.cs delete mode 100644 zxing.core/xx/oned/Code128Reader.cs delete mode 100644 zxing.core/xx/oned/Code128Writer.cs delete mode 100644 zxing.core/xx/oned/Code39Reader.cs delete mode 100644 zxing.core/xx/oned/Code39Writer.cs delete mode 100644 zxing.core/xx/oned/Code93Reader.cs delete mode 100644 zxing.core/xx/oned/EAN13Reader.cs delete mode 100644 zxing.core/xx/oned/EAN13Writer.cs delete mode 100644 zxing.core/xx/oned/EAN8Reader.cs delete mode 100644 zxing.core/xx/oned/EAN8Writer.cs delete mode 100644 zxing.core/xx/oned/EANManufacturerOrgSupport.cs delete mode 100644 zxing.core/xx/oned/ITFReader.cs delete mode 100644 zxing.core/xx/oned/ITFWriter.cs delete mode 100644 zxing.core/xx/oned/MSIReader.cs delete mode 100644 zxing.core/xx/oned/MSIWriter.cs delete mode 100644 zxing.core/xx/oned/MultiFormatOneDReader.cs delete mode 100644 zxing.core/xx/oned/MultiFormatUPCEANReader.cs delete mode 100644 zxing.core/xx/oned/OneDReader.cs delete mode 100644 zxing.core/xx/oned/OneDimensionalCodeWriter.cs delete mode 100644 zxing.core/xx/oned/PlesseyWriter.cs delete mode 100644 zxing.core/xx/oned/UPCAReader.cs delete mode 100644 zxing.core/xx/oned/UPCAWriter.cs delete mode 100644 zxing.core/xx/oned/UPCEANExtension2Support.cs delete mode 100644 zxing.core/xx/oned/UPCEANExtension5Support.cs delete mode 100644 zxing.core/xx/oned/UPCEANExtensionSupport.cs delete mode 100644 zxing.core/xx/oned/UPCEANReader.cs delete mode 100644 zxing.core/xx/oned/UPCEANWriter.cs delete mode 100644 zxing.core/xx/oned/UPCEReader.cs delete mode 100644 zxing.core/xx/oned/rss/AbstractRSSReader.cs delete mode 100644 zxing.core/xx/oned/rss/DataCharacter.cs delete mode 100644 zxing.core/xx/oned/rss/FinderPattern.cs delete mode 100644 zxing.core/xx/oned/rss/Pair.cs delete mode 100644 zxing.core/xx/oned/rss/RSS14Reader.cs delete mode 100644 zxing.core/xx/oned/rss/RSSUtils.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/BitArrayBuilder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/ExpandedPair.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/ExpandedRow.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/RSSExpandedReader.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI013103decoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01320xDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01392xDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01393xDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI013x0x1xDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI013x0xDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01AndOtherAIs.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01decoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AI01weightDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AbstractExpandedDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/AnyAIDecoder.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/BlockParsedResult.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/CurrentParsingState.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/DecodedChar.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/DecodedInformation.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/DecodedNumeric.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/DecodedObject.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/FieldParser.cs delete mode 100644 zxing.core/xx/oned/rss/expanded/decoders/GeneralAppIdDecoder.cs delete mode 100644 zxing.core/xx/pdf417/PDF417Common.cs delete mode 100644 zxing.core/xx/pdf417/PDF417Reader.cs delete mode 100644 zxing.core/xx/pdf417/PDF417ResultMetadata.cs delete mode 100644 zxing.core/xx/pdf417/PDF417Writer.cs delete mode 100644 zxing.core/xx/pdf417/decoder/BarcodeMetadata.cs delete mode 100644 zxing.core/xx/pdf417/decoder/BarcodeValue.cs delete mode 100644 zxing.core/xx/pdf417/decoder/BoundingBox.cs delete mode 100644 zxing.core/xx/pdf417/decoder/Codeword.cs delete mode 100644 zxing.core/xx/pdf417/decoder/DecodedBitStreamParser.cs delete mode 100644 zxing.core/xx/pdf417/decoder/DetectionResult.cs delete mode 100644 zxing.core/xx/pdf417/decoder/DetectionResultColumn.cs delete mode 100644 zxing.core/xx/pdf417/decoder/DetectionResultRowIndicatorColumn.cs delete mode 100644 zxing.core/xx/pdf417/decoder/PDF417CodewordDecoder.cs delete mode 100644 zxing.core/xx/pdf417/decoder/PDF417ScanningDecoder.cs delete mode 100644 zxing.core/xx/pdf417/decoder/ec/ErrorCorrection.cs delete mode 100644 zxing.core/xx/pdf417/decoder/ec/ModulusGF.cs delete mode 100644 zxing.core/xx/pdf417/decoder/ec/ModulusPoly.cs delete mode 100644 zxing.core/xx/pdf417/detector/Detector.cs delete mode 100644 zxing.core/xx/pdf417/detector/PDF417DetectorResult.cs delete mode 100644 zxing.core/xx/pdf417/encoder/BarcodeMatrix.cs delete mode 100644 zxing.core/xx/pdf417/encoder/BarcodeRow.cs delete mode 100644 zxing.core/xx/pdf417/encoder/Compaction.cs delete mode 100644 zxing.core/xx/pdf417/encoder/Dimensions.cs delete mode 100644 zxing.core/xx/pdf417/encoder/PDF417.cs delete mode 100644 zxing.core/xx/pdf417/encoder/PDF417EncodingOptions.cs delete mode 100644 zxing.core/xx/pdf417/encoder/PDF417ErrorCorrection.cs delete mode 100644 zxing.core/xx/pdf417/encoder/PDF417HighLevelEncoder.cs delete mode 100644 zxing.core/xx/presentation/BarcodeReader.Extensions.cs delete mode 100644 zxing.core/xx/presentation/BarcodeReader.cs delete mode 100644 zxing.core/xx/presentation/BarcodeWriter.Extensions.cs delete mode 100644 zxing.core/xx/presentation/BarcodeWriter.cs delete mode 100644 zxing.core/xx/presentation/BarcodeWriterGeometry.Extensions.cs delete mode 100644 zxing.core/xx/presentation/BarcodeWriterGeometry.cs delete mode 100644 zxing.core/xx/project.json delete mode 100644 zxing.core/xx/qrcode/QRCodeReader.cs delete mode 100644 zxing.core/xx/qrcode/QRCodeWriter.cs delete mode 100644 zxing.core/xx/qrcode/decoder/BitMatrixParser.cs delete mode 100644 zxing.core/xx/qrcode/decoder/DataBlock.cs delete mode 100644 zxing.core/xx/qrcode/decoder/DataMask.cs delete mode 100644 zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs delete mode 100644 zxing.core/xx/qrcode/decoder/Decoder.cs delete mode 100644 zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs delete mode 100644 zxing.core/xx/qrcode/decoder/FormatInformation.cs delete mode 100644 zxing.core/xx/qrcode/decoder/Mode.cs delete mode 100644 zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs delete mode 100644 zxing.core/xx/qrcode/decoder/Version.cs delete mode 100644 zxing.core/xx/qrcode/detector/AlignmentPattern.cs delete mode 100644 zxing.core/xx/qrcode/detector/AlignmentPatternFinder.cs delete mode 100644 zxing.core/xx/qrcode/detector/Detector.cs delete mode 100644 zxing.core/xx/qrcode/detector/FinderPattern.cs delete mode 100644 zxing.core/xx/qrcode/detector/FinderPatternFinder.cs delete mode 100644 zxing.core/xx/qrcode/detector/FinderPatternInfo.cs delete mode 100644 zxing.core/xx/qrcode/encoder/BlockPair.cs delete mode 100644 zxing.core/xx/qrcode/encoder/ByteMatrix.cs delete mode 100644 zxing.core/xx/qrcode/encoder/Encoder.cs delete mode 100644 zxing.core/xx/qrcode/encoder/MaskUtil.cs delete mode 100644 zxing.core/xx/qrcode/encoder/MatrixUtil.cs delete mode 100644 zxing.core/xx/qrcode/encoder/QRCode.cs delete mode 100644 zxing.core/xx/qrcode/encoder/QrCodeEncodingOptions.cs delete mode 100644 zxing.core/xx/renderer/IBarcodeRenderer.cs delete mode 100644 zxing.core/xx/renderer/PixelData.cs delete mode 100644 zxing.core/xx/renderer/RawRenderer.cs diff --git a/AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj b/AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj index 082b033..742acc4 100644 --- a/AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj +++ b/AIStudio.Wpf.ADiagram/AIStudio.Wpf.ADiagram.csproj @@ -2,7 +2,7 @@ WinExe - net472 + netcoreapp3.1 true @@ -121,20 +121,26 @@ + + + - + + - - - - + + + + + zxing.core.dll + diff --git a/AIStudio.Wpf.ADiagram/ViewModels/MainWindowViewModel.cs b/AIStudio.Wpf.ADiagram/ViewModels/MainWindowViewModel.cs index 8e3b107..59f7cc6 100644 --- a/AIStudio.Wpf.ADiagram/ViewModels/MainWindowViewModel.cs +++ b/AIStudio.Wpf.ADiagram/ViewModels/MainWindowViewModel.cs @@ -1154,18 +1154,18 @@ namespace AIStudio.Wpf.ADiagram.ViewModels List result = new List(); for (var i = 0; i < count; i++) { - var colors = ColorGallery.GetGradient(ColorGallery.StandardThemeColors[i], 10); - for (var j = 9; j >= 0; j--) - { - result.Add(colors[j]); - } + //var colors = ColorGallery.GetGradient(ColorGallery.StandardThemeColors[i], 10); + //for (var j = 9; j >= 0; j--) + //{ + // result.Add(colors[j]); + //} } { - var colors = ColorGallery.GetGradient(Colors.Black, 10); - for (var j = 9; j >= 0; j--) - { - result.Add(colors[j]); - } + //var colors = ColorGallery.GetGradient(Colors.Black, 10); + //for (var j = 9; j >= 0; j--) + //{ + // result.Add(colors[j]); + //} } return result.ToArray(); } diff --git a/AIStudio.Wpf.ADiagram/zxing.core.dll b/AIStudio.Wpf.ADiagram/zxing.core.dll new file mode 100644 index 0000000000000000000000000000000000000000..1f3303ca34dc17bb89dbd465a5baf4e94f5e6bdc GIT binary patch literal 554496 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⪚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%0Am)JAfl~Q~2Fh#0{!|oFv4TV) z9Z(cfy=o;^&V?Zzh{7t$rnDap1hIt=LkhPjGX*epaq`*(B5*k6l-UCF0$gzT%a+AL zjADjrJ9%FN&1OWupJpqE4dQ(bA}Q80!HN7YpQZ0(*Ffr5?Y}hj{W5*e>=XDkmyYbZ zX15Ub_DZ~*MCZTEsp8Ju%sy3Ni%R=Gm9Fx-(lKWetya~&($$QvbUV{C`_z(N>1vEm z&jyd7JtjZNAwPknWpig7Tzonh?vQ;N-|pvxP*f5kn+Lg^PUhShyeVk1l+Puy6xRnQ zLvNL_my7E-fjY3p5-rWv|EfxyUjkT^{tAyS#N{P@t(Gd@rwcm~Pbj~hDO{@&HD17M z3Rf%#Lie!BnLE$Q`D@yP)d^$D%O6}lDuv9*f!WL`MmvSQ#l5@wN*mtw&NEItu2$M` z`fH!=tTEUgRI=Nf(jZvJl8;5|-xoXvJ30TpphCIWCWlWiX&H0*bL<1WGbuR^c4v`_ zp&`8W?Gg!N*$PfoArl;f_Bt9-{;8QNSha%>3u-*?bGx5M}HWYN2&NxpU4!Gm~q0a5b|}*^Av^%hGud z^&rGCdp0PRiYa&AOQKGSjv5HxW9RxFz$(VFxJNoq@=08FEDMLK%W`xTx?gJjCE0aK z=>+YEJtXOMBw3)|WJ_ruAw_w=vmq>dGqCM{Y^*!OjXmu+>vk`5$hD9;box9D5HGBw zuIeBFtgv!Ro%itt8$?^QS^LZBO*c3p%bn{qG>r;RN0yv@>F4jRmZspMc4&ot-J}X) zUnnu#c|RrL>+k(l>cJzP;QUoC^F!46dm;GouEx!v#|Q!)K1R899Yo2uI`-6H(s(h+ z-M41>yxQoM(U0cptbOjBZ9egWO0(>1*4AR2tYUo^1Af~58Mt=dpeIgJP@J&C$NwtG zwlK0y%m-!0ogKrTVAmZayHfyYJ`sEsW`0N;GTA&kl?%GJw{sB$HAq8feSpqoE^iVee#Hiq6iKZ5YS+DYCqCwz%-;e5UoN99)PJ*x@=W zt^i1@TTD_r$XnTmBSx^^(3e&lxVYU|Sa`c`Ano%b93E7TZpyN}b^^s4!Qm+bPDR#h z*yc6ba5YiP`HOkwfkXTW2Qf@`&k}^fQQ$S!qzqf`3i7<)KEV6!tE&a$KkO*av=(Se zEz`PE-9ZKL9DU|9t$BT7`993;w!kY0drP|{kJI>{ID4t=Vj7ezp;-};SY3gT>MR;F z^v(wpq+tE>G=yuz&QxCZk!!HdX@tm&^L+58_};lU1%$kYR9R{vNsUcs=q%O9w)=Td zs7$`tdOZ!((D|3(`e!7q#Lk+ns!-c=L+je>*^<1Wqdi#;*Bvmw7Waj~aqENYnoL*s}Osk9XAK^ZmE2;g;~Io#FIs zxHVO`q?M9MA}J3zrL-41v}z?83O3<2%<{6%jG1Ze%OUU*F;?KV0cYke0gveNmyxxU zhw^0%!ljzv8s(nB^CB{xd!ZDu30oYrFJpD-acL?3o`4wR1sWnzfs{rFVqVo?5aj#l)wI&6ew|b*fFY0#9{s%PIW3EE~2~jZ36`#yv_uFI?&bkZ%Ilb!wMp0kPTg`Al3t1Wh6;Hbi?uQ3L~oA3%_Nh=wkU8CGGvjlQW0^XvT4f}atp80 z=%wU)nE-iX04Jb%79nvL8%Is-d$mxU%@LfTaZy%Y;H$Vy*Vr3!a>2$NeqQg7vvsq^ zww!`>A}?TA3q@9lgEmlL`Pz&r@FNa6h9F`sgc1naUPefTP=ty;o>HomBE#0W6a{e- zC5=j{fS`+ZS1D4t_)srST;-h3nUf*Y10HB~wa*Phpt0l4yFxq_I%loK1^hRlRpjvaM; zS8Q6{vCw)xGYn?Ih#Ua`(lAWu1S`r~dx}y@Ll|g7Z&b>$Zb5XHQZh?xm7=4^9XKsl z3g-!%rtWx}LU1zUqW>bz@#`Xe>XIm8q-A|;oGMxs;l3wM70rxrvvI1ZS%mwEI8_um z!u?5{Dq4xb-+T6mBYT{@-2-??3c++{JSF7 z?ADn9%?GQijK`mQxyfFBk@-4GX>R&+BXg}cGO4g>Q{(075doCknDZZzH<4}hagN&v zBb{6PoXe$4k!bdlSWSHq>If?1nvQx)32VOUQCBrD^vGQRl(42(-DEZVZ=B~)qB&Z! zQ-!zJs4PK^#iAMD8xJYBBqQcg7caS}7M9RP9bkh&HMXyYv@0`1z)&;i#L#yV@Y>5^0lvQ>UsL>)e>S+;CnqsHa0eK=fferKN|`iO+pZ@KIs1UMp~FXoS4-zAnT-2B*ZE&0 zb>6~^i4j(XD5MlKwb@s|qR9DA)@umTg=lwGAsc5rly6qi)ooV0+;ZTJRL8!f+$%Ra z)0E{dn;NUM0*(WF`jfn{I`fa(-5DGgtaxU+^X9ntK8hzuEYsZJT_)ZMv*JbCA6UGf zZ_k-AsnegNEY~k*C5{iOOK@!uDSS|c!+8$Ig-a3sz`_SPo!d0rcIIr{ zH0NJoz|o8q)D0Y)zt(``nbzCLIkm=pnjj|#Pkz+{pwcf)YSC4(&<0^39eKzu~GX0p#H-*8&2UYYcRAG3b zzb=`rg%6S5dLKn<%KqLy^ZT#X{EjHBhyh-6+U{MLv0>LirlL^3``hB4oF9SGJi$?En12RTab`~w-0LGM2R zl0*&vNK+8C_q%MZf8l4feYE@KksDpe$TPZ;bHla>C0J6;KGVL}>ib7jo84VLNIR%I z4B9Q`&7o#npHOv*xlXB>_Ml5HcK%V>@SbY_n=e!3Rdica-g(FF&9rVOvnQ;InLU?r zb$--vvpD3o{uvB#py*SNq|>dBDhFg-vJl;DWO$NqPi7ij5M65=#8m|qmTb(~o6;kV zrS(oVHF<&y(Q}+;J;s{;G3108#L!o1Z=N8>9d}C#M7DR$dPNr!;%*7Or zE4B48nx}!+5OR4u*^j!eKviD>2jbb;g$G0Tjl;Hr15?=U8O&`k}qDXHI3fq3JZJUP6h=oa8Jw9vL`oSqw>U|m5qmv zJR@I5KsosjBnBUOgof=#JOuF}qhtS8uEF$7lV5J51&*Ssyjq^Y&HzL5>-W$uW>LB& ziye4k*M!u{o%b_p(X+R!173W$8TtUJ1R6~L)C;*7vv-dLGQa6}mx{Y>ZPT?=Tz-et zx|LF*>A*x)3z7V)AX{H}FTl>f*c4cj&x7_^2byHiZ>H_6JhgpBMijUlxMk!gUpvi@ ziA=BAm%G`B$PA4F-3}C?<$7+zAJ{l&Wn26Ok<7h&(c znA!z|fK@AWJ_UxFVC%sxU6ukfu>BHF`$%?uLa^mBJBF?Op8=oc%$mq{{+0ZdnL{d} z^J%_UVfT=xe}=EM_A|?!&+-M`7we*{{X7GJZrs|B=qiWkU#D0+^Lcnb;MV*v(fmSJ z^JP!z6zcS}4_SQK$>OiOyNa7<*>|#JOt{uj^=`}!4Q2aN=~P!ZsYvm*s>PNLP6(zi zb^Xi)lflCEPF|l0%E5a-9L1V)`c5`+L~lHuF9t7V6xf5LxA5?Sq__T!k7}{=1wJJG zb*2p_j6L5oooeu@#2M@ITr|&yl8J(ABSX9`TEYm%rv7#a*h@O`uxgw2AXSE^pn7*Mr`30JLLCrqG+}PaCvKf9BjiVL$ zWA_(1$1(xd_W{fv{c-^)p#5C8ow*r`Ftb170y3yH*`g^;rf8ANis;9`QwEz9dTy;y z)bLd(z;q~i)w&ZIM&e(Zxt=0W2NYWW3dCsxbf66d+04G{ zHQonW9|wYo8SB3f7FMG({XPWrg+}YsKqA7d(PB}Q+K+dQnOc)`U$AL3GWt%CB`}k8 zNQRjBRI8M_E5+<6iVN>hiOw;DhUv_DJ$EChh1TPP$tol3WOb|%u52} z=SJGyDxKbL^}dXnv3E`lWwz#rQfE#vaL*UWqHHq2tBG1{B;h1fg}N`HC~JdgS`zhW zL3|OCQ5q@`Pjlv0`h!rkW*H-Y6y21Dxku-(-5nVV1Sas|Sdm~KgZ}?OP#2b$^l8T9jTHQph}+%tG!gJo}p|W(pE59601YONabnII_!L zN&c$IUUBvfp#9ikntJt|s8a}EQR2`b(*g2P-&T|3wIBOP{Q6DjOC2p(#H57&ft}I7 zXi8-o;umw(FYCqu!qJ;!S}DTgM!k~kwt(#R6%^J>cDuG)9$Pw8EOm)uwT6#IM#(Xt zHGBm#80((;Z78RDDxc&@&kn86{0brN3d$$RFAe8Ta0sH|lux6kd>T10G*$>l3ZVq# z;b=I9@@WJrHxiCAs-q#F%p~GUluusew1G%wC+#APiQ5a2Ld^7fSDdt~uUMLE4ROMi zc5OI#!wrvtXL1rwwG!_cdbdFD9zHB+Ct4`P6wHoSk>ls-#R%yq&%=9ub9{8o4fDRJsEuqNoaC}kabu1WqP znOKF&W~1r3Cc~zL=9A$>*i7_XmRd+sm3dYoTc_vR6mHtSgH@kthON)iQ5ASZc!ZmQ zCsN;7&e+7A`RVKkYjd_gH=S+hiv%l((P93a60C(mru>ClpP`r`X`a>vi?3vXg~fv- zVQc4sq0J#jRO>*vnV?lzo1rOdNmCYtEy`+zEidS3hwbSPB-*hlVniq9PKVP|lc{p2 zcJe;a&=%8{O&tigP_$V1DN39|ndHnCj|z{P{)pa)mrFl^v`|!`I!94e@`|dh;Z`Hx z_4Y+gU{X}|ExuH3?>jJ5Ls38uieW8+NgH~od^ zdrmAL#2tcNG$avpsUMK|J0*tBEvX+Uyf~YMFrhY)rlg3*L`#97BNAjvrrAp?@p0BT z0(en$E)6A5(g}+&^H?ov8iQg%rrX{ZM39ysw7}^Aibl{av-9~7ip(r%d7N2fLtIce zqsyLJ+kPt5DgeheUw)+Z2xpLyIkki|#bwH|?$Ya;G6pz6($Gi+61wpIQc8p~uOVki zuLDf2=XjFRLs#6e{emvFgHuVAjZE~`NH~oM8i~Aj&`=>gH4;t(vVuk;gslqkqH0zb zJ_mu?FHX^2jQ8ta;tqgXc+i#D9^F0sT>~^=`y5OIpxTD#~`Bs^uG{ zULNCWDX(3oc$kf#Da8Zc@vfYdD;z9Mlol%l@cT7$st{7AFoxiO7!P#NjCMqEtm|qQsA;66;aosyJ~;Cqx`k-6?@tUfz+D zK&y;#;~jrU@Zx#BJ4suIrfs)4);nI9 zBu>Qk=#%N0ZB{+%cVg5fNntk6C$iZ6e?dYfyRa^gljG|IjAfC?E}`lBgy8R}?(WK+ zUFkxOWt8Z;1McsnH;hMg(z1p7bjs#t{sL%bBw`+o(?n9X@GA#>zMze<7Aiv+G+mH% zg&Nx;c}-z_%K*2Pg@1RbX9{(JVN=>e0ze5Sk#r8PCMD-eL97Aw8u-Qt((6S zj7(bgZH@v9QxMy$h^n_4A?v+#087K|L3aLEU^^>6==7=py8)*M$l6q=kewW!Qk-rj zH@O;_yV-nWeKw!n5Ea8w&+jn#ZFleq^1VpwE1Trwow#bd;u0|Z2#VIW|8Q*sU-HCj z`9wG*UgJ&xW}Y#z_%|%YS>0-kKgzYAy>O!>`-D@9&em>upMMi!pZ==AaFhQ|dW@#cRTm$;#7XCEsJ*;Q9N7jK}MQCm$8 zE`~Wja}Rxr8f-Y}MyE0@9wdL%_#+>x@yj#LF8+0ty|07|zxW*qZmL*?L>8Z=X2sHV zl~1SBac7`uX=(L*=UIsnv)k) z`Lhdm^u7y_UGTwo*~Z!&$ZWJ4WaGKP7R=@#nj<%NDY%~_T*gv!n1cH?F8ZD^`+d{X zRjEO1iZgf8W}It2Ayk(_;B+d|Ljj<-fqF!&4@fG{DW_B~43n^^)erHnE#w zKc{LcuidkGY&@Gni)V9L9ygn*N!vcYB$VdBl8Wr2CXx+YKs)Zxe7e#L z^T#B6%EIDQ9T`}BGr7lXqD2DSPAIt4*<$M_wuWqHxWwkvY-a*GQImV##MqLuTjh5M z)9KO>7yI!`)ta?hnTq2*6(VqjD;}DelfO-HwP+>^)w4ZKV;^C4+pIXUpwJxbYb5^Z zmE%_g)G?ikHJ$auiSA`9#@d~JJJ$L?RWog_vKFiSPK}ZDB*^eG#q4Zk^W9hA{xy{? zwX>t8o#;SJ*CJzYBDa3gKNO_rg8a5Xiiw=ZFR0BMnyn>~?XFpIH2xy`c~@$mp?+sH zQ3e(|zp$~!L7dO3tvne@ZU~AcTl3m|={{<&_?MVu=O(SpzeW8{&xos6y4o)!>%mQa zVeu`r(&p2Sq>1q*C2Zc38P2wT>n8NVn4QY)e;Yt-8r~`#%8T^6|7QK!r)1AFIbI5W z1KPGvxhy>?s=oj2DyqK!9V#j+$M#%ipFoDc2@$d(Zhowu%u{-H)+N|J9iR=q4wb{L z*|PP5v2a#|5z{HE&NqmP8?I@58*$%GftK??DQg@e{!TSJ?*G5L{wvW65)B$k+NSiy zck##9v!QwTl74PpOc(jLq%a_V=RV%O4Bl{n{C)vwfUx6nJIal-(tQ10K1xjw`?|2_`L0$*(Zcq!*Db?HJ&PS@n-&{=QIUZ)--$r$Fb05fAKzj$}Y#goD#3? zY^$NU)tnZBH}wa>7n#!qxkfF$pDe)wXCr~W=C7vfjcZtVSkp8I|77e zA`R>BhF$X@u=W7oG z=bndw^Zkc`^W%qs^NWYZS^9gHYqU3h`_TCFs}Ae2)|bsoxd+a&g&p=lSw6j^4+Cd? zFPyM@wH?_DXW8~Vx);u}ZXN$Ha83dz+Ir1p?Ku5m*W zJ1zx3Iy;)n&gzASE^B^&I=_oOoLoiHuw_?~>w1;FjGy`IUO3%-nSaZ}zb8eb^k;kF^mX$GUwV)_?&+0(8GrGkRQ_en|5XaqTsHcDNWqrflFFNUEZS4L zTRrs9I7=U7A#wlD20uj>|0R<@MDHX@?w*_ZGU-vsY7-8b0ZVQM+f*#gM_jn9MX~RN z4l*!{3dw72J_QMt1>3D3vz#RzI4nq<)!6j0B@R3K3Q0>;Eaj1Cp25|7DUF zwcUL2a=L#)lw!qWRFM=f`-zcYjQC2+ivM%UA$eKx?H9VSm1I#ybTT~5wV#QZVK}XYE!hRHnmb~%;rlu_=&0(+SLQwWGAF8UBs;cDTCSyiwb(wBJE{U!( z9%l5l9n38J4>HO9A7*TQMCE_b*EoXB{txlf%XZPf1z)u`5yuwEY_VlpE~n(OiWD5e zIW}PIjfpO;BI-w{rv9o8!~E#ikLaPts*F`B3^93~bT)-lNmysrT!I{MOYQ4<*ps3n zgM97L%V^8j)RyeJ*~~sQ(o}o*XAq|~g6vp#BBIJ_`-E&CkH0x&XB3Kr8#AG5dxLvJ zEIX>{lvMjG4vPfSL7O1g$$bBedcWSQUdrO#wCq^RWY3YkDaLWB)|mv&{wxgGkhD)q zL9v|df^E!X*ZI;W=9<-A)q*}Q=%dHQQd9uuI7YK1tMl?c4F+C5rX80f74o;7-h~am zp>~^GegiEny1pU%A3&s^lj)~9p;n0FDJKY`Nl7jbJwiL~<&fFnHI#F=%E|20Lh+${ z3H-s6=oI8qy)uYjT36Z5{U(KP@eqjoj!Fev5Lnw$_ePJ@`8_x;x6O6I*2zMZECe=i z1ue%}s2J48G|U8lL)*Towx!GL^LYaexa9qqX}6Bx2X^xRO`RBSALCInLeVl6%BC)q z)ue1pr(lb!zFCt@k;qtKtLvU@lB$h0+#efoZ@&y<#A4@n)aOm6wT4fDZhuSdo%ud3 zmpDEyvNcI%*oP~jU|YitVxfbL8BL$M0A=GaUs-mO>F%b6(1r(lv%^<_7dkxbQm`S$ z4!W@*1Gxfvfs?LFN}@{VovSYRxCEJbh&kay4)vZC%RTiCi1Qz_hcqJVO95)CVxOnwpB`# zzvt7H5yhy=DlS;?9rYt=YIDFVXnFBseAcvZ3k6MAer5^mf^}uU6(mZ?aXdcT+*+6& zpSv?cd@6{`+rKku|FDjAPN5k82=I%|ovCh$HaN6(30h#qMjexlme^$L;M~b;G~oOz z@~@A7oD=5SJkIAN|2FbZ>b9f!cP#&OWIl#}kK^BI{5y+(=ko8V{5zk2d-!(=|Js)} z*Vo$nnj32E=QTIh+RtfjsbGp_( zy}6~z z9y6Fp!neAI!kOo?A6ZBto~w>mxq{E<_F99SyXLcZUNWia^`}!3zNpqdHoJD&0@Bj7 ztfQIiT3bJ?zSWwR6K(cv1L$nKm%6|Ez;(mwU%qN`GamuBYt^Wh2dM6MakC-F%`IYqJdp6#U?qP%JVbH4W%kdsOmA7f^{jN!fu(4_*juC@* zF#g0aAB&l|2bUb!jtzssQR~Iq@uLPy*{*u*6-sv8^y}ei1Np9HgD21?$0v_=;fhbT z(vIrQ71P=^58#Sjv78ZEvvG9guF%)V(pQ~w)0#;qFa}R$t?z*^$ zrf?%0D$j@%dfZZPT-~h|U#NreexX!v9iwBw^4^lrLftpIO4eBVXoE0SEA~;Hw@gx{id!?#}A=u24qS0pYu5SRbGwWvn}0#?H6t zp|kJFn|wP9h0EC}$HEY$1u)^VDFLI;Z+c_z~mCqX#Q zCGj+8i#atvd9I-ZD8q{xE1Swq-ia>E%U@30=N_WxCU>4vu!U0tcP3)*@&QvGf|ddo;Z0WM)4N$l4aD zWjk|V67p>?G$gk-et&lZYb}tgQ`mkU0}>vTJByr#<(R_tWmh<8(}*w2piLvrghTci zyj)aR>_gl|!r{)N4fB_>Ms2U!8-e`_GhkDVv3GS5_pMKmm3I+v=7pR=ia9K!Ood=+E- zL)$MlRTccxEGB6cGqhuQl;&VWdvxYa1Vze?_730RX9}s!V~-R$4>zsTe|GOeW;*vV zznRW2_*=|$e$2rw%ypk`^g-^3cPNL+ZlEj`O`j#RUaH#_6 z1t9V9TzwQKW##6c&4Ctl_NgRTMdcM?R502R{EdIBp;PAlLSSzTL9W0;7{%W_MtG4B zB=VdFGC__PlVCz<|I`kVG)aAVcPdRObvU!w%Qm^}hZBFpT{tFVu_!cbL!ozQU<;j- zMLC=!)i|=9-!i`ck&LfVMdWiGrGt>H;tXZ` z7B1rZP|1CiL9~_)RcDY72D}SrtwRLi$)gh+@z zG6bXw-sl`=c5q*pF`ejfx$)yhq7LZR= z~CGwxr-^;%b@$Xrrr}5uP+EJu&aCPCok#v@yc>6eAa+hh+f9&X- zTVk4ux9mo%QOWv67pD-*lBbUdRL&zZuhQ<^ysd6TaY=(`cDBqG`_5=+#@hE2S2j~e z=$xrWcAY&#HPz3Tt2F6ty3<}YOwkLcvIhG~*$%HGBOcSaXiL2kEdDdaBly02;X9gv z9PW_v^=)r~PLvMfyqjU50mU0##HIqFuXN}xTQmwM5%N&nwtr=>!0p>c5V=Xphw$V& zFrg@bU?U3Z-PdT|lB&lJ7}@MEqV91gOy{U;lGU(M%=fX5H`StvoS{r1lZXKUa$ZU zr)f;HSiI40LtBe1_5Z$kED+(B(%}wziXQ>fVkT*PLUdLA|8E~y& zbE~mB{6V`?Xs-HjwQoh&Pv44g8It+Qi}i_G5q7u2y;e4JB*jOg9TpkrkkK9qSKp*v zEsxk%PLmoAEtE5?Ahvg>$`?K=eCRFP0*uvgr*C;;J;4;rVJfV1W7dzC8n$ESF0oXL zw=zImt9-dlBgKu+y@dw5_IzcT(;wGS*Dsi^4WIqYXC7^XY5_?>Ju_T$Isfkr8<+F{ z&e;~+bY(AWSUnt@)1Pz+uwtna(_nJUl^kLg)ZX=1akyqzB=TM$86vQ_q9<&_E#UkM0Z$S&m8CI^{E%Rl2 zO>E|BWfi6 z&6Ql0HD)&srE4T+`0_^30Dqe(Gti2rc@#&NuiD(!@uyV%WvhM@_;8*I&}}anu%x&D zP$K!(X%JD(m^PZZvM=7k!W&xCzH|YW1BEtoI#jO@HQJk5IE{lt#Nr(htM9i%F&wcC z(cy5=Vrj4d@M;h1P|(l0^=%YX{^?LqU$|Je4kWQcMM1b`^E>O;oFNJ-FuUQ{$1Q0e z@NM-;OWFu5&@&&sB;v7|v44P!;7mFZ^R`aM`!icd#)-Dh7T9`dk}q8BcyfK;rzj2P zb2mU2Y)9MC1HbkTUpqOp>T9|vzzXQ^?MtUs}eP7x|mEX#Q`;v;#dh3@1x`}lb9 z%d;6<;VuS*2zAvZNP$=5vI1Ni z!NHl&sXmvWn6g7$Wt!_3&eVz~W^|=}DO?vP9O3y#cFi`|?;?~0VSm~uvh@4PJCP;K zY9W_*3OWI_mI-TIXKhPpY1^|(ec*J?rA)2+J|-BFPRtLB6FvO_zfEwLT~88=eELrb zA>b|}JoA1b}olabjcu=Sj9GWK0` zK;Ayj3>NNjW9>!#Is^I?Tuq`;ujLk@i?)ZV6Kf5?@2J%#fhk|qlzZt#3v+)O>WWG?AEy4 z@n@;jN}T$qNvX|hoci1pE{nsL@at4+Elz!DDz!gOMHd-0tT_;;zBX0c>NxdpQ@Dhm z@wI&@g*zChZcpJ3#i=KxQitQze@dmUiBtbFm0FKe5n9FVO(wUIOl~uo-Ro1h$@G3N z)!t-&U!1~CCisF>YBIy4snleO_oPyjIeuO$wHfyU#ZKId$vE}xam$vpwOHudm*T)U ziv7N{w_*r$$u(1F@W|ZB#3>2#{$Cl~asFB0lq?c)yG-(=YilP2VW>D?7z(baXIgXo zYH=8Ie;kBMZ*@2nFdBhZZ|xFg=JTn_P#!GLzaLq>ArRSr_5q2tLZ(@1p4U1bh`VAs z&(HafkgWq>QPKT=>IB@I%WHjbU-5bKp9T)ASK`SS|9z}{)5dZ4-6HaKI888gX&(>0 z{=b>^@It21ydc%M_MlSEN~g#fay>&aJm3@(3$GR(N7Nryp^Nzdn709G%;8g?S-b1H z#(2h4E*viv;K(0?#!qpi23$Dcr*ug|2VR|Dm5rX{!%jp3{6e;LU8eO%j2Ta{=?IaH z2)>)9g0R=wFnst5(nVU~)4W#H=>57XZsQi^~hqqOkY~8F1*c~!-Ps8s#~+--)1hC zS_Er?6Q=o6nu~@?7RL3A_=f%X%J%1{6d$gESZS9r5#lGe1SD6>BNy}&hEY?BrH0v+ zmCD6k*>Z07x=D$$FFNF9y3&tu2u^=8vrp4f>dzH-b^gHcYlYdR0;aS5IFm%F=srZx zsj@XZ1A3z;H_Jd4cOAIv^~|RaY?^nAarzTHO+qiE^UVdL$dix>hs~O2d|n<=lcn#{ zfH)aNk|Q5W-%BS?L@dhEz3Jrl#n|6ZClAEfKS(F@2A?nczI5_?8z&Z3$xR!Z|7_OH{)r^MJu5R>lQ8z=up$(3uaHF4siI;SC2 zZ#0BzzJ^fk)ex$I8bY;5L#QTb2vw(sP?gvas@R*Be#_rr5<9s-@=C4@AB*a(uv1+U zdLY;E>f{|oZqeL`D@!>j+2kkLMeb*wpRglCi%Kt)t}k`C|9K|F^kFa|-;q&NV^OH+ zG_FSkYd8_%Mr7;v;n&&f?Dee4%AJlYyT3p-NoHHv))|Q;JVNUTSs7-A4QTWst2n^H z??fLCduO#Uvg^)@ z*Z5fWZFfOTMMYiPGG=J>->PRm2P3RkPU!zJDArXZ&qZ2+B0K$s`CFRsy+rwmF{^uMl3owP1n~cNLbK;Ecy)sz4 zMct)JYeMt!Th_(jPujwj+NYlqKeuJ1ZRTZUvN=HBP;5UN`BtfY9%PRAnPKSw>STAy zZb!LpN!LduZPD}et}e1;q;rJgoq(Hq11kf zBc@*wpWw}tNJ4;TVR7lbRv|)<{`P1w?9UX!{)5J3x1Pb#@P_DdXe$RH=k(Y9H*IeN zC)rWe{onNMzWv@acY3C~XJ&VLHrY)&+cUeHT?ms!k^mv$J%I$6nKkTY7Xr&79cB`Q z46|7fM1ceYql5+47)2gHL_|~`1rY%S5fT+q!3c_iulPKF-(TSQ{!Z1s-90-C!T-l> zrtiJ=daCNwsZ-~iI)$9Bdo;-9B_p_EFp_{)ay**0)7n`gp$VcJn zv9hvhXfy4kh~!C4^Um`;w*Z!3CL3bR58eq*+BOi26hBMAfg4!N@@`-s4gBH`Dsj}l z%5z_P(%7p!ZYcKAK6W(5xW(mmAsXtz%Wy!F`7;2CMq>xne_K$+H^7)w77j{6gRE`# zjl7_!lYDnHYP><6zUzszZz6Q*2KI$Mpmpd55_jO8N@d+dzAHb=4k@qz33p3ik&EuI z4wuRa7U2h1BPKlho&4;}DRm%AyEvGoJ?{98b{%}1LrOOaF1yrg6xo3WmCmF=PzrX% zV9t^RY%M4I0}JOrS!m{`&&uXQELWkCmU6CwjRbM)YJE)jHyw|~^^N*?acsPA7FSKs zNBY$Lf0CaKK7IO;FX%vF5aD7@a&6#(94H`C$(-@@Kb!qm3A~}2MO-+4i#LQw`+CS% z-F@{{w`s^*c3*+aQ65DFa!l1P=G&B594@hYS-#Y^54<+3XlYuOJP!@yoYWz*%`T9IcmeXErAdjQz}U&j&n~7?B`Qz~UAJ0fB{|P@ z`dpzLmv88vkIk1%qNJ;+GVPKpne13Fb{shh7}M|0E$E0IJ-;?O}4iT zy@s=5%OB+nofA~8b={BG{D)W-d<`&cBVCC0Ss}x-F z!Oa6Tly5Ex%0)2{B15Bbd8M}7^Ky*Q)B73d9l3#4im`zd`v!|Kb33Kr`bWnPQU)sa zm8t$Wsx?p*`iwd_Jua^CTpYK^}YRk?tC%*}25}f|uJ_WE1NP z%~@I9NF%?KYY3tfp}XeZT_PP<^TPqiKE_*S`GEyP62I*zg5tm8{S@FIF3wOKPL05$I7^_!PsF zSu245a1k-oxpXqm2Xg19`h2TxLOZh}+?rq&)Wot?qm+bEwSrFd3vvluX{3HXsj;_G zwO)Er=sttfLTD%=m!5=pB z`bPN}McFKUBq%$mKP`YMNy4q#J5Y>FNw-mDVQk~3B_CsIG>!>Q- zPGho-8>Cj;p3ReQi4{-1CF<;M665+iL4}A7g}xBbqc$jpETW5hoKZ>6zY0_ z@eXR4K2GN(qb0jwwX^9)>Z`%ZFBF1X!qvAh7jMtDXB`C=V$K9BGtBpq%r_foUoviI zb5v~kwMr{LbX`1h|+8M08KKBIe-Vgo7FrADD2a7?$_>&Sykew1d?qh>&LID+;m8b2`7J zSDP}uuky;`^A|i;e@wwpp&rsEOo>>Obo0dbE3^sqYuXwe1+N4La)twz8v{G#E{8p& zI&8GQ#_#GVMkS8*TA*h^sBF0QNU%)z4jFbnO1z4;$IH*w!x@0yDLTVR3k!@4yf$e zKza5mE{d&!9v*xdtCe6%Tj&~UMTuxV!U4su!?{u}xiCPj30jP8T3#yrYl)X9Sq9M89BwGbUbK-_t*W<<6C6SJ%v zIda_D>)xVlet#6wED=hv<8=plgiWJaY~+J3vZZYD0iHY)fmDmwu(*dm%PCiTdKniCgRFUORB`&K+A<*-`p7b$^bt@~E;W}H6Gl=|0 zLBvrl!&9_FzG*YTBPl9x?eF|D1$!#M;SkR5CLx+OHfdK`fw;o7GM4$~1m+vl1-Q?= zJJ<6B%Au?{K)(r%6Td_u7xW7eaY0R4OH1XLj`XgLG)ee+mD&5IVDmge#?()R0r(uj zpy)JT&B(y5A{ynczueNv2ro}yvinX4pmBu^KvU~^Xut#4>KZ5C6F}5YdnjuV4o8Xx z;c(>WyMn_NG62WOS#XSOff^#pqjLkkHK6gjyE z6}gv_e-kPF0Kz} z|FR#^^b!Aupm6r@`w^2aqWjoz_8a}smJgi|XaAueI^{!~E5FLpj$OYk=f(ug(F?b` zJ8KG^2Y|tN;D=F{XqtzvFnfv*IJyUh`bs2d-9J>MXiFHtrr?FeaP@w2&K1Irp0Z?!<~ZNp-nWErTfCMp z;j&`(m84#LpwgXL`D1Z0LFX3G5^AD{UEb>$7_&T2=+^+AO}ov5G2Z%oDeTYa~XWyLY zmFd%8Brw0op-(Qe`!MgM`xuY41s2}I65KUsyp*wc#QJSEED{VKEtda)qG$h|EQc&3<6@%qsM+)u5ia(|2j1Qrr7I!1tzhLJg-vH2jb$k` z4R{^v@+!V3!ibCXYGiWF;PBQD1F1uY^rpJF;+LNL6Ptfds05fpV@vd-yoJlAQpM{% zcQk0ArC_z@Ay|uo`~%f4fzY5}iB}wg46IKBj1XC*gpCB zBK8ThTzU-6^qs0rK17DTlbp>196#DeZkBh;E!!S(PV=AZKHCof_&90oo_39wfir!A znd!Zb;vG)HBe_q9liHyT;3S9SJyOCM9sFZhAh}h41G(M&d>jK&Q$J>H)Js{;C@$5q zy%C{_??}97EIB&i<_;DHIqS_)e8XT;7a_51n(;7FI(W+%Tcc~^1J$B+6D`x5ZSADDLM8+hX zWg++Ukj3Fcd=#4paA)ttHJZoQVibRl^29bL<%uS4Dlb7dhCk`2pu1#(N=?qkp1WWM zcK)ly#y$?aX!?t96vw-%{GeM2RxaRNF?@&e0${>H4Qx zSzsfk8zuJZiUGfeXZs7^loiFDf=*aZl5(4+e6&(7Cn>GJn@aoWrFLx~v6if`-FEaz zqRm!1C}4yY*{YZnCT#C@sWcAT@JH`rDRRe>ubh-WZslF+Qfe@UQXX7tk0h11D&5<{ z_FUV9YwoCo@yw4wm~JcFNEc2H~6=6qJ4SiONQ`FDbk*&Q;^P9ukFmi#HTir zuyE#*{Onu#>gHzO#>2?xU#9j(;d+q;2!HiuJ#y5`KkmwJEtLx`uE)(c_Lp&WCHS464bifnmpY*^>7wgC zdhbxFnlM|GO19Qg+JSqEbf74%;DGwgzb`*Y3SGKPgO*Aj>UA$ zZ$)?DikB0yy_QW#=YNsfv6T@XMIC!O$PssbiUb3@G<`abSmbm|ju_H;@P$YpqjuXd z22}IY0*duz8u*{Xx-l;J0s5y|J-JNUahGga{zM0{O*p6GR}mfls&Z!f8@r5cFEDM% z^nQgX?I6sthDa-36J0c|wvESD`J{NvvqymSb?O%*va0*DLJIR`A_f!g@Kq^yh_198 zT4!-=OiU#p>k#rlAzA-!^!CXKB)F427bNhcp0n2GViGZB)`MR#>A24c^))f0Zc2CC zf{c^O&J<9@! zyDHx&h!HB#dN+VUcRqtNHR7M0#2ZT-5}I&)?(oSUX|xz2Oyj7%c+AA>C}5EI`!+{@aI}0{M8QWOLEZt{vW;h>-rrKE zd+V!%m5)?WE|=j~Pi=#Gd%o%e^hbmKNEpSFio-U9Wb%Jvkd=9nmEP77H|s#DUJV!g}9NSu2;%QTa7+Wy(LLaj-`hD><`%|ad27ac z9VoaBYFv*2+q88|+p?L7b*!edyDwx7wiLUu{|whB6qQ|Xq*2p)6OXK;4xg9KFtcXm zuC<79i@iCcdI)JQC$H)b-Ogcm|J%k(xTOk`vox00A((0~NE4Vn^rTh2<2>Q(1)HGC zbg(-{w(oi8OaMRa&*vEIHU~3nYT8no22r?AW4T>PE*dy99f>|VHsJ+l6kOS_6L$vL zxl!0By_k$Dx#x=O;0U$>ShKEOQ_nih*t${&YSy^D8ZHg(7t|Jm&zi2Ufi&o?)L!+c zZ-dL*a^Wg`DBSNs)PY0cdtJY2Of4MOv)g$G`@?m6p`B{)pFm$GDZ4#-=MkvRuKPcp z+F#F*p5Q052<&ROqvpHrKb2THW8RS5+>6bivwX(V+FN+;x}S?AlfcRJK3=${Byg%- z@io4@pK`ig^MUN{l9b!pV?K~ub(6sD-mq}j{fGdQz?rtYqIlQ+IA=}*Ip~>OJAC^< zXsNx^mwM$uXt}-HhawtEOQ^K>`B3h^Ohc>f1s}={sA*`eeYp?)vw;#u+E@9|6KUF0 zZ8|uxEwRO&+QGLGKKFS(pH1C9cpx~b_k48bq>@DWGg0%X-&GrT01wY4W3%&&yNv1<-2q4(Gra>6bz#{1 zE2d0YA|uw*8D@f|>U@e&Crq|v!GbMe7=fVSEx9vAd21JT7Va5IYkMI|S~RmJq5Nx# zI3vSo_xU&aOqI9N-D%VIIppyRlBFtRal*d}G(&keb|-~a(dlw%G8UxQMU)hn6*k_U!WdG9 z_NiZYp6W4dEH8XiU0Mj6OK(EwY7M@rUg48|eHJzca87Y`!|(jX{_Lepj_Fs)VAyG> z8CN#!sk9r5hJrV4-1NZPCAv$KznxAbn}!9EzgZEVp@IVDH@g+ez__Z ze_#z7mS}*>iI<4|^uFr=*=&w=aX68U@iQ5ZarE;|^u!qBirI~N0z--UFUMJvLe<9^ zs&S*o{;pV!mC5ci%jQ^CvisRr&{rnEmpJv3V&256OWpJG=xp!@M4=xp#@n7r*Od)u9#gyY-QSp7lJ9iqDWMtina|G}PO~d%JG0{=ij2j>3okf z_Vi!xH+VQHj;01e9~Xol49>#}(7e-WNjLGye2?R=ZiiOQyB!aA7Z7A56`SukyLYrO zS1nBMDYAo0*gtWmHTr8n2=7V~H*73XjCjgq-*QM{Xyyr-Q3Rg|-P5O4y|GuM>*ti! z!xuboMtPjEA<#=^`!ASI%?Rh%CTNh8wWAPZs|#NuGTmu5K+6?l2e{;J7cY?ucT)t0;yCWG(v6;7_EAO8G9B-z=iNEvdcm#7=#Rv`a~S@!v<3lQ zq4PPtK+GE(Y!RIWO(DRg-W8OLR^dP~E==DI(GWJPGYi3Vb>aMejh>cZDK4C0HOOd=ueL{3&0ew)ZZVY?2-Yo@~mBm3~@hmzW^1P8V76M zU|sc8b;K2m&kVXxA%Q8OW%{*)1X1Ij7j`~K{uB2OrM^ujn-U~t4rEHo{C$-vV=}T# zp0i9D1rH~9ZBk~M=^4*>hQestAE-=O36o_iDKiMJ9B#XOatp`^@#OxO7`zo0VZ zsfR4n{W4D_Sq8&YPu>e*Fdn|_JuKkNgCoq2`ZkZy+oO1!p?JLAaQQ->hRQSXHc)xn z^v2%Z?yb48ch4x2=69s*=#&Z2IfLT8D=z5i1iaiuC8n@{2P$_$aF5?>553^0z%^?GMx+fyCRag z@N0_P*4)6A7m)0|FnOn8Q_1_(#@<@;-trB>GuGV8EoZ!Kk}z|OWiGjIQBn&$uYO^C z;oLJsI9QV}>OKOauZxTUsdwT|=kpq?i{p#2Wt^;bFC#=)CIQs$c=sGGyqfVv$``~J zB~-26jl1(7!tb{PC(ZiY!t?$E(>n2A=m`med*obn!)bG{$$2btwM^uv=& zZ)RYMaVt5RNm9ar8_zp}1KT%Hjy&ot%8d@@5~XMxtz+Lm{{aq3!$Y`p*rEBdsB8Oc z_mxzzugl+^Tp3Q5N@4zQBU60=SE93WdtRw4GktZXaSkpGdp^G}o;}6u{%XcC`-vn- z+iI27Nz=7w_iV$&WPgqVFB!|U(Qjt@`b{v%^CcPct?28Y-7}r$i8Jk+l>7Ee@|pH_ zLpleL>e-jpW1}^{1KHF=txtP+Ute`kCDY!$hYBw5SFov1Oy-r!w9-Ctwh>lNYGai# zd+0~GzIUim4l4!r5$s!#int@FoVA4jGk|tXRGSRRXb{OI(cntf$o*WTyq=Gm|820+ zom78GuyPbGC-Zt8u+F^x2)~_Qht@l8{QMwu>QWeT#}i^QPJ8vAGmDmoUMw-$>`Dly zwqEU`F}*{p$99A5`Xk7W@Mb}e+`6`8nOb)JpgnWzGKS66qV?~wXMX)r_AIPl&eQl< zcecRE4;szRm#Hi5x4}5nC7a@;KW!VoFzWN>t=G|tp9<#Aov;rMvgY=f0 zKdbz~Np%5R*@d4aD8k2f5H=4K3TtW_J<5P!HFg(qVe3HI1si2^N=7F6ZP~dU1+xpz z_P(DY_Kz0KJ~-QZDPLx4s*%yyk@}ikk~(Lp_xaR0ms+=#`*Bq2$xOjZcSKdh)5^)6I!!f!mh7cB*7;%d4r#x^m#dWXNCsyA1<#x4K>--XiQGe z%rsZONa5@@8`In6BPIE6HTfRhmV8b&W{9n{D@njqlkal7wyot0m~JS#U2E5pB-@(p zQN9rbCL!A!?J+_|+oMUyjEp$O^e+i%7n>F|+AbwUrYbkvvlLAQX{rk5 zAOuljnyT7p&$YJ^*h+(H&Gsb(H3l+{G}@Pw70{=AW7?yQ_A}eN1!)=-H`*)heF8NN z8f%!pzV?DZOGE38SrNDPRRSdq9dFEjMxi$dnyL29?cJ*)_PCaqXw0@?*4noSg7)a_ z>y>OFiET7yZz0xI1U&rv-uBKUw%M5dEyaFRdDM@i0y2qhHD<45)Mvk}SoPnihc`(u z*_i!hB^Xux8j4X5dXiwOG0SufX0KBM04Ko@sjw8h>Bj678>`uSlt2LNoPD1XT$Plt zjn?Hz@DEBL7_fBfy4_OVB>S%06V;e0SIxfbreXW8r&!|eWZ!j>rFtm#T^QB_=74=yd(aYW z*uKkr!-wrdg4Ef0X~{xr!eOET^RZ!5FT0E>Y#(7AlX~@>re5ElShtz1V|vgc?9pZ* zZK4HMp{J&%W74oZW3@wwG4e480*PotV8kV!TB0%N0XgZ zXPJY~i5R%zH0ZFz>v_-xHUPovvOO*LPV z3|;qyNmq7{CWeaL#mzX(7G!LbjbhNLAc#16vG3x>#%qV)vzA{gyY!*rQ$sIJb1oW zGRU2<%IF`;91cei@}IQ(ci$$vvtnzJQ~YquuZHrFQ|5WadCs0r9-f1J^(AP+4wvv> zn@Y$B3wY;O2{OPdVt^OtwjTxvZx3i9w&5baxv7YP)AKkWa2Z=u2~!91i13^_oCI;h zMSN>h5yfEP!*sU6u@^sQ`^PeC8ls{*sOrm+%&w92M*;aNJ@Ow`632*Lm!JyR&%GnK z5)-A=0l1&hrmi^2IX|MBMD5+OY{~J?SvCcS-a=pX2~UFw}&kU-f41XvX`4$+jt zK%7(j^&8Y0h}+!Q$$_}7TB~(+Q+s7>xOIDFbm(HvZf_EER(ml*^lg$=TGHD>oJJO_ zxpTC4u%9-!cd(x}w|B6g&fVTWf2iZz@4Zbe9)SI<7XNogxZfL_TihJLn(wy7|I_39 z-)(Il*EhHJ|1Umg10DYE46L&gpdBt;jJ$F*gInl{h?kkb!mI5QxAJuq=QZ52 z6V+N=MmAoPWdL5XyrYLlqBm!)R!oex8RavM0Ys6_*$$WAaX-%@I+y}i=!~A__d%*` z)Gzb@J4g<9%j*N$mHE3US7r$ugO=Y+^eJY(DOHw^Idj^XP*f%duR&~ubK6PQnaSPH zPS`9&idVB(AX2=Bhw+4w{Llv%tAE4Z6cEC_aFYtxtf04dC*UTjt$MnS`ZBKd+Qi^c z0yVx_SHu;ZW&LUX&d(uXke4L#jL5&-B4!e!r|T>@sNfIiVxn0x*6UGk8_&2-<5|gN zVv*&xwQ=K{R?nmQ`%(oxc~qJ2i(gH>%Ecp8d2g|CdQFYE>$u3PD;EDc=4D4$;>bzd zrPSWU19XvF9V~I&$ixLzTDbdd{fiuYpUr z&tMyQBe$^NNj9F@zAqbZ>+*-O1eb2j_-fjNm29UHZg#ODM+-Fn0cl$n<+&yky>Gop%0ubW@$rOj=V?qwk2YcHy@g*7SJ0G46o&mn>w)wdF zJmE|GInEriVGjgGxY8)WrRuUSOoeRqJ0Je7fH$;=46t>!#^Z`5?|d_xY?##QV(oKr zw2lP9YyqV3xRk%^_adD8-!FvA#-iGT~{ov!Vdp;0ndy0dklX!^7kD6PVk39J?O6FT7u}Oc+YLq8ya}(-0te^-r8M3 zZS|ti8N9rM-n}r}a0V~t#=d)f=uB6(h+4=^QDFDUxk)`9mz&n(^6n02nsI=eNZgoe z=V`kju6wO^w|4;`i8AMk2cHL*Z#}BRx*9V)1qO3&%qH(Vf-Xo0tz4cNx>F2Ok?nYH z;rB`CN3>crix58&F8YH+7kzxbQ)1kq75Rmi5)1{-Z`2C~^{*yNdLO}yh&#id&Hyhw zh9Az>LIX4nioEMQQun&JaPsj+F^SPMxHPcuxbUWWH8PJk4g6YG9p-qP!Eaud;l{Mi z4Yz~~C|edrRnddg=xz*DMt8_Qkqap!x}Lb;3kn()o8|!Vgaimp5P;CPfPgT{(m`d# zTLKZMKVqn6hWE^>P;4ggSRv41BjpnxJ6LnAxU_E-Yb}YD0uL%^x?O`1MU>u3J=~! z@OQ+6DGkrf{G0<1o|p`Q#{+%;xA5R$swl(HcY_DNOAEk*CnZ35Jka-di3gWF1U#sK z2e1PTckt2qP8YU}H-h^e3+=M<$3uuZL}gE8@YPIgBgt z69@m1yTS%>MMfKYge#6>a5%)s5A?#wJe2RB>8q6dC&WUuq#zTeKNK$b=qRBTxrMh8 zET2r~)J&vXC~U++q`1nTl!a~vTVo<< z4S-$bYc8EK-SheE5UEAkMIPu!8WG(C5lw7cJ#{+xOjgW+`2;#1)a9YjWT>j!&+Z3I z#OLrKGe^V4<`U-5S0dUxRL(XqhtAu_GNJ7bLCyS`Y%9vQJIhOFEPp1rm;8Ix$G)ES zsI6~ETIj;^!VeG)Qan4zY_mlc|Br1?t~=Pw^_~v_#t#CgR2(0r4Gu;E*xqSLzK|li zk1e)m?W#0-86K6l&K8;QO82Et7H4d7Y z-f@b@S%h2q-O<)6LB<5wYEtz@%^U(3FLnMcs6`9_W{rfMADBlB=SpK~`K+Q?6?A;n zxG|CS{KA{)jDj)aF!R!bC-~?F-BzORi?PK!t1MjlCm#K^Spf^?Kb9@_s%AMI_D|Uq zd-z#OxShh%~mtH6@c|r>hs{U!Sr7RJ3!s@q?_&# zV*2p2eQYezQG2n^4d~KE>~p;=EHpM!CAB;5DEj@dhR)FOl$OW#v=2U&SUR540+puT zmZlcbw8iU`C|7&d=lhW~pNP!hG!qtC9V80Y_ijW9d${n~;T8PRmHOmn8!%L)CKDM>26O z9_fq`D9%yz+*svn?fAzVpb@xDOn$W7K zd!Y^^h+^f%T?vo!`Z_&w>rc}IJDsQ7 zGq--dJ)`v-c;Z*t?N!S>{VrSk=I;4yhfm{rSDy5=?d72zbAAy+3T>pcQO;^uzL1I5 zpFv6RoI`sz!Ql63L*W8yt8hWNRk)zuDqOADDqOG(g&z>EX4ceNAD%G||6vy1JUq`) z1FzbF2Iqot2xxHfsU+8Fx;^gx>^Qq-y?Fr7ZfgRSLlTLZ59cJZpd;|M_b*qUn6ZulV)2z=do~CjE?6*(fD^$mLZ%I+nVIS4=b2sr^7!rV_&nqa(0SJyNcPyoHcf#Y5Kpj6IB6X zAOF;vtD0uEaCV{^_v$^2e`?Y0R{Q3&Q;Y!TmHgA7EVRt_;_O7DnBhL2e`?gusrL7t zog$_&*YVF9HMLcv#@hAvBL6fx3sdK4RGr8p{If<)oug6X?TPmD`KLxLY%_a|vjLi* zjF<9H0A01sY%)1KW%&tuI~I=jxP_B6OM1x~dzAx6(mF^wfp1#BxZFk4Ou z;xS_~NcSouhP?Z+`i7w4VoeQW9r&67rdgdp2 z+a>ywpFFLyv`drE;nKndTQlVf+2rz>IWbTxxe zQQeN#AII+Y#>f=iTa+nA?v2CV^|YJlq9)5ti|ZOE3-^IMj3gpNZKkH!G|{8QMsy#3 z`Sbj6kz-t(EZzsl9Y>@RGLcICUTi2qQwdr{rIJA1d0h|^p?N4a6v>#7LM2Y-Nue{8 zIw3Fq=7(t)whfF&(ykWmnpC@d8(^cvkxVUjcBq-T0!`_Ef_S;4iJ3Ub0}ST7TGL{j zqNDpl+7i-~P%VLl3jsX@@({p7!5yY(LVxFiXETo;`R(D#Ahvb=9pOn}0Hk3E^L?83v)?4f;RW|38Bz{qrT#Q)G?dlFxU6^;E_5!U z8^t(li10WY7cIn2gK;}`5mnQ3$N4#u#3-#!D-l^B{PDDhQq*#qPA(_<*%Mb|oG;`h9I#lHOJxI@hR= zTFu26bhUH_xgk15SBWVe=-5R!K#YmHd{I;M%0qRGz>FN&FG=*_hb>9MnKR}`=X`pp zL?`*zGPKISRy6Beg6dFvK;nLbqCC8L(mLiRQz89=4yI9TCI-8q$b?SPF<)`LnSLdt zG8VrXmqaW@2IBI4jBPR|nczvxOFQS_=p+q?Za%^jO(Vl*^mO837dWbE2`+7T66z92 zQF_A2x#NiI`^JM;P|ka_r|Nu0T@z(=G(nlKu%BA)gguvrziQD?aPsBAadqNDQA5N- zqmi?ZoV~jU7vB3Uwf6bQ<0>{fP*YS$Wcf4B6FLj=U@V^kbCpgU> z$tDp8-|E$TDXx|a^=c9ICEH$~O75y%diKw`=ir6b1jT%i7|TXP+UQpWo8#{bQmP=*;tgQzTiqk1b*;#sd|%Z<{7q4 z`@$vGXB%v-jS``tQq%rS;oBD{kNLQ)`P?)7%B(FC7fv7BXyW4Vu=)JL6whId%FhMD z1xqV~rRg-o8;&5C+4aOU+mRavn5V|Ns?0QP*S@YQ+?j@bzO01H3Y%sIg%ZEMFID1) zE_2vKKjiJuwH~|q>A8%b>(T~aTKMO zyN-8W3o5}|S>eI%m(WFupc^)~>ZTj0BV(GZCF{%QW)8P^-6-Ek^1GIeCYDPlm&qG( z0Yh>oJR95%Oxrz70@Mu3;5iT`+F-z4tWXMPT3*P|9PZ9LvJaahDdj;w5K;;cuB zIDh1ZR5-)AK{ZMeqjxzN!{9<-yur;khh=i=G2&a3Z=CVxjO;YvU-`B77szwPLvNRq zhS`NvWZKlaT=x*G=|JlscZ03Vv&^{GStC*L`qt$(;=*C`Gzo9w=#02F34gO)aig|) z=X`r5>3wrzWvscEu2Y!eYCJfzehCN|gf{(L9WJInwcIz*2q5}2&FZFfO4Hub@5_{K zT~E`mwEn^fR9A;+{HY59^4LBBaW!N;EXa>=(IwqD6&^E=qjOL|G9VHh>j>!lgQ8C% zX0Cn=Lu*dS!xs6X7|?MQWjBDOh3NE{jp|p8rv?Wcj1CM}l69>E^ff7<6o+ROL$kcc zve12P+;oFO7Z)qXAOQJ$R{ql{|Iz9L&OlztfqWDiTsjbT7&M%`>o99`JNHehbJ6BD zF)wvDYtDEf>F;H8(PAFir_MvNViSyfbpC_MTzfog@?%tfQnwLth>;EO60-@JDdM|@ zdjP~IDsH?$>v8kgEJwPZ@q)u~*1t559#KT=*z5uRvk3RnauHLc_oESc(anb?^`?rUSjuo?UhrE?GMAZN6O$ zlbxG^Y=%6iUT9)ax(}gjaf2;cAx0<`=UsQgGq9UliVJ68t2LiU4a?3HVa}*Rn7#Q= zMEH*;2|Inac4_^PoYLWQyS+Gl%=IW#KA|15)qkv#g}41aeQI(8Eia7ijSj}h(L3=L z46-7w(iFYe4?vvVh&;X8aE+AATgkSkL@OCj0M&Z&363CY#S(m%QU6tL%r(lajaHa& ztC=rsRD*UqTE-VY_d%4{LAz75NMrw8gp~@CcF1h!as6@}=re~n^6lIUf$^6F`R!7m zLABXzC;CQqGkL?{`D}X+1bNY^A(Kg9v|e70KIVPx_*#>-`D$0E=x&eu7D~51S^jsd z%T`gfITg#%_AcxAUH5-JRoiIkHd;I+M?a)K(C}>HufDe*o(bk@>m80pDSc*5u>Y`$w6hqJ_2cQbi0Dd6^d_n$uJFOO|L)$?t-bwa#-ZkeeYFl-tND*7H-k}6HuxCy z>G4*N#AQwm>rCC;@$Wki!XL+}KqvMZVi)A;o+`fQsQmVFt>*pXqaynW9M%5!ME2~cNesB>~7n} z)Fm<;E8fW8p}wW7cfzDo_v~Tj??-qw0nwPSc^8^qm#rPVox{~-m^O6bYeK?k!|zI- zV`?OuLJ6)tK{$|OP2D||6K-EQlLa;9tKl@bNjR;eJ$q;oMWK=wHZ%P zm7C>1A$^*m^c;)m{4cpB+fy31Y@acnKz!trY)%-daW}&q*x^z-o9P2}S8v#RB6H5@ z6qwE;1M2=}in@+e*&Uai`xC-g z%Qp8%+&ZB+mQ9*^eHzEfo087hl;QM6Huseo8S8B^mFjS%e`}ha{_Z|Wv&nUc-T&F` zco-!QXFL;>Fz&!uFuKC4n5CrFhT(V8&e4p3yv)CwKF9?<+Vd1^&)jI%uBP?i2zbUx z44J^Q!5PiSIxpK>F#5^PS5$skLpB9MPakzX7ZnyadY4)fTe6eUU?KgZWJh=xrD#am z9ILaFqFhq9QFgrX%Yg5xeH?Q*G5``2Pu6Es(bTFUph(r>CZVHBNyBT{lB&khcCT6;mG|0?p-nRf#`po zXEHj;^aWAPP6`o+R*uW;NE#5ip+P~7wwb@8r~CTGQX&VZsL>Pszk;&MUD!Umj0}3$ zZpUR~549mgygC0>OCOgPl|>|*5>)~rCCHp!S)aAENEP!aSSw^p6gYzYH~zq)cto6~ zN`oxVf6e6`u?!-}NogZk^zh$V6HTYmaV06r(&FHsLH!HS{zwiCh2?S$ zrITtC-Sej$bJU2=aHZ*)T`h!Y&BZgjCJ~|WOi8w_!D9Wd(-=VG7&JB#B5Q8y?)5}1 z!p~o#$DjXV8cn;zf2&e1SNFv5kmjCH_{Qm@o+?KhW-E~ji!s&Wk{Zn^b&V#{Um%WM zYIUT%vhD&+}>O!|=AxgQ%QvrD4o-EWRrXZzeLlRpH>bW_@J82M)N= zjBHE~>~ftJS=SxFf4Lih$UhSz59PxsuhM;-b_~1IIl+!W>DfB;cMO(paLeFIbiFeF zald5%erM<5_Y4BCq%DGjb7E?D9~{4Vzu*+A!X_lifztb7fEys}Zk;b55+ zwR05obJ9wUc|A?X`810^HWWWH5TEM|$K68Q(;ZzA;I1jn#pQJ8a!`FZ4We@&h0gcP zhfE>w4mnxbZ2izi$u;`MG_*gt ziLkBqLPz@HS@Ru#gW+;>|0qVJ`^sUaBjb7#(16r+-I92lnD4*Sg34aFbh|F+R_P{z zx$KpIiVdcPELB6q^cAqx~uN^}ZXY4N6c}XnpeA)}T zf3Z}pm63<{+YqN^>{2MH9yJg%#XxKy<(}eW4-drlaqb`MF7Isv zvC}Je@a1rP_T5Z`f$#RVmAli(_V%e{Jm0GP!0>YGi`L3}?0a(MLwdRy(e7j2ulv-W z>&NcC8d2>pYUTteu{0qaUmFHHf#4ao{)DS9B0=e-rer4Safw_hIH_65U3M`3c8_fs zJc{(sbm<$Xx5yEMewjU8b-B67&vFll?_Av(bIbcID@%;g?5iLR-UouD>t?rEbKvN* zV7G9H2hb@mgW15#^s)$5bgQttolEPJv(a3%vU@M2S)E(eHZS{}CjJ0rEGd2*_P}mu zC ze6G4$e(~*vfSZ#5dm-R?Nr1f&@cbmeUI;jz1lS8Ts}E*)N=^sxKSJf3jyDk1lS7!FG>RJ!QZ*l#Xd1{M@R-AEhlQ{zSP3;=V)$WwM=@+B4U= z-JW=Jc)5GYbxyjMeCIXpCF=ZuUUmaJ3yvEBd!g^b;9}}sX6!R-w-8yv94_pD52af% zl%K9-UanBMEzqo6it-2kG?^<~<$L&d%*URY`e1=HR(Ao`WDkWjw|vZvC*Qa8{SFBb zxmXzyMBwjwz9Pvd#TLwi%iVmvQuZz(4*+sq#6Y3&JjgG60L)hj{B^SSO)xY!!O-k| zH!w7}hQSp&07J8P77Vxc`(bJm3{wWfty=Z_7ffrsM02eFLbfY(#h7p6RJgepT#*A1 zO!Xmf^G5w}$moLgQfm_oEe8V=eEOlm&^ikSSL6T;t<5lq?;gO1b}<2B!VMh(XOG6R zZ*;pD4j=%0v(pI-mRH(bUTKT+fI)rxm;@GeY%8gwG(5n%UR;>lb|up`?yXBg(jhjw zvs{<6p#c*2HYO5qD}HcrYAHB24-Zo2_i9b@zIj)<)UCut&Yd^d zipD*R{`q!2qs%v>_wZO{i&g4ze;VAGgKY=pIKIFZH%~C#N|!mw4P2!j*G^e->K!%L z2RDiyx<$K|uN7*=TB%m9Rch5*tu|5{MPN8qt9QOceYkHzkKg+ouU@gJGll!%fS#=~ zvW-iMIrg$9f|FRh5R6wBCWy}FOm|btHjm!9A_9+4XyLDcHOQNPjjXfv!>C+mrP?}v zj0F3b54~3(i*a->V(pfhvzc=eNxVK^%jSE30zCL3=-kiKZ-wXb)cjUefYtXkgx9h1 zlX0T?S?S_;J+9ny91}jdJK=?sW{v#~yrz`)j>a`?eK3T>$%Si)nZm-4Rv&zFMEYYf zw^>)c`CXz+tN<8-SOZKV)H9B2tUfrI%0%T*1!3yJ0)o=SF}FK&_+!CZd|q@t9fK3Q z2h6p?1-O9!B;XxK+`{h|pl2p=;p-LN!v^2u_*vyOHka4vox8loIm+|vr@(1# zF0bXv6Wf(CXbF5RzZ!oV_@+0PH~nqko8AJxJ@nrIeC_e1z=rQ6LafC@5Q0L*9 z&We7BM;TuwPJ84f{IUb#sKXXoBP=dHr79zIKB}bmOXNrTt~!vtNAh~Zp#y*4-DGMT zxrk27&XmZjW>)gF`9CP)@a5AKr8y5V&}o?B!UyRs^QIs%*!P&?q=W9i>`OFnHZlmW zAf_ufd-DPYq*yl^_&he--t#azdS8-b&gQ?JD59#j}lre@KfsUg!+{d*tv2fE)Vx} z;_FFnqNH59KUF7A`|i0X&W%NB-%F)bZZ;iUBi-jjyZ@?|6O5#nGlrTk zi9MXK?5^V+&Vl4`M|5b1jt#-3CzrlgxR>gCvG0@F+t;;k$_5?A;+U1+xB*W`X5rBQ zPwnV>T-ZpIb{wHCRIp~mYDvGCE}G&lZ(n8b3stCaRO&eyY<ng6Auv(q`UmZ0Pcdf^%-9qAcnm7+!F6X<)W$(c+PF!0V+;xV0Z$QG8OsbkJw z6cj`8)xaer7IJ8fq6ub?UM9K=7(`ID98xuw8I6ghWsXx!Y%DFyNrhdds_RhzVFCpe z2nGlf%1Jirl>@5}cf+3ggPmV)`ceV zj#pvV&)}q6{!>b~dnQNCX#JxmN9Ko`}0rym!EY<_XaPVD@f6daS=Hi&^mWhFZO+Y;WG8Ybu z&>Vas%z(9`wN$SqZK%^)wzvgT01+$Bm`xt5 zM+I34axBbjuH1SP6p6?eU4+IP<*ON2paqu!2Iubn7^rZXR{_W6RfGA>%v zf-VFo)A>!p+_!II6#NHJKTmC`WoMR3xtS%zsCI8oP?$VgEuzvgYy2z=Kv2LFX6Fx8 zCw6Ah!cVHjnuJ1X5gq}V!%r56uA(qWii4VB`a`KA`^qBF{D>)49n1{ifQr8BP8xF;s{3-5!(>SxXCE@I z?Z|jsrCIVogiC|*I#wm)agEZMu`Z+rsC8B*NP{{6qCfuu)}HDT4hb`MHP-csFO9Jr zb+TeK@cD?1K8xL0JegEUW%z-lAeICbgm1$6FAn95V};9CA=B2o=ddDO1WpAH?gITZ#r47II-Ulyf$1%`SVI#*GL)TM zM2m6t(7l#2uVfG#lI1OwerE-QzQ*F`jB1!2+Dn1^gy5!5P3Y&apTDP)&EEsC0=< zmtBG;)S{(Qm|Lpl7Hj#XvK?3q4wQ6cTb>O;Kr^h&W=NY|%H%>)=9WT>PJT{ZvHC>@ zsM=i1gAXnqGU4*bjhwkW~y!tX)=7bCj3h()4jQL^LF%nybiny;5RmH{Z zGJx@dn-{u*TH|7lpgb?7T7G#kl-C{VPpdXJSKw|zbT#(wK)e(WbSDAI(!SuUY9D=kseP}$V}v}!@!uUZ-URl9_~YM0O&Nf|C- zQngFyt9A*Ks$IgQYIR~-wQ~2XR+4_zE}^g5B}}Sz36rW_LSMB@m{jc&x~lslA-enV zFbG~`^kJ?TIyH}$04GB*)1d0>hDIANcwrK7od-t*Z=uykb(yC|^o&? z0Nim&8Nlu(Smv7z*44H^;l#kB2>)?~XKazhY39W2NBQ1A&dV2g*`u8Qq7)F!rWRVU z&+H~}_RQu_i|l28&Ks+^x=NQq;>(#fv*Dp)%Z_Nv$tCN$@{x+!Vo?aJDhHtgV}GgS z6sh*8+I#h)YBhLnv$reW<@3GFC$JWMSqZE~x+QX#KU4)KB)maf0j7)Mi^$CRXSN~S z5eZZTa(kpQ*rp!rNu)=xTN%4hk_=_oEdlC~i>l&rn$2b_+MCZ8juelmE4gR#;74%T zScI*SNt(jAVRFvKLA;K-MS*kioB}HW&Mmlog4;AW*v*=1(RSn9d_2!FJTqSa=YNz6 z3v-hv?`Dq9kHnS9y_{9YC!%eAEd8E%4+Fm<`x;ot=jYkT?Tz=&fghFD0j@u9?STzz zmzDw7Ot84H%%}aHe0^WMPnl%~MCNXxeo1`EKxtFO`u=#o0%T1=isH%F0SGU!o4fza zLQg5ginO@t4*q9La}z87h1_`{!~uLt?Qr|SDEJs{>p=?!c(5NQ8lLNn9=Y{+aS*V6ibgrokml+e* zI13}m-d|fu@_26Ik23xY`s)8>SzUjda`+Hjft_)oZzt6FK4&X;i>=FRO6%9*p>U=4 z;ZC;oVxxs@!4bqKaueSM*}JNoYPZQjOzQLz3NKiBo~ir5lri5<5iS7R3(rtq&Kr`0!ltMC#qE z_Dv_oSLH{T@m1#K!m*VmU!5MUz=_7nv_(y3Uaq3e(Dc4tQ!8i2WtD}jqi>HC29nU| zzuDuX{K!p0bM-I4j#FufQrKz@ASn+R+_wtc1l+|XxTcidT)A5|6((vyXsh70^L z1l%Tw&yN`6&NZ!yW3F~P-Qk+KTpBcXDf(90c63+cLRz$88<1e}`QRxljFmh@2 zS7NbKSxB7YAnTXe89dQtXl$@mb1f)Kj<%D6)cF|S{T&%y9D?Pf7%xtixA!2Tjbv>N(ry)J|u$4Tq4{9I+re27;#E^~qnV z;m%XPZyqq0T@x#KC9UR*_ye{EiD@h#JVURt;kLwZJ9v|hOYA4@0VPs*b10jJ*{IoI z^;@SMFXEl~-}H<_tV@4Q!SXJjHS3z|9g=D+Uq*Xx^|W4?Cv}Bt=?U~|_i&1OIj+a( zUYFod>bjKUV>?j0u*Fv{k4CwT(BK0!?`lCCVR~l%_g%XDz)Im{ZYP1`wq(r#j)X>t zHgnR0dEN($mGb&NAfa1=V6V3ZCHqi7p-6h$*2`@0ufXz>bK-!cx{bZJks8aau2tI+#f>*Qr*#ENq%*tq*na-o)^XpN}nQHI3%-hYr-&Mpic z6!3Kg;2x^j`&ZuN9LippE&~PcM_#Q-M~{l*Lq;35ucE-EKob=^Y+BjKD81*N*Rp9;p6 z%VQvv);!!DAQfHoSQBS^f1@6v$)Zq_Usq9FU*eDBclW}O6E3Z-!f#5#n^f^;#?t`? zRq+=^1YD*T+9|lbEK%e{&SW{=g}N68U9MzXd3g$4R7^7B5Fc%lzl+U;)t^BG=uXa< zm~HUj%1?qLpd@QVE_e)G_)>?H3Jz@om9j=U*mWX&?_MP`uE>~0PtV>rX!K(5uleo$ zi?u%w0mP33E+tBMdr%|P7smIeE*~VDlv4KnIG*C1pS-iw7Cx?lwL<;W<)nzJ;7Um0 zUNPI@=2P?qv3ZV^S`mFfZQ)Kg?sDviU&r&51S)_c#mS#_1=060Xb7$4-whAXN>r-HCs=AE!TG zX7t8pNY;Kys^tb9R=t=VJufbfW^no<>85q3NFr0$-oM6sb>aWgKH*iN&P|#{H0ZXd zsrhntIl7>mpW@PBe$K~4R+mj{l(JSFZm2~Hfbbc9%DO~Lb&QBrUw(iVU>Kw&o1XB% zNa=0EV3WRH!M~eAL?wpEfGcwo8K5KQUx$LY_irS}k+uj()z#+G+t$UDcskuU+CAtc5A%U03{g*HySaS2Y%oWo;OoG-COD0wbyE{9 z+eZoZlP6o)a5SHj*jlfiDwT~ZR=_PJ$vAGFP<$jOb~9%Cn}@khDc?LI!Y`B%SKtr< zzCHn8>#X>-cP6b2i`M)ki`DKHMBh@;h(skho^}rIQ5*ngU~%c7#IE4r0dy#Nw0!L1 zcR!dg_Av541w@(E78XD2@6hX-e#2yd{HC-wX{Lda75^N4@^Twfm$WxUl;Kk;y6jc1 z$NB|XY;&nMO(JHKA}okYez`qjO_e7nW}BRtbs-3F+{*wRbem(tb*7%mDLSBFEv=oQ zvuU7r=ik9-SSzerMvGoHU4krt)@_`HRa(JV8{eL;`w*@yw>hv*DcTW~l?T#jtmv|k zxw1plN(lcNIsVmy?RcXiq*XH*CxN~Hj5NLl*u;TyZ5% zdt~ln%lluT3M3Li4#`~|Zar}}?^mh~nGRR($XZS(1LiWFZFDjGS7DZcz5^#ynGC{y zByOgcxT2fW*RL%e@9)Dy+q0jvva(ArluF};ZJSXq>>pnO|oV~tie8EIHHZ4~2*&xXFe z59Sb*tm(=oD-Lcr80lWm+T%dP@U@@EHLW$=G%dQ8X(sjfiJYQ|pHDn~R^;)sdS7Zg z6$MMIey7y;stgN?Ed#zwf|gNlMxEaVr- z*}pSFt80GY-;>fb$BqSg6lyTRjSZ<>84Qf`q9z~CU|}16JR=n2l1*-$h>Itj_uBk| zyo``(Fz6?&vgS~jSQ#uMmRP_W8#S5QiaWYgRq*B99&k}aC}p|0w?JKVnbsj0H~cCqt(*)XQg?GX8@zyS zeTDj&zFce`@7j%~}=g7MEd~W}) z@08QS18JH6G&)2yj^tu7$5<>eenLWxbEq+doDO~w!h^@Pdf*Evsw})t{W(yNyD>R| zkPWo}HZHzklsUi|AlHVucXiAlkXvT%g)<(z#gk{uPUMwFTfkCwNHSA?d}ehNWG+Q(KSxJ5_V13? z-fJ&AqP6$&60N<5-@Wx{?Pu-lXZZEwD_<@cfn)CMHSUseK9yej0jmR@{c8N*EgI+s zi(bK-7WV2QfUQH$ZoPG=qte}Zt}u8y^-6X%u*AO`P%|#^x*EZ|3RqVYvaLggQlc&A7R ztWy(N&%+@X#eAbP0o#>IWEb&+o!NNfx>n_dKvR$W2W>9%uI05T9nXa%6U!aQU! zr5b1h=RcrtQ~7c79j^67P0rn0g9^Su%m!K2AbJ$?TMb3kz+Uw{nbpvLilBxnH5BKI zx_F5=^&T3)`48yZY-wB#*z4q^;yd_M2$uH#=Si=38S-FA0)%>YyuPDZ-z8s>(TQTb zYw1K3?^--jJkgOnv%VvUccJ&##T}r9cvpICxxLKqp-@@lHzGo0Np=i;{M#Bq_aINzF{WGu{zj5TD-}SNC*ulV^uTpkwnX8>|8Mt2Lj@ zw5O9NQ77W3gat=*;!s&OBs^ta_Bd|#Iw9sv@pVMxCkn|2Vm!@qwiY=@f3+*&%7pBR zIF~L~XpujH~-7jDHB zvgpe2p)k~ERf8UMsKDWBlHxX3lK|zbS=wApVvipNoLLQCqdu$2g!~eYxOca)_s~e> z-8jII=cEz2)@T@4J=oSlo0KnbaT?+Zi9THpn5F*ES*E_jTc1zc*#~qfsNMUSHJ{o) zr21JE9@*@?S7_sO94^lERf@}Y-j~F2j_Buk_x7cu!Ee!qA9myZHTWsoF%zwPOR}@= zY$zK0N28VMLh_}_j1mH_O_Q#;@Om<@)QOJT)uz=^UfD7DSy|bu&(0K8R#zU8zSpxW zk9O%AmaU#!dD>t;+wxbNUe$(df!k{Fmfrbk${8;d#}QYJ!(8Xb?Z4Gog8fMet-Z1t zd#&0uj%5cY4Kici+sh&9=x~!)iK_=4yp;m;mGv7R&2uK-Vr*cpR`1r{Du@cb8G6Ah zd?(%LF;MeAliq@+X`bgec&E*F!LxUp`}jYB=XFDUOs^gWmfk-&-HUov0zLI=W#O~x z)t#=rOmy&_{g2$rTlLYfWc6s} zo&Bi%%KP=Dd<0fxTE7*#4CwLI3e_XBas?jv<}HijI&Xu@%n*a>RDC_@YKgyx-#iXq$~H+K>|p3 zI8BGl<^2!{l$bxSM{fNCdSE8{3--*df6$)M`Y+luzy3@1EUf>sJ&WrfvS(@if7`RX z{wwyZtpBP#tLq=OXKno>_8eLNHG7V(e^k#*=Mq}K{te#Mht8J3(U3KP<>|*zxZoTL zcXVY?!qw2N!qxDha9^)FVykd<%uu+8M;*0QxH@hq+?TJ8+bUcg zJQVKBR|gM;`*Ji8L*YKX2EvDD?5x7?Nr&t&Gl!wpI7FSd2um|->iqOWJsx%LaWMij z{Sa*FhZ>yb(P*R}>gx1E{g~!aBhnZ_p2i5=G)8^wW1RA%FHaf`{*1YJ=Vm(h4lsXf zI;Rc1qjQe>lvjR1Wj~J>&+lFbNk3+G~h0^*DV)vn#XLH^TFPa zK;2N56T;#`Na#aQv*1OHHHNUP4~u$jiAQY*!s23_W0Wo_{sKtZCG4U;=O=>|0Xmfv z$1xGk)iOphafkxJ?4FmgG3k>^=6Psq;u|)P&DZFM!LbowTF`Rcr>y)_zmLiT^xqat zTb^CQorT8fYO(VbdQEGFgsLv0T+FY2iBKz8sFLb2X`|2)p%0F7jt&;AUl)+{-bu}PX^>{(j>EYD(Ol}1_> zYXW;Pyv8k8Mg(d}%39vf&{`qM>!zot^qf#eC?MZNqq9Nn0zT2&2NSOiM)jVo1D4N9RjiwkBK7f5xVNEE3x>k)7M^7c?4fXVLTA-tODW^ejC~&pw@y%+O5F4A}^iz>u&6 zNLa%XW)dJF0YnHi+yO+A8HPnvHd(^rfGiOd6$KOpWD^7x1OxPG`X3U6 zt^wve831Lbvm09rnqaO2@p7H`p)ZxkraOaF8_%|k`vA;3<`K6TZV5CrJn0Sa7->JA zkLYd%JO_A1jqBHRAvar*U>AO{Kq(2sp6a+TWA7Kb4D>G*o@sMSnEInD`py7!2;_mXckw~u_$buLy%G`Bw;c)t}ZCR{2ar3{Ap+@1&vJ$sjW z_7#s#Lvs6-cqa5Yobz9Xp5`*jl3URAB}57h1s8y%`gn%ID{PHAl0wQzRFRm&CqInW zCTju8R(75&7Py_D%LOs`sH9;EI&3x_IoX`M1v#mW)IrLy-nCN3WmB~oc^VAHCLDCX z5JG5Jen8Y1mNr<$;&ID5tiG_ya=GN0b30OpIUe#Ux(LPZnC%mBpB@oYTU{qFZz^-DmY8wo>g{A;G zjGAlky}Y#k{MAS?m^9d?&l$t1{#pc-E?KFA(z(E)yu5{%3&e1&5w8RWd7`b4Vr-A1 zL8S%^HT8p5xaW8NS){0|)|7ui(NlpX9!}M=jCOi~yz2cQI>vNwG4c!wQPO>PS3BAH zB1fV6QyNt`FWJ=}LjslqjLh|sW6q{D;Lm9c+tu)MBpn%ko}cLO3;baH_M&{F!!OC# z8-7{7vEdE!jSs&f-^B2%@=XrECg1Ym*X5fUenY+$!*9yBa`-LzRt>++ZzLGVnWwGM zK(3HFIq75M3<84+mPQ4ug*pVfClZdO1heSLZ*B#cHRrD^$r|R^lV63tEKug(Tf<+4 z{#u|cjkkus3cXdJER(l}zY4ulpe&)chQA6$my6U`UQd1n+U+}QSaeT*6|~%0LoRso ztDrrdHDrhSb!Y!k1zDfRqwH#TK3@`7aC^&@~=mT8&6-@w!TW-J~i;$TJf!%JRFpJ$x z#JISHWE(gOv+=_w$jLpBH_S)Cwt$5QeZ=AuAjD#`Ay%_V6y~8D>-o`!avTFm6z0QY zUV=u8<23IFa?C8V>@*hSY>%8cbS`Ndcc0-@kYUq>N z41KK2A{AC+(Z?Dr`dE2IAM35?W0e(stgXPOW#fDl8<5rpyF2a_Zf7;&`bRyCFk!yR z<|rW(;1vGN!O4ov!O4`(!O5P@!P&q!2PXqJ2PZ2x2PacE2PbKOT!rlxAW?d&rAFd(N&HMCHAg&_nZH*~3`gEF+CIGm0LXou#Yh1B9)U3K3AM1_S} zEO#<{e+06lN)3rIaIvE>bf?ro* z`rdM&l=x~%7*FXjEM@v0X4oYqVLY!_jxaR#zMB|$>*OL)p3{@SsOiJX+xYjD1aikt z0zK0QlYHYpR1(NtI|+=Lz5^Nf+mb+@+LOSz=|jI^{7+C9wjeztzS+L$JKj&0_*VLL zCB6gv_7dN&ey+sV=g%ndb@|(u_*(s4OMI37zC|Ck*gQ4ZN{%E(C?43|t!>hYT)FA{ zI))~HX)yw_dw7ZOc>lN(-%9_K65j#-87015{qstEeg0)7zApdT5?`zT{SsfLe_PSV z?DD1nn_bHA`0Ty_LG$k|M(FACe^cUX^`9#7Rr)U#eI(7pkoDw5Dr5n~i(`oYb`cXa zKP>UJ`u{BPRr-WxmeIJ~A=9MO;>wbwVV#XP zU273}F4~f|A)x~@ywc#t&-fA(^!PlRqPj3nBynQ|ZnR5R4IRoRRFgO98ragg2FqA; zm9%q5mb6I^7pSn6V^PZ-Me=K1$13#8hpxlW1zTt6m3ZbrB5<6`ZiTi>l@W~iMDv1Z z3jm%r12=tT=crK%x0{q=7ogU}JFuIK1x29ojpk01FV<(Li^Iu%72n*M*7G%bzG6LRUMhXWL*_p7y{|~W=T$)PuSX&=X zZWKYNH_XVUBK|C7%BHSC)|1`JM$pQtkW-Ib>qN{ikO?WD%8KXDEz&40!NihcHw(vc zP~=ji|AS&~i8BkEi#nlPN6t&3&kS%7PFt`X`MWctjF(pcZ=2p;(}#Ml!p9!}8&3M+Og zigO5XVxp>QF6yaLanT=$5t~z&3S|@4a)R1WM4bc;v5{)Wdz9OuW91Bz*ORmngdj)iGjEWcGc8gd2W2X9+o7afB|o{S*zp)aE` zPV5L5`DdY8vk6tpv1YoCcCyK0hj;-ZVK+DI*xnENAaTeV2U{HGTCH_UF;>ozA`>Q&yE?fezop0+sLf1+8PWmTCi_*7O`@F(M zK!sM<5yyG|0>Z`&e`OupUF!)gM}F<=k#^}Tyz2y~)|0lzPu3V4o69R3i_QVNsmF1v z7jd>@pYMpoU^VRIC%M6aF7(xS)fd-)OaF&A&$W}aV{aaDzb)yZTSiQDP+|^V6N}>& zh=i+~7#8tTNIIvK`n>_)$(}&5Qmf-XCch> z<7CFn$6XN3-Xt@MZ;h9o-&^5Lf?EX%5)jT}jtpdp%Z#D`?Sq3o6t2)%q9`%5l$~zeI zOX_Ybp0IB!jSw5t%GQK&H;P=3`Lft%;A9%o(tVolRG_wYXvQOwuH)^E!1+!wjXCS! zH%|6oQPXihl-7qB&PO1yWOfD4;K^V{wWCu=LsT=d!uIHOJ2AJ6;WY3LxN*hP=_Tfw zJ<#fA50*H)N-of}SIF`xE~k>WLt6}SO~P6gVuxRtpUS*< z7+HLa`}I!tFv%a}x&@vi#W+aXLpF)9!GRPmlg{tsWOo!a2vi%;b`34S&~S*jBN2N{ zzSGH06GRa*T)5BaF9#C}Rvg}GgDGUTUNu>||IBwMtS&3-W~R5G63M2SH6vvZnG)q^ zQFQ`2h?pG^?8r7c1<ksC%f(KDmi>HmcaW1= zy?HdWM{^T+RlM*^_B-EY+m1(Nt^svGyx^lX@Bwh0yHIjCyC~G5Da>n-f(nHgfpH|P3Jns1J9ZtY8jN|_-hY782>D4cyp_hs zMh6jy!?qbme)3pERijk$ygie~wJFa8y&h$#33R?MG6W-7HDiQv11b~Ug&m4SZns07 z{6O%?8T0`%iHpkdW$g}Nhj%L&qg6w0%{CT)x0uYG4P~K$mGibiwC}7 z6NNR(Lnoc6(S&wnCF20=4eBcNVS1+?Oi*K&V49TgjY$!aAsPR8OcF;6A&xN`4P*4{ zd8WQNS~WvT?06B8Gn8aXw(k6m=)^lRL))U*Fzp>`mv7_H!SZbyYLRdA&|l=+GPI3+ zTZjHG-?pIv`L+-JTE3VqKB11}(9hISKJ<_}QbXscqhe?)$lCgjY~|2f3aJ`;T^-d! z7pfyYbe%eChE7pO?GW0Fw|f`Af;P@;;vvT$1<^5x*paWMU8?Qh#F4IH>+9>XDzDWNk^NtV?j@h zYoHs3b^*=Wg#9LArA(y|-dc!D_XFYLHe*%pr(h-e9GLz?Vbe_vNwWhjDTc#UJf888 zph|2>(#A=M#Vic1XgG__ygNY2o=;_;a13PWN91iJyIs*%6k`-jEF#*WxplT&IXuaMDoYrbePUrc_|ylf6E#UR9kG)*CwDhe zf+d-J0mclGa>hQi9om$0$V8!xm_!X@ayY@xEoWpxQp`0lkoBCYxd)+?lVhRa!X@=M z2aS2yVMR4YT-Mom$<)8BG!d5EPB3vl3|7=VI7ViNv}~vC@H~HgX&k0v;{@6QOjU5= z8S8=wTP>Aj;s78T0K@@+7XZWoKr8@=1Auq{5QmIO7eNMYDeVLN+X8uG2k=1XK?m?e z=s^dtA@FDiAi~LkHk#kbYgHv>T`HEHE5aY%Ji+>?H#p5?#XFWsNP{dl+!7zU9SpED z{&11CPxOrG^?3ukUn3^jd-p)l~#pVup2wF4LA>q1c5S z2wp0d!StEal=8SOKnXUhzX9jx1MG@;fQ>^+L34}2!X?<@R}08-<#EieLECFBw!KGC zdbYhsR|$NPo}wMnbMOXsjJan^Jf(G}YoO^!$DS$Brh@gy zj0E0C+JI=_HAajo<5!|W9APK7&5LWO2yLtkZa2Ufj;X4X-P$Wo*D-^|^ie14JVNLV z=DrW2qGFXY9*wv^DXn|4la;#esqp;vKngS)xLQU>9+|4wiE(TypZCOziR){i-3{|i zG6XR&0~2!{Xn-s#>~*xv)T_w4ZzK)Im#p);Yes6uLqJFu+^mx?BHnGxui6Xi2_Koj z25Y}PM=*1+6s>_D*8>YM8PJYFa)o!dr;OD7cSPawgf_b)(&wL_183}HiY4$*Df*dz z|Ei*&`SBkw`k5@)AZ>3gzCSJHKil5+^Gn*^qQIlM2RBOE-i}^&Zfmi+L#1Cdzh$g- zddh2!wd$M*%aD}Esm%juj}?jd1iR*O=c(SonEbPnJdM;N!{ZdtoXIIeF~Z`_80b#f z)291=h^YPma_lu^a_>M2)Yh6O{u_*c=(vE~2M7oHN(=oTcu_aCBW*|y7rJ}{t3g?1 zBk!=9ms41lD$ZJ+SV9Yi^P}`;GC2~djrr$DXoF;-Htt_+y%L)6$822ja$K&#g+!8G z?tR3!ZhfKuV6&+AJgl>4_>FAG?k^6w}Ot?(Zx^>R^EH`0z0;Zce4MWQAe?^?*x z-zG`(Iv!WTE&RFnKwM5FsVkcMGXb9ZJoQ!N{zPC*KQ>NW!x9Qi>Ze>kDUDvG2LaNU zSfsmP%N{YX7BjcA&P#O#Hv?$=M^GNee*wQ@oZld-Z`^%nFE`-XW*p;B;GF-ioN!}c z2sbIH=!bQ{iJ${0B?h0}@EItFgVwbr`w(J10WG6iPvFD?vlRLs&uU=b6G(wC)ai-zxBA;p z2-Ulh5z5<1(^Z&qLI%>67kqKvEKy=WN4Lh{f&^;78V0w{x@@px@MI_TRuw%7Sp;!v zOZyBcTNla*cAc8EIvOw)?BA z(Niu&azP}MKiEX&GUfk*G}554Be=jC7!cCgfmvr%87f_J9wcJ@N77#3rXfzNB{om0aym=h+9CRdjjjayAg%t#DAh zT_qQ1$qRdd3T_R}K%g^#?@cdy0t<(Xp!S0s21F6Yo0oTiErf^bi%mMuu}1ZSGu*kW zU2c2fyo77wsJJ_1EES1MdZJh=A6kwa;;?q#!-$6~^;8#)X3f!sYq4yyw;pt(*@|9F zB=GI;P4=A$+`fzPlklifk_q+kh;1cU)KV3_R8A#z4Nt>aDDv`)fYhjBjx|zTRZY02 z+UlIr<#@mkiY6K3DM3^lq%rp{hY~5Z;;F(4<2j>->E!#6@)WKZ^Zsp_iD_c4uiLxR+Jc{>P+qucw-q@ z`W8}fVLPN7no@aNyA-;izH?L54d80#=uBZBRAeVyg?(A0xROy8r^f1XXPNqire5nR zBIl-lF8QKbTQsDq#ROGi#6kyn;cI!%%vJvjda+OETZPcC+ z3oJn&9%l)vXO8V;R_#H1%yvhqJt*s=3^IE6=JO`@_irHYo6BC`_Ym;E=5Wp#z`}SN zFlZ*?w8Ja@`K$lVv+JLLNxy~d#t_eG;`OViuSUt$iK{^9ZZ}v=&(wr z(!s=;@0flDynBR?7*=u3*#|7Rt;_Ph-@qM{>V$4dE3-l`iMHVmitaPc!n0o8y>f=Ph_`4wR6j$1J{Iw4VQaTKet3=8oJ(UkI*+nn$Yq;WV^+h zy69{yI&tq+fY2N`vFcWHDe3*SV?;UTp-$%Z2rqHrbIckYYrAqxy?Nn-fPb#MOQU_S zG%mc=g#TlLz8PeJ#Pu9tqG#NMPlv^SycE$mGy^ZP*ATyMLD63kSH z$=RV`b|4cItQcX#IMhcDRBniMvUWD;b)t4$zoe}7=CT;{Nf_64thi6wx{LJ^7dbjs zu=A0zf-9?WV@1Rqjx>J}#=Z}n4IJilgMV?CCR>?qmcF= zs0n)lju$~=H0XITZuecdj^7sPort-Uak|@_;?b#|3dg?*btMW2ou?x2<;KyYRMdRP zZd$l1hvp_riKbRm8~{uT0O9~(asUtq09ynAaR4wS0Eh#CsR2M70CWTZaRAU60K@^n zmH|K5O!?-54Jgc4YsFivd(8ynSt>7dVkh@;Q_ls$ArG>B>rOrh9&L|*feov@Tm|yL^%-X+BE=gH@~nk%3RkT*wMql_vWa$a z#B()>;5D@bV3`Bw(gdOuT#|X&av8*ik^mwRX_gT*%ZQ!7m6?0)HL)t&CKsa+53r1x zBrdi_qcSE)Q zzXtl-s7=R?cw8{M(3(W>E)dMwV55O$LjDU*b`eAO3qqkEWauIZUFc-@XXw%(6iuF? z`wwD)na{(1gQ05E!I?N!z-rb}p0B`j+Q*|?(euPH>@7OxkT6dTP-nIURFR{&$tE1^ zw$FE9T7*16af)-jGn_1zwn)@Ig^^7%y>t-IrkAZ{Om7IiNAgsA51}LN;Fr>WVST}? zj1ne0%^7$SmkYo=FGvK%D2d2C(!B9OjkkcQ?H;5C5;TxmFgOXjIA)-{?+?JV?Atp) zLe`12XmHYliu7Ya+E+@EGLs$#w7lw5d|5#OR@_%Cqd?CWm#s75{k55kay@(%wYaG+TQ@Bsl{aCBGe*<@nrHy3|3QJ3_ z;jy4!E6NRwUYqOt6P={2$JOvVU#NEIg8h)7j!LKl*3`i?9TFIF2_3A{ng3y=Bs z?I3u2l4RJfWP=cRcVjF=o+lA6gCGAZnyV^_BN<;1W}GWx#95_zcn?hJdmTTvfO~~_ z)K~)V0j2$*pzO`$i`nERBT)9&Y+grFycHmp-F196si1>?a~r|SuZ^(-DCH$*g9vYt zEaeZ*A81MD7ss;GdN<2SYCI8Txsu!}zlF_zkvE(}0;67u;yO{zD%f#`qx#wYZ%{Zp zV`iW4KV9^*x9^(mU>%&vWzZYSW;WkAtU(F+$Dm5wc7o&O4aIQBJdLnlLB7$=1Y>a| z*F+3F%iAK~Xs%7Z7>l#&h~_4%!^=%kM=aN&j(BcMI`7Y(4R=eu=2I%l%hkFRr?A?*bvY!yYglgUf;n;Y7?wbKH*_ z9uWAA@_HGVDYn+q`S4nRK3w5pyrF{-MT~G_nZh6w!NAQ@vme0%DpI%=_X(ti4nz>H z9aw}9?7+AzVlT1)dfbv&`cj1ukAe7RBTHQN9D?>L>dU~)Ez(w)hDzqdfnCII1^^5W z$rGWVbEpVsmbjAyMOwTz&DC8K7J4;fwY75Us{nN++IqOYgARYjE7b9P8M#jsPLkg* z;Wyqe^a+Yx8%-3}z{{?kq`Ah!Bf-%|XwCkCa7GEH&aE_7MtPE2pA%k?3xlJ|=q z0L~-Dw6c?NL`@RJg&1N<8l)+cpORFO98={Oj8ydkqafAFXp`hq6v~s4)24#t)T#nF zX5wgTJa;v7##^1UczuFJp>%Jdeu)5KW+FP`rOPEk3OSa+!oyWvb66TGv@5WvV!PW3 zp}&>3rBAzHHPmkWebL6N$~Hoe1NE8kXC;!e_vlpeW$-nu0uO51xo}wBCfn+Zp!X>0 zIfWAig>8%lz~y>lpgIJ}PoC<@&Bj=I?+)QiL7k0umaK?i;fHT+BoSMdj>MPcj$j$1 z37Cj49c)|%-bJtk7blc-k)b^)*?7$)iCvWP`~gswq|irI=Wd;*0D}3 zw-3N-P=MC2;3e@jS9-X7VNV39+K~-PVr*xF_D2wV9Q9uC#YCO|AX-~|%~gna-U>*c z-h_1?5@*k6k9;wYrDvQZ3F%o|(3ZD%p>L7Ai~VsXH8KY!;EV$X$t{D;%VbVi8wozqH!B+~>cRGEUx`AVfpiNL_FiHykb zLU7r;=D6G3)|<}5@;BS2>iND0K*xW9o#`+Lo{F&^3r^X_<4xh+h~mjk9(JyA_inl^ zlWwzHc)I(BEmpf92j(?0N6qQXQe=w9?6FIJM1CHN)~uPz!o^Hw8*$n@i%O9v2)M_M zF1>M=Fc*z@YZgd@1GU%<%5>mmjSS5vaP+zdZ6j zpPlbZc5Jt|hws=5F+nO@;{QM4n2a`sO_yl@>vLhDssEr?z5i=|kNyJ0+5S2SMfuX}fFK?G!krYn0WsG^vznEtls+aqI(c z{e>v)io%I)%Cwh{T*32^CO@qNC95ZqWP)2koz}=DiiCqwsq&GF#bfa~pG@Jsp4c*& zV}Z+TotQ9J_gxIRC;Sk!m^e-nC*(CJKDd*{-Q1|Mw2OByL;$ab@e0~%8h(nQG+69? z^gQnkZ4^<0h*K^9IXqN<(%?nX=tUY0v21qvO1|=fr+o0-cYYy>*R7M8a6Da~hLVx0 z5$<(x=~XQ@{n*3k#YP67sMcV%R+zj%Z%MP3;2~(1h?oE06pt;%n{VeYryf*aB5%sC zWkOBs*osLE`*{H|UK;|j;uNDihUY1Puo15WQKJMv0~!!)9cI(wsJ0ca@)5BE36}#e z-OA$N-Ea3QlWrwKx>YwHX{FNhd*rPNsAy))8(#-F8C!%%2$vn}*;<;fVC1OI*J8it zaPWR`38V0jf%a#t*#^FZy&R;S! z591hc3SpS9Vc<)b#ZC56w`;vb-IpkV+BlnbNEMMxmTn9gA(MnfvG}aTf#q8Lz&d_v z2iD0H^D1=xRgLNDr2{262*gm3t{*JHXofyAjT#c7>@gFu_4rUknz6cNKoBPtkD zJ9jxM82JSdf}gGi6v8@pE~~vNUEL0TV!0s?wx=sO$%Vkq{i{3~QQHK8Ym$D%HCVQW zXT-{}<;Z8Xo!CX9xAq!VB*8qMFT$Bac~1Kkje`Sk@GOD z=5+{uDwVHwVA{>myWJb46axfHS*{rv|Mxb2+d%uW^H-uF@g!}H@nTMUY-w&kM7v6J zfb(H;fb~r^@a23kgZSuXp^HJy9*>$G$W}W`2b`tSA%@d+^otSmAXFIq%T5a3hu#xo z4$eQx)x3NZI)mFb@pyrMu)v%B74mJ78#>o_wEBmOzs={Zoa;N<{iDR6P57taC3c)` zO8To6QtltGj+B3*Ix76tic{$yuZ}9Q7e%aU{}jbZ`)k!vio0RQSUcP z;@OPdQ94FB(fiLV zdP$I*{8#1M?7u1B7XMxOw)*eMx6S`hzU}_U@&$`NRY%hQOdaLESs+YH`4M$g_;Gbq z`YCl(`PJ&E_UqJ<_8ZkviwKLGCtHhtd|CVnmQW&S?Xx=%UlU+ z_WKml;%~2xR)4-a{xgf_{#O?5E76<$1LWK656HL0KUlu4{tEfF`G?CFQY2rnXtg?$ z{_*N47yCctA5x@{3jY*!RQijjOa80;wF;^BN7a$`f7>ZRHU3!&srA36jynH5b=3P8 zsw3mCQ%8e;g*qDjtJKlt-%({*bge>K{Oi?GB1JbUq}{(m9f1^WH;zS|53`|ZrW@tG z3O2OgNTg=DNoIXVi~qRzTm7fy+vYzf-**3=tmGu&zm0bXz>uW>Kk6u#Q-H!EFC#$} z{_tdRRO)N)9oZ`XB_V@`_P)kS+vnf2HS#zvqSyM*YEYd&qf(;Ri(w;zGGdMbM}z;W z(rFZf6+oK&Hx<(CzpIWG{|ixxj+UShGzE2_EvO^w3)4ooCyT28Q(wdffytun`6NA_ zrvFqTxA>pQx7CN*0Pr?HBHwmDE?-DdN*zhRJ|;OS_p23>3QAoO6t+@xLKe*@+0lMv zNi=DrJHR!x4Aak!j4b^M2g7YT8b&Dl*3&q`TDG3%5the#nnp;;dRpq#G0HX8&>^Im zJup)^R0wAGYzSO?H3qJIn*-M_O@V8t7IlqsvfQ;(QJ*-xGXdz=IVa})`e_+YGCAsk zi}T{R`5%NmBVoBi86-B&4b6yzjuhq|M(eC}+$MFRG@KffISEXoqJ8r~qtRKj8xmNWY?fJHN5%m?(D8DIfhOMug$Kj} zeRZGdCV!Mmv^}Cq1XK2C-*3Uh%+WBwiRJg_Q=~*o$H1j^ ze5aM=7LM1Nc-zVp)C~=*vZpOS8ZXY~+ps^I6juAyZLYoqm5zw6_T30m;43p1JB0Fz6+~hn{gulEPHVLLK zCJe^?6__za?R<;&sDEI61aEInmbW((ZX+j0s~T1&8kS?Z<29{J9T zEAgu404B##*gbnAJCP^Rb%*7qV)wu<^2k7#a#GQQ?GJ0E#Ik}%J-@}#VdO>Ekhq@- zd3la`QT24(v?Uv{1c_mBmu!Z8Yiuy3kEvGR4K&2eU_KvnzL>3AeznuQ3ie9iCE$FU zjT1jf;-!&Gu@KZ18YCzY57%d+yQ;@AfNtcU^LuQ4M4MM)UcXLEEbSDYb5-!W=XI0; z4H(yYplwGDwKC63UXw1KymWbn+G!Z3O!oZ>TzsFf)Fb~ z(C4*k@w8GAVKBZa0xrBQK}eJ!*d*fNqhe8v{(OJBF&)F8hJG{XOqvD*SMCVbn_gci z^$k00^MdqS(vjvWVaLVZf!hjHkjnNOl^xK()G*BMbg|=Xfna9FushH&h8t!Y$5QE7 z6D}R;yO5Qp9kc91V4(?)v!9mz2zc?FdZZ1n`nC-YZ4Z`ZtUwjEgC`k;4cIUhDG4iQ z*dXHBFe`2nmI}fwO)Gs8hI9V%LR&(92V(j`n}L3B0F^g7f0=zv&XWh+67mZ?Y!!F| zas8Cy;h{N}CyUF*V6R?P!ZeN?!ZaxDCo+xw8RJRvWn&cZjyT!YO_ z^P==8fe1ReqalMLh<4&oJFQO6OuR(A+@sJl!485*4uP z&8qwMg=5-bM-MCXjC@)5ltBpCC zk)Un|dza&axF0M*X@^%xgkjh%O>pdS&EHU#4I(QM84i+~8!Z{$*Ib5Y7?~?AA^|vI zq@l;uV&_MCU-T`)Z-pyR8SHthb9nkZ`9(g2oygCJdPOvz(KyCMjReyLJ}QYO&5uOG zW8_jYohj0?5|tu~N{m4qMA6`TZc89D>@T-??9oU2XP3iqOD;GD)N}i z3W8izpZ0p)dQJd??PB2p)nl&+52Pld1Gr?J<-*Iz<$25%0Ep4egV?zv!TRnR&AO*g zBu6-@%%tKyPkYfpqSDS$qW$+6xQpm{#=xxP|A0Oxtv$~QbuXq(KD<{aVkTh@@hZy@ z(dO%7JWo2AF=;|hqkad=31N#Ngx|r`L>zX_X8y8@iI^4+-L{8!K(WDq2SD{H>L?+D z0b`$xz0poDQqlyNgN zws5s7WzgKZE|QsET{>=xG}$gwWTg{v50JRRS&>=$V5zvv0~rbJ2O@Gl0Xx~WA7D#& zY=fd(1uYkcZ#eQOW zetY#a%SH$~l9J#m1h)mq7%mv8d9Zz1!@$ykECWrf>rlHcdg5LL=6;CgJj&@g_n8;+ zOWQSZ0I(S#}8x6Ao`=~SVfH~2!I|P=OXz|e89*%>u*_OigXqw~&#fgNp})(A;t??JWg^Ier*07yx0F;;dm_y@89`EhSz=hFLcgMAwB@ zJa>Q0ePzuQmAjcgqHO4~t&WV<#WXl;NhY@fDN=)5C#sGnC9cG<&4Oz*bFkC^1{9W5 zbmXx0jg2)_n()Xquwyr`i)>^kXVk(aZ#?$>U@Y{;Z%EkC*0R!1&G|k#4PT@pk~;`#vqT9fsV8Ae8LJIW-En0=Gx8fL*`(hGn5P0U zcP0|4jgB0E!lfhYFzv+{mG%x9tgXfjIClm^G2N9+#0H@IcjU=zY|9=1ifXNs=&rUH zxcF&4tlnvx#x1gOSVk_k#ijadm{iZV>3f_ecM5FFhL=)+-YPMF1r$Dr7;*LumHp=ZqIuRu-A$4u|Jwm^60JWj|{&sI{jjaYHMcp3Ds`1q{%uJ6e;F4A9dwZopCTo(EvMFti6J zh1l1clBu2Aw-mz}<_hU4*xO=3?A}%fp7ZX*rCkW?#BSD>89e39IX`Worlz+XNayh6 z7wO<6HjZWEmVs1yO5;+1*I8HRz`BOQe(VA?PDdjKvyzB7f{h)%Fe1v$5~I3i~=5RyQgVnKrJ;~j6X5$DgjYlf%9=l&f# zVBiaY*yK-l0E$<|=RU=Kv8m|}?wWz_6a>StAkD65>-5%hFK2LN0!Aar+z8|b7rNpx zaU7He3sAc)xwQnEzH5cc0&7!PrgnO!c1HeW)Exw4dF{;nzBW>N#$bA;&8Ct`&lo6$ z%w!Z`6>%(NAShgVX5&EZ%rwBr=dARsp6g9|I>sYBZ$2YiJy1I%JzeDy!P}&_nfoO+ zi=mT|*N#NtSZ28+T~R2gBT_g)9f`t_Iw}h%(NQ}a)B4%iuZx&FQNAV}OYma0>tPBv z8!AvZY?kN_vWH#2L0H#{7{NUdxb1$TH(&?ao_nCXLgx==qhI+RX6}Rd7e<70V7#Bc zVj_|8q2e1KiXp&K3;O#(l;cg7W2hHGp5!T5+(_>>3^wX$G63TZs8I@v*EAR(sEEe3F`^sg zF_wha66DrI<88L3a*2XKuVo-%i(;bLy7-_*rOHpE1_eiGOAv~ILgNmGaaF6>2C=}( zVD1pbqVEUH5|$rw%>gbH8%!q#(uo%Ay(gpTgeF84LKV~jNw2M#NgO6m+H7(`fp8Dn z0^EI~9SE$KU?QRMXtHlq~q&g3WA{pt9lKCb{Vz{=v;AM!i)_?t)1_0O9N{*3MxbR<+3K96Af-EzpdB_rSe;g zF;FVMrP%wV@>wzUN#z^-y?2APuuiUWD=~M`nFsgwBj$0C`Xke~ZA@wirK0|zagaA~ zXk(Bw`1x7TEJp`oTc@C&jVc$o0%cvohBwlHwuyuJqI-bOG}LR89gy#y`(XgNoW};K ztEi)`U3|H#)q^Xkag$^ZAyl|h2`vZ>E5;$D7|B9lJn!O84X&ZFxSl%zc?-@isBYuG z+a0XTPS!1wCk_oCv*b)p=aX@4Nc<1@5>92;f{EN6{hE9m{dMwf@~@R|vwsu6qX&XO z%lUi4)VCwkV##00xi425h#tW1F2WiE*egX?Qvh3Egf$1S?}f0@WpHY8qX)y;Dk+a1 z0;d@vATtT;QzQ9UFMx)LfX0b{rip;&QUFP3S}j3(8cIElrJklzPjjiKCGbcV$Fh?e zuFme5f~~aXc`P2sDZxgV3!%m0%%2_w#h~+w7C|E%h6dTBF&f4&yNckhaK;ImVD?m< zbg~&fClMPp;xt%1*@%r}w0pvp;1baqKLrKp#no9YLdO$#f(KH$ z*zJj9=S7gPoreA=9Y=0#rz2J|qJVojo3(QBP#|`=V>FrX;B7|hf(xziVkMc=JVszT zc{SRSn!P9WT}O1`J&&6a)&M8Il~4`gd7&}d5>?gbu;r6S3~N=CuHgOOf}0s@&Ri|7 zh7wmM+p55(5ZGAa!o#{(kK4;V6sfWs;$7nVLB9SZ{l{Tg-6g$|!w^_l$!%i{ptk{w zwdky29ApDsCM?zH0rVoO^~HS=yAbx6+3szs@mtZ`jM)r)z1{g;@a^qw5dYlXt@5)_ z)yZBEDr>CB=i!+oo+g}V4n55kdDtV`kd}&k1j@hm zlV1?vaEq%+5QsXlZxP-Hqtpb9QgN?3ItKF+c21dKVGI#Ng`VC;^JlYQMp*?J$-8KF z!S_AkH%zW^!Idjn!X{lzGL$k-91qKX9b{k;rtcoUwE+{S@Cp(ycOC*oX{z+AOt!ap z7fCtl^UtKO8H!vq32Ga&{K=%qqg%KLk;gpBDNb`?bhw-ulduH9TxF8WsLAd%2KQv> zX?J8ZQn&&!@m523RYIxsdI{V&&*6i0l9Agc3YP*2*RkVD6%ip5>&b|?+JqBGm>Y6j zBy)(cu`XjQ%zu(L7Dfi%wuB`-#}Z73<_@9)-NGfn%S@}CSQNFbp91q!g>hbhD|q2OS_l}#I|i^82j)$Y?4UkH1%-m8Wg{;p*D-@&54dwA}yk|CFT4ivN zHcE$6KgPjLJqu11H5A;}o5>Fa?t1gs>)M9KYxO;gji0^hDB)UgR<4gEUrVL!@! z^L_CZ-I<~^ID*5ORKwu%q*vl!krcJsI8bg1^xq9~c2#s|a!I17&c;e?a8@xlk>Qn+ zso}%fB*wulK8bA(PU03GH7B5qe^ELDch-{)MDqk4Wv?0Gv_^qrF8UN02~5IT0tO;5#adOk7SdCWX&~INyl@-!1V}1|qahL$ zb2DCiVCX^$Szyv3Jm&ouAC;6tld$p2J?Ut|Wbw)s2w=V2VjUWian>;Jv4Iv%!K%iE z{{5i;*G=e`YYZ4Mu$0Zc@Y7-YKK7J(Epcot105m;LR(lbC~T6i_@S^V+&=ECA*;Jv z^qbB0rmbs-Ubme_)A(Og0kd4eYZ!x5f=Q~QVrk5)=dNtX=f^`k9NdcPYN=h;o z$gn5#mMdE^rt+L36nyD7;)QDfr@5DlIp{mGPU2Kx2%+e_ z>Tv}7L^?6VM{#fFdLSDE;7I`XypGN$vM~eWw4mSO^E&7R$zvUV=bJ57YCl4r&j5UD z^2fge3yKl0CzPFI$}mwwYq`alI~mDH3uB!*W+%kQoS*z<#c?|rW6`>G(Dd{Q6u!f3VqJTW90>xMOh#&Ol=HfAv%oJ9fHbw=u>Avpw!Q0_ zafQ2)q4U9)FrTiRxA}zpkF+n1WV6#Nkk#ptY(2!c4*yYc&@c^s36Uf-bL)@~k{D&C zx_XChpnD1q&y}2bc86AB%t7Fd44gVK@M$QKx_afP?NBB9OCa7v#Ex-@%|jo#2x}f% zjkh20!8?xp?4-U67_WKgNd@8sVfyaZPef5}a|HNf1=c7KCl!hL<*0nNL$X~vVb~qs z0coR4?q?RH{yI>7XrS27TSK5DzcZ`dHG(O>GX1fvlsMZV&XE!a6E4&?E3n%wd6}1XBRe5R?tT)Cb$kBXklr9@G z#INSZwgYBUoSrm<(*E9&I}3!DRk#(CMGecq%v(MOVd&k8Jay%+%TI}>$tnM_j$wjY zH3LI;7fFJD{~->##$ueoP2#j6AO9$(v)To}i4Vunmy1ms^doZH4bV+}M#zkkubBpQ zlamb=PTpne70y~|KA#l?8(~JcUfc~MjG*qu5k^pVlT@R)M|TEPrF0j#Af*ckSjl$D zlEVl?zPVq+BYG+JKe!`;=jbTEjD<}-Y~;cr{O``VYe+<(bO;pPbx{WYn=E(yCs~$& zhmnmUo!Q98zoeQqeI&Ut!=lR@=z(P0%#?&2rX+;loUeRF8rexnXDv&it#B=)*`_EX zVsY9XJ_E#2?01!P#9Kf@)-dWvZecCHLeVV@!&w-?kMt5fZ8ne$nHY#gOjo;xW1yt$ z^Nc&&qnm4las#z#Z96}lmwN~~a2s-1BIif;0kMvrhRzY@XruQ6OK}>K>=d3o4YO4wq>sO`eISMe6g!JA6n;J0f@h~y6a4a1&B{a?!PEIKJB;m<}B)l6Ez8504{!T_Ud?;zI0 zMHqPHK{PBc@R(r9!+>DKv6k!~5TotPYGMAe#@tyzE6S{{xi<=~@G|MID@oT`!{&1y_Djl8H_jTiBI|=`5!;gW zHQCycqRZ&P{%UXJV{6XIf(?W!vz7#NUqL3gkI=F$_Y)ccCS?n5vfyTbnS_GH5GL&V zBjyXBU7GJUdpzm?LlQXFr5S3470%hrV$u4hcj#k?*60f4r#RW}#7WZzZq=Zlw%JSi=Z>m%dhB$Az}Zg>4$vfmHRzx%c-@(O%avwc}|zxzABn zJ(w!}9@8`~Xe(h!vox2-X)X)QWv~{qIuQohJdV??5I4*_=S%aMcen692GofBhO>BF zh*ARObD$Bd<01_rX5rA?I}}F|M~`P7LSVZ)bUar>M;2L{O972tWhKAthKDtZJ1h;W8E6Gg>Wa%Gg>Go({unHXDvTTpPbG z2&Wbfjgobu+)^IlTyt>V!xaL= zG8M-gR}mURgpP)&MVe6OBs8wh9hDst+(dRRWU7(ji%gsTak|$!nxFzMRB{Uw(VH*^Wj>cxb63lHj7Y{uB&+$rzrk{H#)F3a90Hu&xdKOgwqayBpd(m?^AIW} zEsou;@{-|&^NYa}zXkEJc3?Zz_!khtCK9d-R5opXZEn61QVQldk&<*S3`2|gj26SO zFA*S=6c7VYv4Bg%EL~CxUSh$8b*0eF^WxGV4d@I4CSJy9s(<0!%*u!G=JEhtc&l@_ zk}?;r7#FT@G>qfjH;FKjcS^@Amc1}Gj*f=MO2Q#{T7{(@=9Mb+S5fHEdwh#uP6WjP zz|{dj9KsLG+70&OQMWlc%H-t4QeP~#MMO&bxIXq1=;P)F{YAv=f%qSlj>Vx}s?ft? z!Wy17+DitSG=*ZorWUC??Z0TJGH$Npk7LBivwElX&YU)L`W!-{vR1$Tr)6de4iZ-X ztjw(LhI{`L{VyK(g&|_BeI0Y=eT?>8_~;Y|3s2F63I^7Wg0a;ooU>0rL;} zbMOkqLD&2&pWveKpJg+7sRC0U!~dh<0Jltk0wXb1)q^Xji~TI4gj*8DnfRsSY%9fZ)= z|ABU5ehD1@dFE!ozV|3ye@BdKU!iMu==v){6;>U>t_)pghoRfU#dMSA5ri@g&)i*G zX0AovlIFCB6qYo{0FR-#&)d2@vzqjP=b7!EQ&*+=>>b=N@i<}i*&uZ0+`#o+bVeFu zTMSj5>xuVGz|@ruVN>uh2=OY-+-q@@JW5$(zVdgajA}yu2+NoSKR4zeaS?XbH8kY8 z2Cl#2<#o@z_F9ly)%(VDLp9);S;&>9c5;}PTWk(8=6A@w(yPfUJq zv>YclYfe4$xJ&+J zOdl?fQrF*+OH#?0JAV&{t?$_1uTJEkz`3 z0qTtP(P`F#Pk+9cE$fobGP5GeI%-8Zl)J0%Gv+#h(kL9W`(yJ4<2J{F|$`JV&VXjr17Lsz}6=^18+ZyWQ$Z<+2dt+adQ zh=w5UDafhj`Eayabv=Ues_W9N0(pMvo}kXVe-TJT;ck`jPBRJht1-5-IjA&Sqr8;% z+2$L+H)e_S5#8V-@iJxu-Y3%9x;~WM$%sKI?lgb>TR`vqw=kpGz}(ZqUDNnFc&e`U z|4~<^)HLO9uG!^|pg;H&ce85W^dno!N|6$k>|5GZVs|jdBJ}KcnX7k089EVW51PM* ze+M#jT<9vRP-*HkpKKAdqt8OQzdz*Zb|Fu{l@IcKhLs%8JpFnA+cK1hwaAA`#8^n> zUfYg5vl9koE%`c2uhaYjmlVXGw1~pdl*Wj-2LpQ z0p)w2SIPFw&S7e|A_uD>yX|J!N@B+R(Y8yrn}03gFaKlUF++tuG6LOu^6u8GMD zO0S{M_#-59v5Ddah%$^YCqkwPL0htrN0A;Ot)>mbJ#ltI?@LHOa?_{~NDCnu%ztMH zfsk?+uvlb)f&H{Pt6NU66 zrF~F}YV!%?SMxK|ED<_c^zMYr0^OAYS#RkOg7Z#gI3W#bA_ycEz`AQ1RM zoZWDmwQO>=c^GoSSXY@t0l5w=USc_B02vj?Z!O0NIaeS%+Hw(czCtX=2)SG!pIMF( za;-p?S&k91ULcj0V}x8Ukb_Dne@9AjPROxC%@2iR9hMvYW(CePkz+r$dF}^y9ujUG zYV*@?4mXbq&LJVkjxbN+KIv-nW<;f>A1|1{B#_TaAR7cy7cJtvA~}2|2NLpv$o=2_0W6V2}pEE+v`{v(LgTok^6z4QTP=n{9$0p=fbC!t#P;C~4 zc|OaOmod*h=;bulS*ERw_4T!o^JkgPGS=yxVSdgsITAL#9~tvY^n(wAa$X?YT1db7 zx|t?v?HWS9VRjJ8|3bYpmNDNjyO)vA$!itT56B{ceEOFFaxv`mnCE0jXPp@oNG61g znWM_cv8~WwRNjT&++A-@6`ZZWRYLk98D|RR7L-dN*YlwSq(0?iW2R$czu(+o@U#yg z-A@IO@0lygMgdufkwI~OV6GC#Dx|KEo6OZh`Kk{B$dAl-1+w(n0CKarNhrVcasavA z{6uih!q}vA?lyM|r99tP5n=%!eM>&Zdqm_e>T+) z7gg>;wwLLje#KMLt7 zdr%-B-5%h~E_(qvG=}n{INO)~Ny>F$OAu>m*fO^p z=N{Cc(pgoO1*F=%7D5g$>yTKK1jRY3YzKk-GfeBGvfW(Pa!r`$FO}^nkhi7=`B_`G zA7bHlBXFH`7Mqc>0ikm~dN!qeCLpA9B)G1Sua+Gmv2KP$X{;;Dj(1r*|G-$UIM)F} z%C9~X;H)n@2{>3mLZTGshk&4KGk>$CSZwYu`>Lcq?^RSzB&0=S zy;gR+KyHL=Xso}K-7S#QLLArmr9kcvagxqs0+}D;lsmt7Df1VEIBDl4!O2;i`A&`V zra;cHIJ-D?&L0JGVu+J*{w$E6g*Xk)hf?;1u&rYb`*Eh~W5IbKOufbVR3LALsdqX~ zgfjMMh|}$O0(n2gne9{yXPQ7x59?w_XB&Z>XJgHG7CCbuZ`I~;o1cEOhch3KTvnTku%vrBI}4;EgzW9$ z-W%YY5JDC^`yf9!wH)U80B1kR;iq9q4|P^Z>bHlfAL^`>)StIFyEunAM@y{tfwTV= z1`@T(IZklq1BZ})gMBlh!@gG`1?No3&*0w`a)9GI=LybUmd?J;iO$6lw&mN<4`{4m z=jsUCP8(YHPcfV6H^a`gLgzK~&jI8*fjls^%tB6gZV}22;4^Xdbq5vkotFjTTgX+;RnDuCQPkJU z5OSUKw&0wAw#>AyaK7#QQE;xeIHx$*JMRf(en|NS=P#PN&GRYF4bI;L@(i>CT8i&D zp9D^U?r?5$k^;H?x&U&sQx#>Ne+n&!QvR`% ziH@TGIS4(rLVn^jNvw-P9^T=!McH;91fTcEe5)TX!fq{)BSOgC&a5bsF{>>Enk;8~ z!8rqv7R*xK1Y`$+l!HIJJ&hg-Bg!rUS%kC*nOb(gvztJ6L#&@*_Rx=4dG?U}a3-?~ zIQ`}kXEE|zEu)M=9(4|oSe&IO^a8HV|hn$DG79l6P3HMYm@%q)L;Ple)L*!l`{}RpuBQ_fLO+S1+74FYTX}3 zIaYGKP)NJ`YvIpUA>}FVBa-?wj8=-Xjr)S|XG_ee30Z9Bx$jGU*4kJRcV`QE)0T^n zzX%TNVvW?r&h94y;jB_2ySimwP&*3Q-Hm#bAJ&dS_HwHP!nvP9_QoA*#NlYJkR@(b zASXflaV};&{bs=J637jx8HFr!cN55dm}@Cyx%&k`V7qmmLXLM=x~m1}J<@I)a6_X5Egz|5SGweAV-O^|_VQ-}IeoD;7IK|N28f`3(0(k3Hl)=pmKzx$YZ+ z^Bm>?cL_HxcHi>Y-VebXKq1$;9|=w)_^gm`yBh_v59(AQ*Sl_vlphA=TRtUMzvFsX zI8~cp!52W10(m`z+~`)u*l&FQug0uIuk@*VtDAxPpxS(jej|W131raX+z6ajq4N%6 z5a(S$vVt=;#JS&{A&@VXKxRvR-S74ZWL60Iox4zCJrm~VY4;$3TpZGQ#$6g? z4ek}jde%KuAn%8<-f>S7%2grGJMNc-&O;&2pWUwu&Lv?f-gnOvI_HFC|G@o5jIwd8 zrPFUda4$kEV;+7$`Lo#k#T^qm2Zm{F1cW^NBuvXht`$1fXkRRQKW@QTFF0?7X+(rO zhB#f3dV%zXlxIY80x3tYe&KbL=NXZ%IOVw#z5vn-2=-9W&nsk`$To5I0Ci}sgq-Nk zj%+Vz-)#eD4Ng-3biIAz@cPHRGbZ7yYSqF{#hZj z04Ya)F2V@Hzvs=i7P2>TsE~dOIqKd3vWxd?(82mEp^$#FtM`OJI%@*RZr+m<^0SBc zbUcYz+_T}|^JcO4;snS+-pg?Z-1yx+iqmfn@m`%kXNC7yDc9xyR-DD=Fz?@hRGZt$ ze*E>D)fTeF;fm95j>EI7%=5c8^?tlK7fp=k>hU-~PX188!N0}k1TQI&qtV_Kata_( z8gKp;Q-5a9iI82LiICGW6Cv5{CqmxZB-T+~6LF^P zJrQzK!$iohHi`8cbk+PT=J}0HaCU8+h|`04BmauAdglwE1oHE`iI86@pakdeO?Y_h zCLB9#6aJKK!k=3(U*%shKR?-PB4oiPCB0x1jwLrK>06sX&e$Z+Pi~Uds!h_OnKA#0 zIozdtBIK1#IJRJuv`*Y4t#9Wi(m87r>AhrJtjXr%>v2njnQUIf_dR^SXZ^nuzvsPr zHBM?RTrygAEKX+Nn_j2iJNDP_-=^sIT+|lBYp>GptBdt}=_LJrgjpZMXN>6g*j@Ge z7wg{v<&*G}^n1%8`t3i{!Y|bCRTt>@h;Qll3rFbpElcN<>~cj=0_4f=???FAw=(@Qa{=HxEjnOyIrfV`UU9?82QJg^ zv)2DM_(lA`SbxK5>i>tOb1wMG@K@9Nt^AUH?-e?e%@I$q{wJFoCBMb|oPVw{2P59k zL6=|Vi(ei$=9l^5Hv#(m?s$oQ547Jizp4JaZ1_z`k9a4e-ueCJdHQ|sbp1YfhJI&3 z9vFTF>Yd+xZ2T7RgZ^Et{~$~M8(T2FiaPW?a0uwEydXY2KQ{JVsgnX#Y190)q5*KQ_$ znK=sba2CE-<4d`ygWQ}0|FJ(b=2Cnez&~DC3Y6nCl!M>7CpKW1-$>_Ymd?*mp55+eK9-Cg_1j|jT{fKG3(*eAXI@(r#Q%j2=Qn*DUi-$E;g8_E zAHI*_y8!W?!uMXJ`v>G}dRH0nrkmZt=d-|vJ1|#%3H5#rj+lXg7ad>L~5C(v7YxiO!B&I6!JI(g9j=OWlJpdLTR_e1-w zLVeOd0D1o$@g9a8NA{R(4yaVQir=8|uM&PN9?e}!|8(x6)6F#GvkLfyXBmI8 z+3)wzubqyOf2Z~Oi1Wc43{_=Hm@!0$}^?L@nwKW)F)q918N zIy*t*PzCz$p&nT-<->IIJmjGY`FRHAp9H+wf70+f6U3iv-obpe6W>RLUy!FqjL6~Z z_dp|ue4h`zZiH_Ixh35@A&>ly?|&wnf7y7aPExwpJZa1}h^KVQOyF1g=##e~9~X~) z2mB`AoKIofvB!a3K%tJYcY&}m*?^Lw=g-G}N_B)FH zfd02OYI{2WbN$jHU~j<3mt(rQYLxt{H3R2Rju(%E>KY5rUr7z_A&fD)*t#Iw1dwVm6^S6 zQh9Fqp@u(>ertcwCZSBIkfcInNu})ddtLW+9p3tUzK`GcJO5nsJlDNm_jNDlKKD6q z^3VU5bZH!>bg5iCE=OfQ{y1?|_89FqQQ70QzZmLvDd+nV{v(u^;$0A#rS+le9kly{ zXm{T)yP=*_QLb4c8;Tq+@-CE{(wQi7jmQ!$+o%^_V10sIuP(9-;#0ieVJDJFx*Sp2 z-JT_m%5Egm7P++#UtjeQ%L}@_qOt?p|D&=Esc$L92a5kK#t)Khux=pvfb^Hi67TMp z`1&W>K2h02CHy=IKShtDQQ2Qey3dK6Au?6cdsaAIMh!ip)T{94sb~-K>zZ2n<407sBjs5j{`0n$ZB(v=50&swh`pZ^ zc}?v2g4l71zRu(9aQJ8BTBY8EKhe7IU6eQLHl81NUFMH3!?UO8b`DiV&~HSzLzuUM z*B7}+fAhfD>@CQTB#r+hX@1y@^nbuM3XOyGgqvgu&OeeorDaq$)r0Io^&r_n%Kg(r z%(r1YqyA6*z0APj*%uIQG3LQcl#3*-7Z;;G4N#A*DBnZ4S*QMgscd!!61@&0=#du8DAHaA_@^UAZkD)&immS1%YZOaL|7-ZsxjAf? zBO<>LSviHTFOvSUPwe-m=+}u|>&o>cv=7-kTKZF8k^g%?#(a$U8&SU#A`c-Q;?+oh zBj%l#;pg}m`Sts|t3^0VhI;G{#n=hi_5|}?XIZ|vh2`@*SZ>@;GE{xC4qt^ISWSJ2 z`@0{&ksnjP2vz;GM8Co~eH88ZHpZu;xc+lR_9u=PsaUw@#chsN8 zkGmeh*N~9k_Hr0AVTV7FF3qFdU)w0|uTk0kb^nXXeo*ZGWER_hgS6Y-w=!>me^9$T zCG+)bqJKcb?-pJoJWJ9$DgFHar1$gj^YzQ&$BRM!XJL=+$e-kFCj zl#9ka-yUpt-`?%igStIJ)vGnBpN6Wwn<>0+_fWCBAAh*CTN`P&cG7M)(&6^{Z@kK? zvu@u|btHt^F)BMjk7Iti|EKHNTfc@UWoZ9TJlsnS`k(E1Mf%Yvdc2Ivep`=QZB(TA z(-obMq2Aife&dhRAH!eDz&~Q)Kja_&^^|<}LqAmr$F4Wq z1!rQ!k87cyQU92T^)t!-A~PYWT%2F1zHcovh-GEifyVQigQ_TA*Ww#D^QeB6)LuQF zR#KO?Q9Jtm>_+-@n(u$h=Sl1b^@E?Z6@6Ece*O`sv7dtc?Z1#NB)4OzT5%4i8&S@% zo7(rr^-Qz}jTbW-87ds{xvp6AfJsQn_+yT`ow8@ zV_kN61=;@wFTwhk)~RFG^8P@_m3UiokfAES$9{MM;~up`smLO%gNWCO%!6MOPZHTm z>eU_P=!5b^X=$h@ksi&juOa=RNPmk+&M#EGq3>_7ueAoh*Z@7RA7KYc_nhRvUGn98 z+NgZ2i|D@N6B*y0mGSM#`>6a_KR?3qE?GzYjroDb?GNCG6faz_t3uWNC}%XvTM1{l zQz4&R&vu!AfXA6~SQm`J^^o6`x^EEHqcZQgI^9Z&xsvkvXRW_+{fh8vEe&<)L%yGw zgLwzv_Pie7569_MQD5AYj-l@P9>2T}``jV+s`n$+hu15Q;JVsD<8Ea&s{%W!zR#>dlEYIvA8P+-qiW5-rikW7Z3lYIU`mgO<75DymF3w}lX10>y7 z@6oc7ng#g^{AW7Sqw-sGSXQ0H_Gt$Hx(vI;Yd>zIPN5vszjlF1zKZgbd>Q2@nE?MI zSr_9t$zvji!QRC0KgaT0k?mX_uYW?iv<~?c>5^Q4bV<%bx+Ei!F3DSv9?3%@2OwSI zH;^955|OWbg8gmO>mt&ndX*i;ay8N=UWRl@j?n!D_k&1}_>@T6cOouEdL)l(*+%{N z74|<-k26~0C?~|=SzodPyN>-@41^t)&tOEAJNz(pRKkVbRK)ccNgX$(r zy6+%fUzO!!@I&Ilt|UWMw=cQhq@iAG;n%nA#J(WpN-a4*TJO=x2(AUuhXDeifUIx2xetV3dm_ z_v_ef+BYL!h43Utp&yVO+lFQ5&MX(9esrDI@gy@)Pm=7%vDs%N{w0yE(0^#Zv%AP? zTDDWq!mmF@|Ga|xo{wSg)L*GSja0j4RR2b*4D5d%n?(twEFHa1AF3j-XF~S;@)f!s zsuo=!d1Jl*5!U}}2gPRpDl$RKP&EG=DCo#ei9jQC5caDg!G7nUMC?-%;}D52`oMch}Royosw{@ew>p!S}G z`xTmZZ{BCazM|H%Ka!sI<7i)gLlyR)U$tzf)}kLA9Mn#|4tWguHrUF3=hTu$BbwW&j~DYky8ry>R5`LoCH3g<_?qZotaIT%6z>D==TX@$ zW!!5Z3qB_gv`g(iyH2j(T zcs%@;_j9v&8=Oa^59QZFWEGKhMXtU^^Ah$8MfUlg?1KFljBj*( zhg@HY{!e^V_#))Le?QJd_&fEZD_F0RU$ji&a`neNR&!7_wHSVYFF>m% zk8rw=hjIBz9%g=EDa$8Lu{>MM@*R=cB6o>gjd7C7{So|wWIMctNHTgOb4B5=n)3Cm zOL*ITu%TAH#m|!pL~a+^0)9m0pZW&NxmvbS-{e#I4Rt`XrDlE3`j6kn8?A$HjK>X8 zzxIP;v-_YONUp_vLGtnESkk;nyaM-2Br_#^A^Hz-P4st?RWRR@{8#jK(7x?a?hCJT zzPC!b$|9dT(cZs7Qv3e_JCe*rdQ{$Lq@Chdb35JKJ{a$$p1-f;bTfrpqF!VN|2gP2 z*oU~ofAsHxX~BUyf~{j`lbiT+2|x!i43 zXNh-M*W-pCg=&8?)NfLbJz|eJSRYXNMu|+5@_vMR)AbpsAC2pMaGlomoiL7*f0l>6 zDc}2tk%YZ4{!{pGC7ouH&MjcN{~9O$ktedE=>L#-Th?;8E6A7fdkyxd=P9>f+^79e zUte8c$8%XN+o+1L1NGxNB3ENvC%!{?u$Gn7a~PLPu+ABHO{tz}_n8i6&injih=75={LmNGm~?!tUbMo~#2aBVQUv7l?d8uLs+x@n~;)K6V)G`^uo<+4->d`2oYTUlF-g&xgaa zzkP_WzoFx`Qx{PGG6UPGnV4@#_C)>ZzU0L)n)gHXeHxWxS}2vHy{e6T(!jT3e4=qW z{(w?hQchwDN6*n{zNPCIabKS`xSjENI=+qpnT~m2Jmkn*ShnhbvzXwGZIzk=xxEZN zVh@=*R;g)_zYWH_n~=lG@%5GM@hckOKOg1rEn2bMFoV-uQl4e^5qOS)a95@>PoK!? ztxw|X8~XC~o|q3Q-xWRaTm!OWKM8j~>+QzO1uowHh5o@t%u{Bv%(#>5b*2f2?=^w> z^*Fp;f$)=%AJw;AN6zOD)b|bWJ1va`wR zX*Ap8HiP3$NMwDR)*SyZ)&Z2?v98RI_vi3m)@J!mES;lhXC&Uk`U{o09QSr-{k^aQ z*}b;O>3jnFkR4|uK3%UC!QmUC{m5>as3+w&1MN%l8`Ov7lqwv4bPtZd=}9i{T9lXK zjc>|!8i)3zbpJ&;Dc%Tazupb_`dZkF{AM}QA$v5gz~Rn>vNT~gigydfIZ7w|Y24R9 z7NK3}deLys|Lw_~|7*>0e}LGqk^-tf< z<=YOsQhFPEbGVb;l-dveWB~Iz)Q{@a^?8p8gckDXg5l)`5@Nc zgZ8HKA4U1;dUe=`>~{j~LG4r??MD8-rWc1>(S&8?x-7@s!RZ?C14`#A{FKV`4fJHE zCa4Ep9}Rya|2Pf%k$%+_zJ473Px=0Zd5yv?f!~rWLOYP1mcxF;87Lq5Z#*{1@nR)7VaU(@y7mFYI#~*FWsX@j}opRPNDeH%jl#7>?gp+Vw8P zr}Dmm@>0IfB(pvKNaXO(!~SHq4!BOT*x>6)@IOkgD*Th|SKeX%OX^b;#=OgB`*aZh zZg)SYGgkb#;6V;oQj^1tLc3FX7y5EJyFAW%Bbw`R0_Fdm@-Uict*aGcL@td~c z>vd&b+kyT`{be1lQ#npx{HAah9%KHo0gq$LYH<4XQ6I8bV`&Eq<2&WsaVpD0@DD0a zwD|2r_yL7CCa^wY2J3r?pTB}~Q2&TPeiW{KTbAA6k5ry+@LwDCX&=Sq>R5$kd(@ls zWicO6yfHE!j?QGBn#%GPn1jl*4F8aS+&2a53Z&Pd8keW{-7H&)pWOEl^Sjg8E~W50 zO23=VbvZ(#hTabN=G6XKol zN16wUVISft@OPS*dtkhwe11balPre4NN#|g$lhyE4hr8M{fqJ$-j2B`{DXKwC2sfA zup9N8Y4AG=Ux0o`_GlZ)vU4BFSITz{eogU*IGoR~cd-5%>|OzOdp&~V4T9aNzL9m9 zPd&}?K0yDV^t<$Dd#{7vQF-rvfc0fEl&XSshQRMBoN*_oe|t}sf1zAd&)?y{G=A2c zgmpT?pKQ$6JI>_wSHE-)AB%oV^?C&LBzXb;MeV$Q4Ci|U{zduJyoc=&U6I4hg}ta; zw__Zmcz?BF-h=v3{qxcPNdG(9lj<3Q@)P%h9VxvZ(XJ#9o1E?;q)+Ak2YyH4{)GRK zyba?3#oq_J6R$)+rT*3u^`m@8VH}`(HV$R|iXoiNL#PL(=ibNVp`Y)n2RkfAeiUyS z{DsnKm&D=rjpp+F2LC4gvHUtV^T+@x*&XW z*o(&Hswf}nn@B%7igbz7EDnDR;|}?gjdrH^cfvnNzZ~Ny*`s@TgaEj&q>m6-$p;Aaus^!e52Aljx$mvce7DW|Qit;mNPRA~<#f*U;!>_O?Y zR~fMHz#%LnMaB%du}|~NF?{K2NNo0Tj1wf2Fz%4t4Syqf3GGbsh{$l*gLoLqOY$?h zeoqARD&cPzGw*we!X3_8~Y2`xWd3StxuJ;m4xB>uf`fAJSMIMEJ3g>rvma zNH^yfd?yj|zK?Le4)S1SoUfz&ZdEED@@x3tGO^dDA=T8N#&}N~a&l|zr$b)rgkKGS ze4>w1)rVG7r#y@+kYA%58?gU-WgAIH(Q~ZIs88}dmh_y8xa=sB9Db98-}L_*9?wJR zdrR0q@z0r$e~0YA?He)lhMno0bTvGmp>q=?>6|o4dfr2l&dHIa=QkwjoHR)~Crz@F zNIEB74f_otXfN77pywE!hT>cU_CJXGU%8Qg_n`c1qu#xT#%3==IY`oZEt2mnVA*^j z%LlZ)QSNEkN)14`UARv2R3Xb`w99~@I6t?V_m%Q=y$!X0CFO6Z?}e+sO?)Fgs{bQ+ zE=1)a`B4{=LHZ}KEJQxzMcyg$S&@B3P8AuWCC&@!dWWjvpJPAhf7pZ1%XaANKNq=? z-+b630r`<#NRnMh2GCDPl6^=%hyIf=)KRt2FH#}5f6eu@-efsl%g6=_e|g^CAC#(S z8Y*76FT8I7cHGmLYZP3>_bCI0nyk4*jmG~Ms+j6C;lL*PU1v*O6@KCi%r=Il#)c~V z<#~A_l)j}N5N@)O(zn#3%#yyP=4kfQchnEUoW857VD`eko#OOe^_1p39pAv$?+SuA zW2md%3gRh4%c!lI^J~0?`YaxLi`pNgUkW}J#KVjV>dzp)$GBB_80B$3Md!B?y|o6j zx90Iiel#~4)(4y}!EUTS^FPVf=% zWX-vrI)l5np>@+g(2f-8Zh0eypM_(g-Bh^y)Jb0pNq&jNO^``xePq#;g zsRY(bdxWV8LA-KknA)tlMBC?<$R^6eY=HLE_Nf*buELuU=c*bgU;W6YYL@Wb;M*f_ zR~v<&2Dgc9rjBZ6dv}a%uELsAe71L=$kr-dv)|qkYPRMa6%BtJ9vPwL3y;y7omH-8KfgQG zY}SW7h0_BWk$0+j!n47n!Ape6f9{Lyq7Dg@|2zmjE?oAUQjbPErd_EQ^$JGWylW%jIPNQPGb*q0~zVzZ|nA;(M*MexTYc zTtm2&S^b9DWPap83XH#E`%m=8WnjAN#+OyNzeWyGHQErDgggxW{K%mM_$#pkDF1sm zxcopo?cWj^#cJqR!M{HRx7P9VyxVrucsEQ%3eUvbF2oaLqHE=32MTOr%@#m_S zQQlLLBh)(K&3KylXJopH?!bBjr@Q`)%vAk5F^6j&t(IXGjrEe68G&!XMvhhGFuM}} ztmEIO>U3r9_X_DJsPJygf4xlnpi0Bt2!-$VJn_S7au4ES#qB>u6>9eDGgU3q%>I5Y z@(DGjCxy>Zw`XBB7Wt%#?8UqZv+K3UY}N5D<_OIG*CKP&px(?AP~K~iPpRBK#D0F$ z)H2PSe&>)pb%a^`Wrn&a%>FV%RqRXg{rPT&N*3n%Zl=l==J{@>qNf^uf5kaBRTRV( z!8?Q4ih4$U6U3d}XDKrNN^F{+%0|s*R3+tketGUX^ZWv%>c5imJb%o&&OCqQUuT}r zUbxOYpIv92U&qJ-U$6O=$QQ3O&5wN|u~gH4B{p%j$VJzg=Tj_c^dIZL8VV<1mh!_% zgt`1nt}~Z^>2>Dvzj~dy{Fv1AUrBi`|8bQRx2Zg#QR{Bv@Tm1S zahoVivih$?hwm8m{!N_S9*ejjePSdARc5Krhu4|wbA!1)STss_uFnnT`oKv=&-J;^ zQlBmAry&1c8Tk>808s>gKKfW;3L%#HXsg;K%;V=)gSl{-M^XK;OXsw&JOT%X;liRiifyH$iRmw&hF zE#Y~7-L2w8&-3eUmB}pY@7=0Db~9+bwE|7kGitXQ7sLaiO4S_AdFpMLqG!||RmAL7 z$J^xzQG3y@w7X3hS3?rW76N&5L-zYsiy zj`~_n)qLF8iSmpGFACyEqYkJ`n*H<+D=X?o`m>`BtI3*k^n6#f<#Dw}v+qwQRhMBD z-uI_ds>*O?w*M&=&aBw}r_>nDd1}`;_??KT-&BKWou9WI?RzZno9ZIGU#}m2Q}LQ} z)L*E7XB_c9qS>EcepgpD&sQ`az7lm_)rq0>=Bu7Xc@vD_c{1$ zaERtS?{&Ric8p4*e_yYc9ix`$Pb|UH$0*lmDEcelli+5e?{WgChAq!%C;Gd=Z-Tps z{_XO#z6&vWi+%&xRv`wKT=--A{2f)s$PHq1*e%A&Ag(m5vau_O>kq48bd1ySRU1rA zEr-=JCJ3+59hQ#=AkBSf-(Il*5PAUxc?ALc)xz z!iO-G5?4v!^!R>0%!n7}^~Y^Su`sVcZZpCYDg1nO)G<{1VYeA4gqLr`H;{)lHfki1 zK40y@)ZBkqxItu!edZf*Ld_*c^N;ENt;Kb20*)Eh@;cWAXAEm&BNPGgZ~zyEYMHfzpTC9hh9%9TD-iG$s9yQcBC;Z7v#F56J3=TiwPU0wIj^_EQ*BAH>+OT0pvG7os zdf~7*qufXeKVO|eQ@k-O!H5v{4x(LdOEeA%xBC{SpNAzIUM7bp-ZU)LXf6CV(swIm z7}>&f3aG0!(pVv!^|?}?4a?N+N8<~RzoT#BN2BgFPU!HyzfLgz2;z!rf^jW~JG&E& za#>U!f4qOt$kgn|f6y2=n)D^A#aVnmXxM|s#e0Zz)E79F^vkeEj3xIn&%j>RrD0DR z+2e@wyze&PRPgW|V}|gr;8r0yM!xVRt$)f`And(Q`lpOng-4-3xx=R!ZwrqHR|LN& zTn_&44$n0<30DPI1Q!dxhh5lO!=E;G2^WDIfcIzik^zE77|&qw%{j*+JMxIy)8 zGCa?is<}k-fnhU^iw{zG*0&u#+o&?>26r1i$B2J~IA6_JkNt_^bB$u*uhHId!{;04 zgl~ntCJiq%nos8N&7jX2zQA}wIO8LHwPpAsW3_Oi=2wjU!W}W+zcu_-qrw!5@3+_M z*ZqOY|LO3Xd78Q0sKMdY517Bc9KOO>qnYoY_k#DZ-n$?Bj~i;NHV$ge@uq;cN3Aw~ z7Co=0))=Qm&+Dl*#(B~6dTOn4RrI``T5H&k>hfy;_-^>SMtNcKj~~I+gvmd?8~&bA zPni7UM{pBnX|Hw0AkEw!Cx)*x#su;C;qMzskKf48jNW976sG(_z~h7|KQnr>F-e&6 z3jxzt8OWboY^D9yEymNrox%9lsPUZeke#&N_{f+qoCLPjN5(76Qr?e^V$EFMiqRh% zM}oLc^e0A@Cn&!hWutwYMVA=;pJe_V^X;9{JB_*7#QCZY{H0g)7e-MIb7&EE$)mqA zIzL6s{Vyf@TcejS)psO#pfJ@pC3?RxT$t)R5}Yht`F1?Di9TRt3O58#0N*D}^?fAz zpz)9})%P**6T&}#iT$wX?~FX*Kf!t6=Y`)yd1pr-GF}v34=w;N5zfZ`#KP$Bjpf46 zgO`BUF^fG98)4I^zHHAoqYoQBG?(c9`d;*pMzuWB`~Cfx5w1DUt8fJS$z%EWr< zMD%In+_R+5*I%vqJ^GCC63T`0N`B{z)tY^KoHI6S_Sf_0j6*^EXw-Ql`#DbU0KRW} zHTse<`T5}Vt{J(S3sl|n_+7i0YsMDMyuL4u{KqKOJWajvJx(jf{A-+_L-D7nA+Sev zaJ=5a$Wd=%zp5^Hk>+XY(JQoG4Fnp@`rfd-lj)B!vdYZhY%B3{(#c@2^Nv49sCBz*od<>v)5H5aI-us_*3#tRf`_U%B&lz(!_W zzQUNW!2Te9E2eQ^>QaiIqxB!gga?+t%Dl6zp?1dH9=QEA&Dvk~#54~K(wyg&hkqRl zv4#czy&~pydM9SYfkhbhbezs~I z$kkk+_U^*2r`0AvU!x*>fAc-|Q)Ai%dTY*Cn>F7NDE9{Gr+HVtrvBU^5GLFQ$S z1iEN0QM}&n5TLgPXg$O0@eYA?n*H*04A9#a)W4~ICt^AVHfYZAc7e}=KW5hU`75SV z;D~0f-@h?k0<+%M@l|8g*NN>K_=8#O*DY{abBG8_CDA`6&_#GR?EhKpeSvkFw;9Dd@O&cnfxr>XIjTSIM~=om6qtZ? zsQlHiemEQZNMQ1Q=84DP&#{jMHXk6)Re4D7@7N~;(Fcirdru2Y2x1kN7nr3v&nrZJ z(IL+Sma*RZ3G3@)foB4nnWcT634|eCYAzG%hyNS<1*79u2Zo)|dKq6=2U0b&zupghF0(fX zZ__*+wfA>+Yy+nxj=pNA;ur;%RrIl`D!@Q`!#NN;E;qT{ynZVung-Y%KtWu z4|jy@2}ELCA^z}Zd{riHZ(zCb6yz5Y|83yB@M^4&D#srPMEp(R3)CdcANAr71v*|} z{_`R9hxo&Rau=D`p?%uM9}PrbW?lyF7JnkJN4OaMzi<4nfuq8g!IAN&16{6g_=afD z)cA7&dK;SZyMXv(!gh8NwNR zaX%4noBK4+SDRW>_z*J}^8}@r2K&7jU&ic+GdL7~-ad@C@#W1r7VDF+-g_gyg4sm) zES|5gjIU_M3*V3a^-+9PbF%Oe*lT-ybu$d}7Ny@8iM@pa6KxX&m3 zMU4Mlt@>sc;YIM5xmE*niSRcFe>lFO*~8=TzkpB1-)1h?oUh{GuYbljF^hzAP@Xs9 z!_DRx7pOjYzvJ|Ed{c9ba9NBy7vpa?*9o77e_f1kVX875zBT@j6#hfAhBG^`4%zR;b z{!=xftGPh97+f2?OtU{8bTb!WUZnPU6Y>9y?`Ce%?ANcmxlOabzV2>*6T}S@x|^qi zxN|};(?UDnuuosJwq`$mU$f1BxIeSk9;w3^CUTPj8AZA0!MlBd`xZ?e+8f*#An1G$(8J+bhbXa}bnY5488O zK$ICG90j&jlzFT0!x+C?;8*Nw3FmqlHfukv`5GFMJVP zQN@{)g`dFsYgIzLnJxS*_1HIpLO|n5 z?^2w%OUN{52>*(8_nCxICjD*+>2tvs62_R#vF|`ULi0UlzGi>_W2`w>v){kQnv0pG z{l}WG3v>IAHCG99``>GB5a#y3*Zf%c;4Abzah&;?@F{TTxN&BwF#E@S=6+%JkNeCY zh1oyuH%|()f81~WARx*#$8#{{#iF#E>@lYU!?^z0uK%{s#D z9}~^ngvmc%vmP*82$O%j32rY;{&6hupxI5B{KHlcn*D_NdEF#)s4zdTn`Fi_i+?<1 zW@_gBqer72GA*pD$shRn#G_`I=6ux|>#Bbfo-jT16Kc;C^yga=pEe7H*JFKGBXPP} zzoD+5q(8$9XZEfjonwI+W^2tkURmAWW|*CPJ?4*NfthAc(O1EJkgaB#cZ>c*%#XM~ zF^7qM7uZ(Mm`S3qigneoz_aE^(Ki9x>REG~=r1F`V}V)bB+YHyfEqob8aK5-!%2bM%*7KzF>Z;+4tW9^IK+**5i#63(Oxh=Xm+x zHjxG93DMK~ym8`O^PK2oz-=PunwLaR>-)xu^GqX*^2_m(bo_Z{8O?d#zgj=vyjAoS zbo}{dZPCBHi0tvA*+}$nf^GGpNxvaa{?~dj=?l#W(RTvds?h8z`ra>-eu3FX^n<~+ zT3`+leUa8LG-E~oxz;Z<(=^Z5``^tIUow{janHmh=0*;$?R|IRQuE?%x_+8d65lX$ zG0xL^_12H^c0%Ht=044NYC7iq35jo+zha$7<*%&Ezry@ObB712)w+iI0bUn!yVpV&_IUv1td`Wawbtu|YVei`oD zjs@13?S8tx5MilpfzNtv3sWze4!h=6Z7@vnm2lNnCIKBs}~e?T2nK z75dqY`=1SFN6r3xxxwu5AKtH-_cxzN++Z$hM)3>O9_({WPuysR=|{-<>Z`-(#fh8D zj;%e8gIxxWjDUo;c5&wgg|}P26R6 z)12eY0e=GSCwlzms`@<4LLc0kdw8!-=Kld1m#iF3%n_x&xIzM-B6^|DL$V%offDAH(mt zHt5Lu8Sqo${=zxWQTyyQ<2$jQjtXjhXXZ}A&F>`6SF}(1TjE}Gs^%O;>0eCz#$4Wo z_1Dn;fusZGMa};D_B*qBH`3>MY@hGU`kHgZKHr()qNn}ua!H5G*1`eY_f-aWVwV2( zy*Zg#wMKnH6Azn(!V&0ap@~138-;0oRy*m4xnFoC{Hk`+k7jOnD$g|an~wjJ`I_cD z^&7%BO#0c}sM#<7F*CLYm;YUiSGCP!W~%TO@I-aY9L=oDcYD%tbE;vj-p>g`y}zC8PS{di!b$???Li>IL-o!i3W%KA#H4{U-L0x+a}5X9<6*^=Hk^!r7P~ z3KM=as|?`quWJ1{)4Q9~qvs91lYTeT2C<&Tx1^+t=0@Rz@b}S4m(3%CSziqM7A9OV zYYbtg`bep{(!J0O!k-EURK9^Kq<87A85?q$uVQu;yz?t~F^G zb2;SqUQ#)0&T!_&NbjSh^42=x{@=k$NfoT{7}oDY`<5nEwyMN3XJ9@(l2qF&7On;V z>uQBshkQo-Gf54tv^WmG4CDTb@!?jk@C^9prKDz7xp>yo^9w7vrIjW;81*Ti+{P*r z-h%wAB)7A|5;%N3`b$?U!s;Ewg$Z|9<229L=kIDIx3@Yb>hN;E+rjFsdA_3k+(yYA ztQD-+9Fg4Fx|+o44}ib)PVQo5Co_KndqyUAw^j&0i2Kdd0D(h>3?@#V;Eg!+0 zi1oqa$wRF1X~h2eAkvzw+4r|d>oDu}^Mx&uk=Aj|{CuGl{F~@I<9yT8$x+q?(f0x8 zgH`&C^j}UMX4TQm`@b*8MO*pIdcSQ|a-6kH_!0OQzKLjU6pjP0PfoP<3y+3>YyzJb z-i`5LD|m7S<;UsUD%mPz_GW&I_j!_2tapWJ|L@D>RO=&Vo&Ub%G;5#m3n#GumYiW# z9I4Y&U&23*BxhRDn%Q2BtSoCPv$r=uu|Ihwd7>4bMe%b~A=ax_ z$|S3B6xV0bQoK!>GQ~PQn)N?p{;iqvgth2i=C{`2{hgF2t*PUfQ!V_ONy;>9_5H-t z)Q`AdFG!eSeIWb{^o^{U)&b#Fn2)m(W?MfCkA*)^RL@ywgd5{IN=5a&bye8=ik`R5 zv7GUo{(HC|>X4FeRn+YJ;|taV%>~M9K>J-USj&auP`|lWfmJHp0^HS_XLXrC=@qCB zN3cJcGT)jyk=ReK&`N&bW}f;WhcCta+&iVvTKc4n9FJ-aS zKZr9@Ua=+!4+}HYy(vqr>?s`n!`rdno$`jY|54_BOO<*mls=to_1!FkXFl==X!a2JdIRo{u|+d|_ojP3cWjFJgc8P|9v=yYL+Bx8%lsWgQiM7XFtT zx7YIWIQ&!S-=T?LTVcX2za;*~iWKfqO#H1iOLzv_FE?(#wU61m1NXbf0tc(QW>USpPu(fL@ho}0TN%_HQ@C-AR_e{zWtH!g;Wl`SUDL-11gh~H5_^R;h z+I~M-GiFhEfBkXPnlhW%Z~vp#GR-CGyD&ptOF3#4%^`h`8j1O3O5!ip<`{ZsPJ*{M0M86 zXV(6OZ|hl$H0LWSZ}ZgOENhW2kNWvTJnu_AXJu>l?Qz~}|5|YV7pxwd{roRjT~?6Z zFaHHAS~Hjb(Wnbn#g(M@>vPq*x|;JF^$DH_re3q=tRc=(XOVyZ)PJqCcZvP_2JCw@ z`}qazY|Zn%VYq)B+dg2w_@D5v1~JaN*sFqgXsT%+(d^gHwsSXddG@1yVp2VO#{10F zUWEx|>?IqSpTzt#BDJi2QTPk^>!{T7cFrcPm-Wsq_8QH;J#MkLYxe7Zi#=`&r$_s< z_oh~`mkBq+dUaH4CA(P>>HYfOYDZ}H>wl}=|3CV1n*I9RYG3_?;^!!;&jYDd?JmWf z--x4BpK5maHfF9*b$gO9)#uUFn)Z>;Sl<->o0D404&Tl^XFtBukXqY*m09Xr&)%=u zuWvp3oMyki^=xYg#hMQC;(uD^^;_xv)#i2$&H3sJ%ulORo7ulm&3<`W*)#v6U!vJBPb+)>p5XGdwNGpI^J{Bc zdr9x-*Vdl1FF3z;_5#g*e(mfvny0Bom|q*!ZD$Ysn!@KO8c*L(jj+cE&jsTIh<(eC z!RfWPTWj|Hr@ejgC(`F@`+bz!$v*uvr}qZt(+5(!+R;au|J{lYHKum6H*3yUcVPX! zC$)!tTJ(Qoz4bt9PkY%hPLI~>2U2_4g~yrC*1&m-)IN6jFT{TP_Om-`_UqTro^X=% zzJ2=HGc^15>1T(W3Xb33uAp#Fgf0n}M=<)G%>L9!M zIp%9W;k-xc5WC0k%w8$%IU>qlBuxFw8!_CzsySbA|BA8u|3TsLJP_wbp1&o|E@c*f zi?_r6B)wn1c)N>czkbl4C%tc<1iQ6nzkUgJ^j|mh2~i1l=|y6{K8bdhOU!)!F~y#v znbS*%O0i2X2Zv9!&s_-)pKc>D{1uny`6=BFyGnY0zdGISt+_<+Uq2d^W%s^D`g}#_ zA1jO)Yj4*)SN*gUUoReUzkOAh$Aj^9@;^GikW;V^_SYppKCj<6^+9`r*5i32QXQ2# z$^J((zkh*m72EE=IzO@JLv{_#{_~fI>4Irddyy8pD2bFY`5*Avt2Z!8M$ zm-iX_2hD!_J!4_}3+(Nh{qb&reL{1-S_6L=F=COOQZYFH#r7o4zCSIt=LYekQA_PVZwmj0 z?Ny@q)AV|6%!oJaWtwwjynoBybt~!fRm>Oo%Ik;~cKOP|`K`2DYxd)>w0CLtjs>!H#T5;eCJo(H^52=Vy|s{eHA_ z8;R38x7^R@P9vNBnG07JgNDj&Qw-9Dlj+0O2Cdb5$ekkM2YKa!n||x%%ryg$c*) zFyXuE;+K|3{9=z2{<9A8Nqe2}`;EtY2}=YZJ1}HJ_FM#IOWtZA-Cn0J^Ko^jumkaYbs7FRI<2~6b<%pA)G@HXRm+*7xj;3*{m}Td zI*xTG>8E+?8qxEMx=uOGIo>DWiK?zsRrK%Ue(dqIdQM%@7lWsP8;kyo*4KAhivEh$ z*LOOIp4+Q|(_Qr3UJac7tk?E_CN0z%ry1|_>hgp+Gc^1D8s=2#Lgn@SBg~nqIbU_f z{?UtRw>e8h&;HWH*)RGy=&Rh;#Q9q@xBud_aHmdJuKziV2k)dcbHX&|c$dK&z%4}2 z&qJF#cZi;!hczDK%&a%Fw&rvl-|tQD=ZqOZ`f0jFvwRST-(3~^Y3W0pU7B+g^@k~mQO@2Wr1$5CVU8NA z!%P1d<~%h_r>FgGcKR@9iRN5&_Ir%l>BF6ktXCJ#Vmt#QG5nR-Q=xBR40lSke!kiZ z{SxS(iw;gN+F78vSlzV==fBcpoaMrIRHyy7IA_yM;p3g{H-%4dR1Bq8tT=pE){Oc)s^m`aMpB@MGA2{xJPsXSwEl^*GiepQhjM*h#_pPjGJ0 z?B_qhsiQep)kAxIm_AY3zu4ybPrA-r|A(FFH^qO%nXB0^|72&2X5T)OoozwkC#uQL zS3$fpeTs9MSq+E3?M;8ov6890(-gh;RNH*aslzPu(_>DA=(iuC`TsFzknldRtsZk? zg^y^S>WmR?isvJ>&BvWw;eT+yNW4V&R2Sw=!rrU2pYgb}O}Gu>6Ymzjfbhfzn05JH zs{goiTJ&_j=s^0Dj+Mgo8C`+Wf6{5B*|*P=PIK1l_}?S^pdkJ^J;xa*@ps^UqlJ;{ znsxf3(u#I1#+ErLGho7%XL&L=l>)8;aFh0Q$u(!*3ZPPg{i#6(Zbof zywjaYzFxRMvtRz{&LY-(f9Up@?kv-s;{|@C_L%OhWWBDRt!6kyH^ranjJuD@SD?;* zO6%j9&Y1DU`6?0q{A>C%&N<jhpB6&|IKdWxVLj5dFs2ao#^;p%eBXr+3c4>5%kA z&OYJxc>Y%@W04d75bH1Dc^vV$hnee$e$6Ay2jMSM5*Im>Co}H=SI=1NL_8|t;a^h{ zUv}0ASALcBuQt+7@)cGw) zUmE$TbCp@$gZ3VuQS1~=*Xc?4ZO#{(IlW48+nht1bJXXKp`OV2%(0%O@Of$k;^%<_ zvxDPrcUo)q+iSZsD2N9{eeQfE%=X#o?Bn?IzVS}y;Bz{C-9PZ#c+OePet+HNT+z(q ze`(|{r`+=t-haRM3um)tKl~TYvKL6t=g;P4eBp%6)#X(SFn+w8vD=9jo`dz^>lt4; zD}-w|!}}T;d!7Blb;}X&bF6tB|6c5GuFUw_Y3*};;%}T};iZk0dN1Q!Cv8555Bo@| z4>I;UKfb70?ERfnuaMYpzwexm%=&rj){O6*=pcS8=8!XH0fo;|bUtNA#$l)V!r=6N zcA^&(7c1Vc``LL&bBSVmA9H4C&QXtGJlU6V%sD6gBgW@Ob&ordFLU}2^0^sSik+1an@P1j5#X{=Ltss?d*S@dA^JDq9ZRmW8NV4*T?@j<=!Ip z>ub0*H2eNyxDi1-AS&SYe4E1i=d&%hw`TwSbjwYChxGh@dh3z4TcX)d-*XSLUhM6; zCp7!}X`bt?;PmNy@uN}Y+;XcpJvu*e=g3O#qSeeVG%?hGkyYJ-HN<}UHQYtaUYk#F zzc;dmdsMh5cm%l1S{>dizZ2`@ku}}P!ZpDYz{SGzw7!a`Wy??alQ8_J+AM=BkQ;q*AeHd1U#R9d}LjB_iWz3pY~u z95n>@&of6ha!+b5P}8d5Jl4o2uJr-wi;WhK;A`+Bo4WBIGSm5%cSbgIw{IfOS0{1) z<Z7Mt+++!ug8-(yb{v;_P*PF z{yz*Q{z}TT|K05h>+cIaJo0Y0P>1)&=Yj5up!gNlK=U5+=d1GQKiyK|-4$OlCty6tj!AS+Yo4#@Jk_YwB-h)`@ri#One0yeinu_P zV!!CZ$aFXR8;)NG{p+8RneI8^Q|PZNGsd_LzUAHPQV> z^qCmHLNXt8&x_u~_;pL>Bv&1v^tpdj%Y4XfpqbYz4Kg2dCuyFq9zy=jGpD(8g1B8~ zuDc?LyJqIOrJD0~_`aDl-P1w(sLWaJiG!41j;d{uzvR2Uzhkz93pMAdPP@q;^4*QX zuTJ zjWBEM-_8{8A;nV-OTx-xU4Tjc`t z16u!~+wmgv+yCM`MdoIAvTz?A{$n@n66>cU{KuJF-RR5A_hP)5YZbdQm}Pxd;$G40 z&o3ozjVlyBPp^k}XO_4fgLrGkXKwGSr04bU&Y11)cFo+L`!jdA(bqWsZKufpOWkq8 zO|U;ooGUzB&+nz~BH{j`Unl&i=ywT!i1~!#AJsfft;7BG(aci!s^1W!n_lG_17R_A$(#SpTA!dCZ{F&IjZVgL^R}(N_UCP|+ zjuBpl{QxKH8@E(5&eOr)DrFsTm)jIRN2S8wDrFsXdpOJ!(7)?sedn%lncw+~^oQIY zAkf zZFSZy)ts+VF<*AIesfiMou2B4@i{c{oV!H0751Y;6MuKR-@^K?nBO~x{NY9lzlQn0 zbI5u3yfA(L0VgQkaGGe~k1s(#BARe7n);q6xzN(G- zj?cQqORh%gGf&Q{;5Dzo`H?^Mjl0!L6DEIpIj)Mgomu-s=aA~&RpCbP*PN`H-h`T5 zf3kOJWG%0CEoN@t+FqvcBGj*uRojc8pIwE$=zGxbMb`IL3rB)yXN7wEgd5q^K8?KO zIvoDk$Mk%)k$0pnGrf0BoLi6iN#U^i#D4oV@{S5~`-ORt4Oq|Z7v@dYoTum0@Va4M zVGz&DYV57koTH}Tetuq7Q?GR>=f~~c+#4s%-)n5{%?RQ}Sj zKlmP(w_o^8;d2tdJ^VW~v6YwBi1W)p{f`A&d$X9m3R`LY+1gvC+4r~BUi~H%p8NOr z>8-s8&H1VW(qER<*2@gyx3eO=HJazESFqo^HmkjNLijPHzcH(WS1z2=o3CnN{rhoN zN3VGhud2|=o2xm`sc9r!Eoe$mtSDq0xbyd$Eg?^RS(-MrJHe{nsn&%1lo znreG`n_nY)cK7NDmx688-D@J8jr*TtfgWBf%{ks{VB9Zy9YtUDAJX^qdI&cJ9IgBFG}KX)Z=R}FH!U%I6wK}9d~&d!j-|_W!>f7%dGw7NLFueY7n2z>hCQK z;(xM+cx!^V{HWnxwcELV<#B&kZ&adJPjilZZ#>Zp7yaL_D%G?@l9wjzqW(=gBzuLz zbIy^yQoK^(m%$TNidUx@r@sgLA+^m^FIxB~@I;mBEfMDLO^opN3-k9TMtEV(Ies4Y z|LUfudC9^H!A(b{dCP^@Z=&?my&r{lgD0wV@1pQYtzRd7W4tlKJHegf#(0~Vb^GIe zCeLa^;c-4RgnqB*9xp<3iT>VLyHWRglY@B3s3*MbZFTw*|0(Y)W_kbYDer)0|NXP4 zyq`o*@1K1cHO>1~^z{DO*Wf={uhUB&mFtynN9mV@@cYwwURBNhd6+z}o@Snp@Vv)s zt$Dus0OQN(Q8T<;&G=p+(!YPyOmCLNr|;oU0T+s%=f`KfQepl+?K9p9VSeBGS+79^ z+mpX<`>fYdnEi8>H$j;FbCx$l_;bu(#{#pxBH?{tTg~?N3y;EnRc-S*@76mw{YhZF zf8{l07W+Q$br0f|kzlHad+!8_kUv*O>=dBH2!kvKD^S z@S-*Uf6RRke3nxi|8?K@^E`X*`+l~z+G^FRtyV3q|Lgy%XSGrZMO5@>DYez22t~4~ zmk>&mV%XH{U*nB86vaj;LI|Z{OHm9(2#eo!UFSM`wug!LeSg2tk5Bh^-*cUFopY}9 z|Id9t*k9v(^x)(I|FXU$*Zuoy{~G42{ZHV2*FR>g_HR@iMqvMO3v%>~|Gna+@6q*` zahLyHmcL>UKWoOL{&MDb!f3Sj9Wx&HFYizK^?k98{yUlL_%{02Gk-p=!S(Hi z8PEAg4OH^!n7++3%KX!V#MOAVea0*PQs%2+?;hN5n(>z3lR@$u;2-G!^BJG`x7Olc z&8YAP2a|j?yomn4pK-vSI7IR0FA@L3Kb-jzC_;N%Gr#qZ%_R8}cnFo5WUljL*j>-$^mG00Jkzkt6_@v~Ec>`{_5PJ*N1w(1{p$TI%kHW;sQ0fd zd%SS<{*}k}pUwU`zrAOA?SsN8{k>=U>^-BEoOp0%ggtSL;`Dx1yP1Cbu<$$a{hiZi zI(F4LB-iDr4F=k@ORnE`v(c}gF>Z#QLTl)Yda@qD27?dHsku@lED zPVd`YF|(l^JE69|SbG%ne3*IyFnw{h{{oiteu*)qvAv7=YDjnn_ZMcy+wm8Yd^OPT z11z1{)XuEMm(Ofr&lSFHFTF35WIw=MuUA{!n-u5u>YHQQ*j*>7^u6#swx5}8>@|}W zzXjJ%>t?3f(OD`!FYX6CHnW>OzZQRbW_SBd=6Zjomt9qhzc{nEJ!&e2zd_>bZx>Ei z`a9$P!>*bA?c|FU{}t`?{>(x4_!)|i#P)M!<`8=?^Hp&FKk@v1=IQov;d#hU%p74y z&m{l4zZqpGFn@*DC%?@cWglg}64v7TImc$6Y0u9l|H>W)oNebZ*Z$A8m*tRrC3vxY z&6qseev`TOKgQl$i~F<3*q&J-ea*7R+X=Io`xjz+?~|QvrwPAT_$c8$KBD<$wmn_= zZd?zO|3$)|6aNLmA25}?MEH9m-!A-9oKKOya^VrLD1KacADmB;{y?ru-;WYLS$KA- z@}DleJMNE>zOlmdaXm)ibA?}o>syj96~6h9k{2@1hXr_EOY-bF6rZ+lwmtq5;wzz& z*8kZ#_72T4{_8!t_D{^Uy)Usnm(~t{iM@=umS1WY)Z#<4FSV2Bsr)^N?Y)z+&`uYA zHJ-;w(sJaBv#+!BMBantdG<1qr?WiIUMcd|Fuk3Oe0#0P-$xz|`St@M{{;6_IvLm7 zkBa;-@@Tl;-X!wx@w}juvBZ9zx#~}%VTpaP7GIjZ)LwK2O)5FmwGq>LPp7HOjxbKU-w)VSa;uUNYII*sc;j<4UqevF%yJ z>GS6lE1n>HF7B6-JWcq1tUts@312IGy6`!|7YW}Yyg+y(yq`zmON9Rm_n(Mw7v2i@ zhl!U9ABp1+@#Dfza(gef1J|nbzQE;OY$ppp59`Zw*~NA`^H=;c#Q#|4+TO)>u98dt zU2KodSN8fE=ld^bKVVl2-?D@Fdi(0@IX)@>2koWIRsDHA`$4->$^EMRJ!&6ep6?%t z?eChgkJ{ggT(!py_Rk`3%kmAjwM6A7i`#37?K02z&tZ9q9V_xTxxabLP7wKCCCVL$7SM0f1f8NdBWKUs^zbArxAM$LGtMY%!&SS2|?|s=%*#$~2 z=TT4FCBoHx@2745O)7tC|Lqw&o%w1wfa~pw>}Tu+wfN!eE%v{d>-;@uKUa$f{9Emh znB(`oxV=4ZA7Y;GpN~8mp0~di`SmP+!Tv$yceDHj8$T&m%ig8-qs;aAREDc;`tKDl z?U(*Gv&`Pa^3|{u-zPhk{i5x^g~H?eg`EDE?6g|^aQ4ggeBlo6pZ}cws=Y?Ih3A1Y zChxFEEmz@x#{B}w*=g@(z6xgJewH`qH9PuNlCOeA$laV>_C(P^=Br>V%Dd<6wRbQtfVEpGJ>_=v zO65NZ%e!CBNA`H;dVcn?JzdFVy!zN4e+T*3_32}K(<&AIs{3(1ob!p@v4FU?=K(vd z79W#yz#duJiwm z{gd)9{n=65b60Kq9JO~c*Y-GO@2SP7y1vvFLrN{XCjY=U+kdBZ{qY;+rve^lG9slj}f^_?@4=t z$W?kz+82qu5B87EtzYd~A|Hc%9{g(0S8`5&!2g?F&U__2hWckrHk^dJDgF5SPB`9r zb4+JEbDe*Wvzz%Un1%X!+Fr+h5BXmOYcYIJ+vi-%T$fjbvy8d!e!B z%xUPPF<%LvV0$mfY3xiCeh==h+?UhDIU)QTZ14Bw#5?g1Dt(i%|LSQsb%MfIqWtlk zX3qGBlzbPi=eFiFch)l3`EBW}S8{3ZEuFCslYgC`mQL!UDmW0JRb#)-TM%iB9yBEJgvk2@JDPPWKzL>>((&ODLN z!1Y%rql2?hr5wx^v`7;=23> zINvhY?O}iu`|pr^TFw9`xfXvnC+K9>;`?(lo#ajI-+#w?vhOG-m3hAZ9^}z5%IPWc zhyx@)(-|Q07RaOFOlO$LJv^U1%Q;KrG03CgEN7g^ze0O7x6XE^i2MZdd2qIqE%JBq zJf@Q|+LEIl*~Neu1-J5|bbXlY#533TfhRkCYVoVbT;!~0egp59eVsGYnZJd@GdE}DI@^WQ z_Z%9{y4>0DEXj5Lu5>mj&c6@#*4QhZYT<1v=>G1N&gkdZzn{|o*4V3@HNq+VdyyX% zuFj_xI4N6|e|0{!z`0a$>CYEB3q-EI|Gv=4W3KJF(78$EDQwTHos}Z*%l5q5xm)Dx z*q+xo4~Tpt+w&S{gOYQ6EoUuq_9)K#m8rAxodw${eXHRnoUiqqb-lBK`AT@X5H`X5&jF>^MzRtI7RO(`BgvSeeqcjI_p1Byb{OHeX|~RviA~S2~jWM zcrdHPDcC3eQU9=U|8jQM;_WVe!ts2l{L_B$x3ivf(rWR6=WKGOGtY-;+`l?xKJDyK za^sM=dkdJ$mhY+&N1QY`)bcPKM5cB8jVlSIOcwe{|0U!hs@26 zBV4ub%}yiX-S9r_A#;nS>`$DDUny=Ozi0LVr&{=EoR5^u{>(}F zCKO-wtk0bx%(Z>La3%^@_g$)-&9(eLKfB7QP@I1cm(lI@bDq#@BP`wouk6P!24qF&;H)Y z{8q{D!TRvg>>r$6!Y{}DsDrbAbf$kta$P@8IP00O1p3Z;)$9|_w~9-7{N(tKlYg~- z{ciS8PCRq`9zVWcvt#zpPFKbGdsROpA0>Q0rswC`)eZ*6|6cK``uVGK9n1Cj2JUTP z{B9Lq>N~jWm@k2$Hh%9p7u*eX{2T5wb^IG{srcWIC$}$+HryS;BO2oQW3K7$sT1Dk zR@4dabB~CB3*)%ya|RU{-f~wTPpsm@acFzmgL^=$zDrfMOVcG!sGfW-bncB zp^7&X9yLnwB;nh~D4rs`>U_n!2)`U-q4;_U?~IlvK0x@EIK?xC|07ZHGqnE{#m`}` z+E+i@=T29ge=jgD*YB=juJ?Oww?eque{x*^54G!)<8EZW+CLNLdkMLYyG!`x%mZ$f z@F^8|{+Ju(CjLm_SNp%j@u*#Hv^$ph4UmoJU)^&Xx_QiXeQD&LP;#yxeRCVR_6Z8F z(%;4t=O!!8=^v8Y)Sb>;r@xt7B3z}vxqDQ&YR}Exxj(7&Q2IyaHg}f`r}U4^ZQ+(M zzX2XuhwoG6wsPN6TM?t{(lx;j`e3&Zlc@dXNphfFUf7gT;&IE zthuSom%w>gzZT~vxjlvFWBs~6w~c$5a39vMO}WYLBH_oe{=c5v)_q&}jac9I<+gLH zm@EBWXz!-~Qak<>cRX_~PjMfv#Si3maCg-4-^s03a(@JtS0|&Bn@~;q@b?CgM?)uf zlyG(bq_aC#xVnGR*_|X@-9PE#UMyVQKk4FLqPW<%tGlEY?`L;)AFjotp}SkkT=#E1 z+>e+qftFQtf1-!m=p?0Y2^_-nF5)S|58(aKFLHahJ$_a4k$4_)BDb$QR`^YL{?Nvg z?yhIP3i{!E@weQdyIXicDS&TIhMW2ugGS-h_>ZlFobRp? zUXAy!i0=`;8^?d*#}()M=8fl^?*ISt6NOu+84xfpbr&ga561gl&-v!Mg(6RS4S&zUoa=5Eei5es*T6jYp!n~P+Rq<$ zx$E&#e4p8LKl^>-a<{c`x}V+9obUEioZ}xc=Sp{s@Qz0)eOI~J!Uy2{7U$2o%DqAO z6FA?RHfMpmMsZu&=W2Je@Ut-e&8@55z2cwJd;XlOUGQ;wjB`)m_crHT<0dk%G}4ei z3D>v-n5+KbdX%51xW82))t_tKNzC*8ZIOH7T6c!X%kL%mV)qh}A3*Mf#qI(nhikBZ zZg;_T?!C-)`@GKG%v|@M`7Y)9gHO<8V8Y0k3Gti-(@uCZ_EF^i7WSRB-9P(Ex!cbY zT6~v{i?MH^^gfJxiue^upt}!$MLvb|W#YK2{D*U$KM$_eN#9HD z6>9fzTy_+_p+D_krOT9b;eG(_S^Pe|_`5T>mq+fUct?}MzmIc&;&TrpV7`gT5ytNeuf`~Tg&K70SU zJ+vKukAGEP3%o;1^`Q%nZG?|j*5+mn|GVw-RP9E$yT9sB$FDKGUDU__s{X&~Pq({M zwNvd+qxOF)USB?RxK`4?|F`WbJbZY(r)sAMaPNugi$W99r2o?HTA$`B{igJrzwdAU zT<)#WKc|S|HDMIqEuenu-}nw9^~Wl`Ug^(#(w{|0f98iN-2dV41=Z89h1=s)`44ZG z^|d!W{%AXd^V@OHmh#g|#+z`i!zm2e`Bd#y+yC$4UAU&A^dw^0l6?X9kZO;2;qn)8 z&yeKGpSNaQ4EI-8j~B*EzaH-IkM;R#{2RFDp!Df{4Jam#zpKRQ#QP&M{;BfB_idzq zv+*tk`MazU`8VOVR)qNb#gi2G%^s>+C}CU^VvQorqk-kCIgt$-7Xu_-I#4XtIo^s!hXR_pPEU$kpNM$*$i!ltj*Y)qInTIL= zrmUAO{`NV=^Y`36@a=Mn-wRb7zpqBWE}uWv=YdCL9Qj?1$@Qd!?O-szi}h#m zsB#GTzn9yY0ZnAy)9XtW{}#MMK;`?njHkMsb-5~k_}xFLFDD9Bxcj)BTCh>ZkzW{1 zQ1#3LRnH9JI4_cV_m%k9{X+-b!=m`Nus)B>!@V+Y`9SH7fcrT-?pGwLe5-LzbNtQ= z-c=-fyv1liERTmC7$)^rhYL@iZm+sL)wqi5TG{W&+hfY!}`MUm~i+Y>BZkc6}t}UAogC1dy=HT zzHU!~s_*dcnYQ4dJXsfcD zPH%X<3UA+Ub34QDxfWA66V9$s;p@&9e!m{6yFS77m9(F~>#oD8@z9X*+pOu=_54t^ zf2*c{Q{04x+bF#j{37eOPSPJJcT?OgQ0^WX2k?7AVkf0P6z^HPRQ|QQ?q_xUs{iuT z%=CwFO=XJ7@p$6-Hf`QHYJ=T z`aBX2&&Nc6src9VSLrw4dc3nn@#}OcxktviQ2w<&RX7jSwMQuZx?HsWy4)G`wg)?OxZOOiIXnxmO`d{r|)el{c zme|PyN{_duyp{dT8m{Z1@)w%#hx^m|!~LBrBxUDM@h%eCdmh&({9F35 z{}t+ST#v_kJo$5XJ&&_sN+~7}(|4=P!yb`&SU6uQ`%oJHSLqMe^XKb?(0;<7`!hhD z|Cn_n|J={S;@uZ-|H6;jeOC?rPo@ny;z(n-{wBJPywzd0#0s|2UQZDp^OJU^D?F{G0f#KI-@4 z8F78Y^TWTM4>j*K;dGwIS+EGdJw@fB^BakGTgWbIJ*NB15Ra4ntk%VK{b_f7F4?|_ zocSdGTu)6wUzc zU+Yojr`=6Z+>&z8=?JyQ5u6_jrg6Q{axaWy?vrp4Vi$i+x^+JPT6hDt$h_oK;nM2F zYrr&FM=85mHSz0upy#h$c%B$)uZml6=x3_WA$QGnz0;`ck1hwDPBpHD#w#^$VLOoW zQu70x-$;8=cGKq#xIX6cwcsl$FYRC5QwW{2sqi7YtMzDTUN?vBg7azFPuJs#^5=tv zJP*e2RmprqncltHTx1O9ie@#D`elMzV%Lz7s#F_^kc-|r{MlgucI_#za6%2 z+AsSF3Uz!2WQd+mOw|s)W3=EE?&m%5B_saIsif-#UiX`j#rr;%>`UXi^AFuUp!Tan z>-)((?ppAK^dI|wQTb8((w6wwnA+FMA;aAitA8H**`%60#iQ{c!SqJKLWUQxh zFr^>D{e0}FaCQh8GEX1P`8PrBOIk4TPV$fK{zrvZ^L`Po%a~hm2k%2-Tw(M1Pk9{2 z`$Dq6bQ{~tgcsz#RNZ)fzaOgP+C3a~`tbMkq+V~6`&cTTkbixi8;)(hQ27Z@mzsC! zdrzT#5OuzWzn{we9lkdw`}umE+(6coEi08?H7^g@MTb*pO224<7sq|FzuqUQFaAHD z=ZCKcbi8=}P-kAIxdr>5Rq1?yzOjJitI&jDQt#_aN8R-6{$2HFCgw!-TLygnKwUfN z@}4N?tlB<*9?z-u>v^t16ACIQUOaD+a?%cb$miGwD8%{g)8t;if1PffzTVF%|KG4a6CUJtiuV+F9q{}5sLNp~ zm#+mM%DK5tM|gcZUF=@hJ(Lfshh#TBPSdze<++c?nNU7-eK}RS^!TsSsr74jJufJb z@j9GSI%?OaCbAyV_R{P7`qFVKxh_|AZW)^QsQHJ^Z|FQ;%`5bM$54Ay?N-kpLiasC z;c;E-!Qa_FMg7zH(x~Qpp?R^+Pu+Q7sQgqrw`%5H+U|ATJ>Zpj*&oYwd&B)lt}nP> zuvyj1`s}RcIrZ1m1>D|3b_myV4cGV3Ibpc`RQV2Xe|6hcedVXqQ=dFkzTxR9;q->= z9v**@tT+E|xDj~wo%##vH>ln}DgCn6r!icwYF9cv^_N3iP4_={`Y8U;Ig1+K@jD{2PrlDpTd@^8ub z?U8#uUKtOtKaqKOec@GnI4&Gi@rIYbZdV@8j|r1y9PGqsLa%zbw(rwC9$J!~Q2W(# z-G5BRcPyx0Yxh?rJ({a@S)lZJK;_#26%O|gPpa_O@;-wJqj|ir;5ixJ)jGkfSyx>m z<@3jO36;;=oGu)vc^(+DleX*4vJd>A>;r3erQei%Tkv3=bA^!pc9ISqu0H$Mb;s{v zZddtrWPkBu$*0bj@{iwzmU4@ce&dgM$nGi94{N)3vhMd zVij-0N&VZ92DgQnxrwQEeS-*2X zJvfEhTO!xm;ht|#rRTwFKgk2<^S+W-?lt`0ey_@Up3ubfE`CPYYcku-f=b?3@xWJ% zUg*K~)(7{$Nd9pAVt=82vjg|z7R+VDbtfb4AMtsj4~FpkDniD4KU^y3jJkh4F7>XA z(E|@iebI8AKNZdczsY`6-SMT?eg^Ny{662he8cZAmP-HhzgjmP;e8-H58(T7zh8gp zed!-K9~M;0`JL{E>caw=e}5t4_YX3DYj?H(X2OyRRZiMnA-3Ao@ z$M4W{JlcQgKJrCU?iz2Eb0>X1&;Z{tCH+w{ZZG(N;?e7S1L|^1+D*87s9q`mcu$?{ zpQpyZt`~LX_4j|e-~3~H)So}?U+q`o_m8Chx0U|=F|nUMA5?ZQYR=j8{;Y1t;pM9B zrs_%P+@yi*6YFx+@#}q4l@1G3Iy|7#f&1bzZfSpdzxG<$_qtj3Ef>i-q~}8_AKX{v zax-f1ukPd4=dW)3+P-*SQsyUC=y#MMUIrcYy%YOvC zc|Ym%L!r#`RljI}-f!3CsQH - Debug - AnyCPU - 2.0 - {8faf2142-c26e-4d13-9701-f86f6e6d0443} - 1.9.3.0 - - zxing.doc - zxing.doc - zxing.doc - - ..\..\..\Build\Release\Documentation\net4.0\ - zxing.net - en-US - - - - - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - AllMessages - HtmlHelp1 - False - .NET 4.0.30319 - False - False - False - True - - - - - - - - - - - - - - - - - - - - ..\..\..\Build\Release\Documentation\net4.0\ - - - - zxing - {6431cf13-7a7b-4602-b96a-47cda6f0b008} - True - - - zxing.presentation - {ea513204-63f3-4c50-992d-08ff430b6f70} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.net2.0.doc.shfbproj b/zxing.core/xx/documentation/zxing.net2.0.doc.shfbproj deleted file mode 100644 index c988b0f..0000000 --- a/zxing.core/xx/documentation/zxing.net2.0.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {12441bd6-6380-40f8-b6f6-c42a98443bba} - 1.9.3.0 - - zxing.net2.0.doc - zxing.net2.0.doc - zxing.net2.0.doc - - ..\..\..\Build\Release\Documentation\net2.0\ - zxing.net2.0 - en-US - - - - AllMessages - HtmlHelp1 - False - .NET 2.0.50727 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.net2.0 - {41b69545-aab6-42a6-96a0-6f6817e654a3} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.net3.5.doc.shfbproj b/zxing.core/xx/documentation/zxing.net3.5.doc.shfbproj deleted file mode 100644 index f4ee722..0000000 --- a/zxing.core/xx/documentation/zxing.net3.5.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {0ddd7a5d-c54a-4841-8555-7940db210df7} - 1.9.3.0 - - zxing.net3.5.doc - zxing.net3.5.doc - zxing.net3.5.doc - - ..\..\..\Build\Release\Documentation\net3.5\ - zxing.net3.5 - en-US - - - - AllMessages - HtmlHelp1 - False - .NET 3.5 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.net3.5 - {41b69545-aab6-42a6-96a0-6f6817e654a3} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.portable.doc.shfbproj b/zxing.core/xx/documentation/zxing.portable.doc.shfbproj deleted file mode 100644 index 36eed4e..0000000 --- a/zxing.core/xx/documentation/zxing.portable.doc.shfbproj +++ /dev/null @@ -1,80 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {B95B1194-0D6A-4121-A629-695B1F8EF0A7} - 1.9.3.0 - - zxing.portable.doc - zxing.portable.doc - zxing.portable.doc - - ..\..\..\Build\Release\Documentation\portable\ - zxing.net.portable - en-US - - - - Standard - Blank - False - vs2010 - False - Portable 4.0 - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - AllMessages - HtmlHelp1 - False - Portable 4.0 - False - False - False - True - - - - - - - - - - - - - - - - - - - - ..\..\..\Build\Release\Documentation\portable\ - - - - zxing.portable - {24b441f2-cbe9-4405-9fd0-72ebcbea0ec3} - True - - - - - System.Core - System.Core.dll - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.sl4.doc.shfbproj b/zxing.core/xx/documentation/zxing.sl4.doc.shfbproj deleted file mode 100644 index 85a5eb2..0000000 --- a/zxing.core/xx/documentation/zxing.sl4.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {f983b572-dcd7-4ab4-b9d5-d218a22ba5fe} - 1.9.3.0 - - zxing.sl4.doc - zxing.sl4.doc - zxing.sl4.doc - - ..\..\..\Build\Release\Documentation\sl4\ - zxing.sl4 - en-US - - - - AllMessages - HtmlHelp1 - False - Silverlight 4.0 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.sl4 - {03b962bb-7a24-4589-89e5-c42a17ddc376} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.sl5.doc.shfbproj b/zxing.core/xx/documentation/zxing.sl5.doc.shfbproj deleted file mode 100644 index deeaa6c..0000000 --- a/zxing.core/xx/documentation/zxing.sl5.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {cd937642-91a0-4371-9452-336f8cc63121} - 1.9.3.0 - - zxing.sl5.doc - zxing.sl5.doc - zxing.sl5.doc - - ..\..\..\Build\Release\Documentation\sl5\ - zxing.sl5 - en-US - - - - AllMessages - HtmlHelp1 - False - Silverlight 5.0 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.sl5 - {a3d48b9c-42a0-4fc8-bb58-d368f239debf} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.unity.doc.shfbproj b/zxing.core/xx/documentation/zxing.unity.doc.shfbproj deleted file mode 100644 index ce966be..0000000 --- a/zxing.core/xx/documentation/zxing.unity.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {9ab81466-791f-46b2-ae88-55d4759de821} - 1.9.3.0 - - zxing.unity.doc - zxing.unity.doc - zxing.unity.doc - - ..\..\..\Build\Release\Documentation\unity\ - zxing.unity - en-US - - - - AllMessages - HtmlHelp1 - False - .NET 3.5 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.unity - {fd386cf5-e9cd-442c-a44c-b7d996e68ccc} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.wp7.0.doc.shfbproj b/zxing.core/xx/documentation/zxing.wp7.0.doc.shfbproj deleted file mode 100644 index 782e4e7..0000000 --- a/zxing.core/xx/documentation/zxing.wp7.0.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {5fbc3f17-7792-46ce-b974-14753d605a18} - 1.9.3.0 - - zxing.wp7.0.doc - zxing.wp7.0.doc - zxing.wp7.0.doc - - ..\..\..\Build\Release\Documentation\wp7.0\ - zxing.wp7.0 - en-US - - - - AllMessages - HtmlHelp1 - False - Silverlight 4.0 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.wp7.0 - {7144c757-8ca7-4433-8c6f-072c24c43c62} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/documentation/zxing.wp7.1.doc.shfbproj b/zxing.core/xx/documentation/zxing.wp7.1.doc.shfbproj deleted file mode 100644 index 3d5a4a9..0000000 --- a/zxing.core/xx/documentation/zxing.wp7.1.doc.shfbproj +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {13addaba-9d04-4503-a9ff-c39e96b6e6b4} - 1.9.3.0 - - zxing.wp7.1.doc - zxing.wp7.1.doc - zxing.wp7.1.doc - - ..\..\..\Build\Release\Documentation\wp7.1\ - zxing.wp7.1 - en-US - - - - AllMessages - HtmlHelp1 - False - Silverlight 4.0 - False - False - False - True - Standard - Blank - False - vs2010 - False - Guid - ZXing.Net - AboveNamespaces - Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - - - - - - - - - - - - - - - zxing.wp7.1 - {ec6f52b8-af75-4fa2-85c1-82bf77861fff} - True - - - - - \ No newline at end of file diff --git a/zxing.core/xx/imb/IMBReader.cs b/zxing.core/xx/imb/IMBReader.cs deleted file mode 100644 index 07cf0a4..0000000 --- a/zxing.core/xx/imb/IMBReader.cs +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright 2014 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; -using System.Numerics; -using System.Text; - -using ZXing.Common; -using ZXing.OneD; - -namespace ZXing.IMB -{ - /// - /// implements an Intelligent Mail barcode - /// Rishabh Hatgadkar - /// - public sealed class IMBReader : OneDReader - { - private const int NUM_BARS_IMB = 65; - - private static readonly int[] barPosA = new[] {2, 6, 13, 16, 21, 30, 34, 40, 45, 48, 52, 56, 62}; - private static readonly int[] barPosB = new[] {22, 18, 39, 41, 11, 57, 54, 50, 7, 32, 2, 62, 26}; - private static readonly int[] barPosC = new[] {40, 35, 57, 52, 49, 7, 24, 17, 3, 63, 29, 44, 12}; - private static readonly int[] barPosD = new[] {47, 5, 35, 39, 30, 42, 15, 60, 20, 10, 65, 54, 23}; - private static readonly int[] barPosE = new[] {20, 41, 46, 1, 8, 51, 29, 61, 34, 15, 25, 37, 58}; - private static readonly int[] barPosF = new[] {51, 25, 19, 64, 56, 4, 44, 31, 28, 36, 47, 11, 6}; - private static readonly int[] barPosG = new[] {33, 37, 21, 9, 17, 49, 59, 14, 64, 26, 42, 4, 53}; - private static readonly int[] barPosH = new[] {60, 14, 1, 27, 38, 61, 10, 24, 50, 55, 19, 32, 45}; - private static readonly int[] barPosI = new[] {27, 46, 65, 59, 31, 12, 16, 43, 55, 5, 9, 22, 36}; - private static readonly int[] barPosJ = new[] {63, 58, 53, 48, 43, 38, 33, 28, 23, 18, 13, 8, 3}; - private static readonly int[][] barPos = new[] {barPosA, barPosB, barPosC, barPosD, barPosE, barPosF, barPosG, barPosH, barPosI, barPosJ}; - - private static readonly char[] barTypeA = new[] {'A', 'D', 'A', 'D', 'A', 'A', 'D', 'D', 'D', 'A', 'A', 'A', 'D'}; - private static readonly char[] barTypeB = new[] {'A', 'D', 'A', 'D', 'A', 'D', 'A', 'A', 'A', 'A', 'D', 'A', 'D'}; - private static readonly char[] barTypeC = new[] {'A', 'D', 'A', 'D', 'A', 'D', 'D', 'A', 'A', 'D', 'A', 'D', 'A'}; - private static readonly char[] barTypeD = new[] {'A', 'A', 'A', 'D', 'D', 'A', 'D', 'A', 'A', 'D', 'D', 'D', 'A'}; - private static readonly char[] barTypeE = new[] {'D', 'A', 'D', 'A', 'D', 'A', 'D', 'D', 'A', 'A', 'A', 'D', 'A'}; - private static readonly char[] barTypeF = new[] {'D', 'D', 'A', 'A', 'D', 'D', 'A', 'A', 'D', 'D', 'D', 'D', 'A'}; - private static readonly char[] barTypeG = new[] {'D', 'A', 'D', 'D', 'D', 'D', 'A', 'A', 'D', 'A', 'D', 'A', 'D'}; - private static readonly char[] barTypeH = new[] {'D', 'D', 'D', 'D', 'A', 'A', 'A', 'A', 'D', 'A', 'D', 'D', 'A'}; - private static readonly char[] barTypeI = new[] {'A', 'A', 'A', 'D', 'D', 'D', 'A', 'D', 'D', 'D', 'A', 'D', 'A'}; - private static readonly char[] barTypeJ = new[] {'A', 'D', 'A', 'D', 'A', 'D', 'A', 'A', 'D', 'A', 'D', 'A', 'D'}; - private static readonly char[][] barType = new[] {barTypeA, barTypeB, barTypeC, barTypeD, barTypeE, barTypeF, barTypeG, barTypeH, barTypeI, barTypeJ}; - - private const int A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9; - - private static readonly IDictionary table1Check; - private static readonly IDictionary table2Check; - - private BinaryBitmap currentBitmap; - - static IMBReader() - { - ushort[] table1 = {31, 7936, 47, 7808, 55, 7552, 59, 7040, 61, 6016, 62, 3968, 79, 7744, 87, 7488, 91, 6976, 93, 5952, 94, 3904, 103, 7360, 107, 6848, 109, 5824, 110, 3776, 115, 6592, 117, 5568, 118, 3520, 121, 5056, 122, 3008, 124, 1984, 143, 7712, 151, 7456, 155, 6944, 157, 5920, 158, 3872, 167, 7328, 171, 6816, 173, 5792, 174, 3744, 179, 6560, 181, 5536, 182, 3488, 185, 5024, 186, 2976, 188, 1952, 199, 7264, 203, 6752, 205, 5728, 206, 3680, 211, 6496, 213, 5472, 214, 3424, 217, 4960, 218, 2912, 220, 1888, 227, 6368, 229, 5344, 230, 3296, 233, 4832, 234, 2784, 236, 1760, 241, 4576, 242, 2528, 244, 1504, 248, 992, 271, 7696, 279, 7440, 283, 6928, 285, 5904, 286, 3856, 295, 7312, 299, 6800, 301, 5776, 302, 3728, 307, 6544, 309, 5520, 310, 3472, 313, 5008, 314, 2960, 316, 1936, 327, 7248, 331, 6736, 333, 5712, 334, 3664, 339, 6480, 341, 5456, 342, 3408, 345, 4944, 346, 2896, 348, 1872, 355, 6352, 357, 5328, 358, 3280, 361, 4816, 362, 2768, 364, 1744, 369, 4560, 370, 2512, 372, 1488, 376, 976, 391, 7216, 395, 6704, 397, 5680, 398, 3632, 403, 6448, 405, 5424, 406, 3376, 409, 4912, 410, 2864, 412, 1840, 419, 6320, 421, 5296, 422, 3248, 425, 4784, 426, 2736, 428, 1712, 433, 4528, 434, 2480, 436, 1456, 440, 944, 451, 6256, 453, 5232, 454, 3184, 457, 4720, 458, 2672, 460, 1648, 465, 4464, 466, 2416, 468, 1392, 472, 880, 481, 4336, 482, 2288, 484, 1264, 488, 752, 527, 7688, 535, 7432, 539, 6920, 541, 5896, 542, 3848, 551, 7304, 555, 6792, 557, 5768, 558, 3720, 563, 6536, 565, 5512, 566, 3464, 569, 5000, 570, 2952, 572, 1928, 583, 7240, 587, 6728, 589, 5704, 590, 3656, 595, 6472, 597, 5448, 598, 3400, 601, 4936, 602, 2888, 604, 1864, 611, 6344, 613, 5320, 614, 3272, 617, 4808, 618, 2760, 620, 1736, 625, 4552, 626, 2504, 628, 1480, 632, 968, 647, 7208, 651, 6696, 653, 5672, 654, 3624, 659, 6440, 661, 5416, 662, 3368, 665, 4904, 666, 2856, 668, 1832, 675, 6312, 677, 5288, 678, 3240, 681, 4776, 682, 2728, 684, 1704, 689, 4520, 690, 2472, 692, 1448, 696, 936, 707, 6248, 709, 5224, 710, 3176, 713, 4712, 714, 2664, 716, 1640, 721, 4456, 722, 2408, 724, 1384, 728, 872, 737, 4328, 738, 2280, 740, 1256, 775, 7192, 779, 6680, 781, 5656, 782, 3608, 787, 6424, 789, 5400, 790, 3352, 793, 4888, 794, 2840, 796, 1816, 803, 6296, 805, 5272, 806, 3224, 809, 4760, 810, 2712, 812, 1688, 817, 4504, 818, 2456, 820, 1432, 824, 920, 835, 6232, 837, 5208, 838, 3160, 841, 4696, 842, 2648, 844, 1624, 849, 4440, 850, 2392, 852, 1368, 865, 4312, 866, 2264, 868, 1240, 899, 6200, 901, 5176, 902, 3128, 905, 4664, 906, 2616, 908, 1592, 913, 4408, 914, 2360, 916, 1336, 929, 4280, 930, 2232, 932, 1208, 961, 4216, 962, 2168, 964, 1144, 1039, 7684, 1047, 7428, 1051, 6916, 1053, 5892, 1054, 3844, 1063, 7300, 1067, 6788, 1069, 5764, 1070, 3716, 1075, 6532, 1077, 5508, 1078, 3460, 1081, 4996, 1082, 2948, 1084, 1924, 1095, 7236, 1099, 6724, 1101, 5700, 1102, 3652, 1107, 6468, 1109, 5444, 1110, 3396, 1113, 4932, 1114, 2884, 1116, 1860, 1123, 6340, 1125, 5316, 1126, 3268, 1129, 4804, 1130, 2756, 1132, 1732, 1137, 4548, 1138, 2500, 1140, 1476, 1159, 7204, 1163, 6692, 1165, 5668, 1166, 3620, 1171, 6436, 1173, 5412, 1174, 3364, 1177, 4900, 1178, 2852, 1180, 1828, 1187, 6308, 1189, 5284, 1190, 3236, 1193, 4772, 1194, 2724, 1196, 1700, 1201, 4516, 1202, 2468, 1204, 1444, 1219, 6244, 1221, 5220, 1222, 3172, 1225, 4708, 1226, 2660, 1228, 1636, 1233, 4452, 1234, 2404, 1236, 1380, 1249, 4324, 1250, 2276, 1287, 7188, 1291, 6676, 1293, 5652, 1294, 3604, 1299, 6420, 1301, 5396, 1302, 3348, 1305, 4884, 1306, 2836, 1308, 1812, 1315, 6292, 1317, 5268, 1318, 3220, 1321, 4756, 1322, 2708, 1324, 1684, 1329, 4500, 1330, 2452, 1332, 1428, 1347, 6228, 1349, 5204, 1350, 3156, 1353, 4692, 1354, 2644, 1356, 1620, 1361, 4436, 1362, 2388, 1377, 4308, 1378, 2260, 1411, 6196, 1413, 5172, 1414, 3124, 1417, 4660, 1418, 2612, 1420, 1588, 1425, 4404, 1426, 2356, 1441, 4276, 1442, 2228, 1473, 4212, 1474, 2164, 1543, 7180, 1547, 6668, 1549, 5644, 1550, 3596, 1555, 6412, 1557, 5388, 1558, 3340, 1561, 4876, 1562, 2828, 1564, 1804, 1571, 6284, 1573, 5260, 1574, 3212, 1577, 4748, 1578, 2700, 1580, 1676, 1585, 4492, 1586, 2444, 1603, 6220, 1605, 5196, 1606, 3148, 1609, 4684, 1610, 2636, 1617, 4428, 1618, 2380, 1633, 4300, 1634, 2252, 1667, 6188, 1669, 5164, 1670, 3116, 1673, 4652, 1674, 2604, 1681, 4396, 1682, 2348, 1697, 4268, 1698, 2220, 1729, 4204, 1730, 2156, 1795, 6172, 1797, 5148, 1798, 3100, 1801, 4636, 1802, 2588, 1809, 4380, 1810, 2332, 1825, 4252, 1826, 2204, 1857, 4188, 1858, 2140, 1921, 4156, 1922, 2108, 2063, 7682, 2071, 7426, 2075, 6914, 2077, 5890, 2078, 3842, 2087, 7298, 2091, 6786, 2093, 5762, 2094, 3714, 2099, 6530, 2101, 5506, 2102, 3458, 2105, 4994, 2106, 2946, 2119, 7234, 2123, 6722, 2125, 5698, 2126, 3650, 2131, 6466, 2133, 5442, 2134, 3394, 2137, 4930, 2138, 2882, 2147, 6338, 2149, 5314, 2150, 3266, 2153, 4802, 2154, 2754, 2161, 4546, 2162, 2498, 2183, 7202, 2187, 6690, 2189, 5666, 2190, 3618, 2195, 6434, 2197, 5410, 2198, 3362, 2201, 4898, 2202, 2850, 2211, 6306, 2213, 5282, 2214, 3234, 2217, 4770, 2218, 2722, 2225, 4514, 2226, 2466, 2243, 6242, 2245, 5218, 2246, 3170, 2249, 4706, 2250, 2658, 2257, 4450, 2258, 2402, 2273, 4322, 2311, 7186, 2315, 6674, 2317, 5650, 2318, 3602, 2323, 6418, 2325, 5394, 2326, 3346, 2329, 4882, 2330, 2834, 2339, 6290, 2341, 5266, 2342, 3218, 2345, 4754, 2346, 2706, 2353, 4498, 2354, 2450, 2371, 6226, 2373, 5202, 2374, 3154, 2377, 4690, 2378, 2642, 2385, 4434, 2401, 4306, 2435, 6194, 2437, 5170, 2438, 3122, 2441, 4658, 2442, 2610, 2449, 4402, 2465, 4274, 2497, 4210, 2567, 7178, 2571, 6666, 2573, 5642, 2574, 3594, 2579, 6410, 2581, 5386, 2582, 3338, 2585, 4874, 2586, 2826, 2595, 6282, 2597, 5258, 2598, 3210, 2601, 4746, 2602, 2698, 2609, 4490, 2627, 6218, 2629, 5194, 2630, 3146, 2633, 4682, 2641, 4426, 2657, 4298, 2691, 6186, 2693, 5162, 2694, 3114, 2697, 4650, 2705, 4394, 2721, 4266, 2753, 4202, 2819, 6170, 2821, 5146, 2822, 3098, 2825, 4634, 2833, 4378, 2849, 4250, 2881, 4186, 2945, 4154, 3079, 7174, 3083, 6662, 3085, 5638, 3086, 3590, 3091, 6406, 3093, 5382, 3094, 3334, 3097, 4870, 3107, 6278, 3109, 5254, 3110, 3206, 3113, 4742, 3121, 4486, 3139, 6214, 3141, 5190, 3145, 4678, 3153, 4422, 3169, 4294, 3203, 6182, 3205, 5158, 3209, 4646, 3217, 4390, 3233, 4262, 3265, 4198, 3331, 6166, 3333, 5142, 3337, 4630, 3345, 4374, 3361, 4246, 3393, 4182, 3457, 4150, 3587, 6158, 3589, 5134, 3593, 4622, 3601, 4366, 3617, 4238, 3649, 4174, 3713, 4142, 3841, 4126, 4111, 7681, 4119, 7425, 4123, 6913, 4125, 5889, 4135, 7297, 4139, 6785, 4141, 5761, 4147, 6529, 4149, 5505, 4153, 4993, 4167, 7233, 4171, 6721, 4173, 5697, 4179, 6465, 4181, 5441, 4185, 4929, 4195, 6337, 4197, 5313, 4201, 4801, 4209, 4545, 4231, 7201, 4235, 6689, 4237, 5665, 4243, 6433, 4245, 5409, 4249, 4897, 4259, 6305, 4261, 5281, 4265, 4769, 4273, 4513, 4291, 6241, 4293, 5217, 4297, 4705, 4305, 4449, 4359, 7185, 4363, 6673, 4365, 5649, 4371, 6417, 4373, 5393, 4377, 4881, 4387, 6289, 4389, 5265, 4393, 4753, 4401, 4497, 4419, 6225, 4421, 5201, 4425, 4689, 4483, 6193, 4485, 5169, 4489, 4657, 4615, 7177, 4619, 6665, 4621, 5641, 4627, 6409, 4629, 5385, 4633, 4873, 4643, 6281, 4645, 5257, 4649, 4745, 4675, 6217, 4677, 5193, 4739, 6185, 4741, 5161, 4867, 6169, 4869, 5145, 5127, 7173, 5131, 6661, 5133, 5637, 5139, 6405, 5141, 5381, 5155, 6277, 5157, 5253, 5187, 6213, 5251, 6181, 5379, 6165, 5635, 6157, 6151, 7171, 6155, 6659, 6163, 6403, 6179, 6275, 6211, 5189, 4681, 4433, 4321, 3142, 2634, 2386, 2274, 1612, 1364, 1252, 856, 744, 496}; - ushort[] table2 = {3, 6144, 5, 5120, 6, 3072, 9, 4608, 10, 2560, 12, 1536, 17, 4352, 18, 2304, 20, 1280, 24, 768, 33, 4224, 34, 2176, 36, 1152, 40, 640, 48, 384, 65, 4160, 66, 2112, 68, 1088, 72, 576, 80, 320, 96, 192, 129, 4128, 130, 2080, 132, 1056, 136, 544, 144, 288, 257, 4112, 258, 2064, 260, 1040, 264, 528, 513, 4104, 514, 2056, 516, 1032, 1025, 4100, 1026, 2052, 2049, 4098, 4097, 2050, 1028, 520, 272, 160}; - - // create tables to check decFcsChars - table1Check = new Dictionary(2000); - table2Check = new Dictionary(200); - for (int k = 0; k < table1.Length; k++) - table1Check.Add(table1[k], k); - for (int k = 0; k < table2.Length; k++) - table2Check.Add(table2[k], k); - } - - protected override Result doDecode(BinaryBitmap image, IDictionary hints) - { - currentBitmap = image; - return base.doDecode(image, hints); - } - - public override void reset() - { - base.reset(); - currentBitmap = null; - } - - private ushort binaryStringToDec(string binary) - { - ushort factor = (ushort) Math.Pow(2, binary.Length - 1); - ushort result = 0; - - foreach (char bit in binary) - { - if (bit == '1') - result += factor; - - factor /= 2; - } - - return result; - } - - private string invertedBinaryString(string binary) - { - string result = ""; - - foreach (char bit in binary) - { - if (bit == '1') - result += '0'; - else - result += '1'; - } - - return result; - } - - private bool getCodeWords(out int[] codeWord, string imb, IDictionary table1Check, IDictionary table2Check, int[][] barPos, char[][] barType) - { - // initialize the binaryFcsChars to 0 (has 13 bits) - StringBuilder[] binaryFcsChars = new StringBuilder[10]; - for (int c = 0; c < 10; c++) - binaryFcsChars[c] = new StringBuilder("0000000000000"); - - // fill in the binaryFcsChars - for (int pos = 0; pos < 65; pos++) - { - if (imb[pos] != 'D' && imb[pos] != 'A' && imb[pos] != 'F') - continue; - - int offset = pos + 1; - for (int a = 0; a < 10; a++) // int[][] barPos - { - int i; - for (i = 0; i < 13; i++) - { - if (barPos[a][i] == offset) - { - if (barType[a][i] == imb[pos] || imb[pos] == 'F') - binaryFcsChars[a][12 - i] = '1'; - } - } - } - } - - // convert each binaryFcsChar into decimal format - ushort[] decFcsChars = new ushort[10]; - for (int k = 0; k < 10; k++) - decFcsChars[k] = binaryStringToDec(binaryFcsChars[k].ToString()); - - // change decFcsChars according to whether FCS rules (whether it is the decFcsChars value is contained in one of the tables) - for (int k = 0; k < decFcsChars.Length; k++) - { - if (!table1Check.ContainsKey(decFcsChars[k]) && !table2Check.ContainsKey(decFcsChars[k])) - { - binaryFcsChars[k].Replace(binaryFcsChars[k].ToString(), invertedBinaryString(binaryFcsChars[k].ToString())); - decFcsChars[k] = binaryStringToDec(binaryFcsChars[k].ToString()); - } - } - - // get codewords A-J - codeWord = new int[10]; - for (int k = 0; k < 10; k++) - { - if (!table1Check.ContainsKey(decFcsChars[k])) - { - if (table2Check.ContainsKey(decFcsChars[k])) - codeWord[k] = table2Check[decFcsChars[k]] + 1287; - else - return false; // invert the imb - } - else - codeWord[k] = table1Check[decFcsChars[k]]; - } - - return true; - } - - private string getTrackingNumber(string imb) - { - - // get codewords A-J - int[] codeWord; - if (!getCodeWords(out codeWord, imb, table1Check, table2Check, barPos, barType)) - { - // imb is upside down - StringBuilder invertedImb = new StringBuilder(imb.Length); - for (int k = imb.Length - 1; k >= 0; k--) - { - if (imb[k] == 'A') - invertedImb.Append('D'); - else if (imb[k] == 'D') - invertedImb.Append('A'); - else - invertedImb.Append(imb[k]); - } - - if (!getCodeWords(out codeWord, invertedImb.ToString(), table1Check, table2Check, barPos, barType)) - return null; - } - - - if (codeWord[A] > 658) - codeWord[A] -= 659; - codeWord[J] /= 2; - - // codewords to binaryData - BigInteger binaryData = codeWord[A]; - for (int k = 1; k <= 8; k++) - binaryData = (binaryData*1365) + codeWord[k]; - binaryData = (binaryData*636) + codeWord[J]; - - // get tracking code - int[] tCode = new int[20]; - for (int i = 19; i >= 2; i--) - { - tCode[i] = (int) (binaryData%10); - binaryData /= 10; - } - tCode[1] = (int) (binaryData%5); - binaryData /= 5; - tCode[0] = (int) (binaryData%10); - binaryData /= 10; - - // get routing code and imb number - string imbTrackingNumber = ""; - foreach (int t in tCode) - imbTrackingNumber += t.ToString(); - ulong rCode; - if (binaryData > 1000000000) - { - rCode = (ulong) (binaryData - 1000000000 - 100000 - 1); - imbTrackingNumber += rCode.ToString().PadLeft(11, '0'); - } - else if (binaryData > 100000) - { - rCode = (ulong) (binaryData - 100000 - 1); - imbTrackingNumber += rCode.ToString().PadLeft(9, '0'); - } - else if (binaryData > 0) - { - rCode = (ulong) (binaryData - 1); - imbTrackingNumber += rCode.ToString().PadLeft(5, '0'); - } - - return imbTrackingNumber; - } - - private void fillLists(BitArray row, BitArray topRow, BitArray botRow, ref List listRow, ref List listTop, ref List listBot, int start, int stop) // list: 1=black 0=white - { - const bool isWhite = false; - bool insideBar = false; - - for (int i = start; i <= stop; i++) - { - if (row[i] ^ isWhite) // if current pixel is black - { - if (!insideBar) - { - insideBar = true; - - listRow.Add(1); - - if (topRow[i] ^ isWhite) - listTop.Add(1); - else - listTop.Add(0); - - if (botRow[i] ^ isWhite) - listBot.Add(1); - else - listBot.Add(0); - } - } - else // if current pixel is white - { - if (insideBar) - { - listRow.Add(0); - - if (topRow[i] ^ isWhite) - listTop.Add(1); - else - listTop.Add(0); - - if (botRow[i] ^ isWhite) - listBot.Add(1); - else - listBot.Add(0); - } - - insideBar = false; - } - } - } - - private int isIMB(BitArray row, ref int pixelStartOffset, ref int pixelStopOffset, ref int pixelBarLength) - { - int width = row.Size; - int rowOffset = row.getNextSet(0); - pixelStartOffset = rowOffset; - int previousPixelOffset = pixelStartOffset; - const bool isWhite = false; - - int countBars = 0; - bool insideBar = false; - int currBarLength = 0; - int prevBarLength = 0; - - bool insideWS = false; - int numWSBetween = 0; - int currWSLength = 0; - int prevWSLength = 0; - - for (int i = rowOffset; i < width; i++) - { - if (row[i] ^ isWhite) // if current pixel is black - { - insideWS = false; - - if (!insideBar) - { - if (countBars <= 1) - { - prevWSLength = currWSLength; - } - else - { - if (prevWSLength != currWSLength) - { - numWSBetween = 1; - prevWSLength = currWSLength; - countBars = 1; - pixelStartOffset = previousPixelOffset; - } - } - countBars++; - - insideBar = true; - previousPixelOffset = i; - } - - currWSLength = 0; - - currBarLength++; - } - else // if current pixel is white - { - insideBar = false; - - if (!insideWS) - { - numWSBetween++; - insideWS = true; - - if (countBars <= 1) - prevBarLength = currBarLength; - else - { - if (prevBarLength != currBarLength) - { - countBars = 1; - numWSBetween = 1; - prevWSLength = 0; - pixelStartOffset = previousPixelOffset; - prevBarLength = currBarLength; - } - else - { - if (countBars == 65) // made it this far, so break - { - pixelStopOffset = i; - //pixelBarLength = prevBarLength; - break; - } - } - } - currBarLength = 0; - } - - - currWSLength++; - } - - - } - - pixelBarLength = prevBarLength; - return (countBars); - } - - private int getNumberBars(BitArray row, int start, int stop, int barWidth) - { - const bool isWhite = false; - bool insideBar = false; - int countBars = 0; - int currentBarWidth = 0; - - for (int i = start; i <= stop; i++) - { - if (row[i] ^ isWhite) // if current pixel is black - { - if (!insideBar) - { - //countBars++; - insideBar = true; - } - currentBarWidth++; - - if (i == stop) - { - if (currentBarWidth == barWidth) - countBars++; - } - } - else // if current pixel is white - { - if (insideBar) - { - if (currentBarWidth == barWidth) - countBars++; - } - insideBar = false; - currentBarWidth = 0; - } - } - - return countBars; - } - - public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - if (currentBitmap == null) - return null; - - int pixelStartOffset = 0; - int pixelStopOffset = currentBitmap.Width - 1; - int pixelBarLength = 0; - int numBars = isIMB(row, ref pixelStartOffset, ref pixelStopOffset, ref pixelBarLength); - if (numBars != NUM_BARS_IMB) - return null; - - // create the two bitarrays to check top and bottom - BitArray topRow = new BitArray(currentBitmap.Width); - BitArray botRow = new BitArray(currentBitmap.Width); - int rowNumberTop = rowNumber; - int rowNumberBot = rowNumber; - - do - { - if (rowNumberTop <= 0) - return null; - rowNumberTop--; - topRow = currentBitmap.getBlackRow(rowNumberTop, topRow); - } while (getNumberBars(topRow, pixelStartOffset, pixelStopOffset, pixelBarLength) >= NUM_BARS_IMB); - do - { - if (rowNumberBot >= (currentBitmap.Height - 1)) - return null; - rowNumberBot++; - botRow = currentBitmap.getBlackRow(rowNumberBot, botRow); - } while (getNumberBars(botRow, pixelStartOffset, pixelStopOffset, pixelBarLength) >= NUM_BARS_IMB); - - List listRow = new List(); - List listTop = new List(); - List listBot = new List(); - fillLists(row, topRow, botRow, ref listRow, ref listTop, ref listBot, pixelStartOffset, pixelStopOffset); - - string symbolCode = ""; - for (int k = 0; k < listRow.Count; k++) - { - if (listRow[k] == 0) - continue; - - if (listBot[k] == 1 && listTop[k] == 1) - symbolCode += "F"; - else if (listBot[k] == 1) - symbolCode += "D"; - else if (listTop[k] == 1) - symbolCode += "A"; - else - symbolCode += "T"; - } - - string trackingNumber = getTrackingNumber(symbolCode); - if (trackingNumber == null) - return null; - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(pixelStartOffset, rowNumber)); - resultPointCallback(new ResultPoint(pixelStopOffset, rowNumber)); - } - - return new Result( - trackingNumber, - null, - new[] - { - new ResultPoint(pixelStartOffset, rowNumber), - new ResultPoint(pixelStopOffset, rowNumber) - }, - BarcodeFormat.IMB); - } - } -} diff --git a/zxing.core/xx/maxicode/MaxiCodeReader.cs b/zxing.core/xx/maxicode/MaxiCodeReader.cs deleted file mode 100644 index c9cfbe4..0000000 --- a/zxing.core/xx/maxicode/MaxiCodeReader.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.Collections.Generic; - -using ZXing.Common; -using ZXing.Maxicode.Internal; - -namespace ZXing.Maxicode -{ - /// - /// This implementation can detect and decode a MaxiCode in an image. - /// - public sealed class MaxiCodeReader : Reader - { - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - private const int MATRIX_WIDTH = 30; - private const int MATRIX_HEIGHT = 33; - - private readonly Decoder decoder = new Decoder(); - - /// - /// Locates and decodes a MaxiCode in an image. - /// - /// a String representing the content encoded by the MaxiCode - /// if a MaxiCode cannot be decoded - /// - public Result decode(BinaryBitmap image) - { - return decode(image, null); - } - - /// - /// Locates and decodes a MaxiCode 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 - /// - public Result decode(BinaryBitmap image, IDictionary hints) - { - DecoderResult decoderResult; - if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) - { - BitMatrix bits = extractPureBits(image.BlackMatrix); - if (bits == null) - return null; - decoderResult = decoder.decode(bits, hints); - if (decoderResult == null) - return null; - } - else - { - return null; - } - - ResultPoint[] points = NO_POINTS; - Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.MAXICODE); - - var 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. - /// - /// - /// - /// - private static BitMatrix extractPureBits(BitMatrix image) - { - - int[] enclosingRectangle = image.getEnclosingRectangle(); - if (enclosingRectangle == null) - { - return null; - } - - int left = enclosingRectangle[0]; - int top = enclosingRectangle[1]; - int width = enclosingRectangle[2]; - int height = enclosingRectangle[3]; - - // Now just read off the bits - BitMatrix bits = new BitMatrix(MATRIX_WIDTH, MATRIX_HEIGHT); - for (int y = 0; y < MATRIX_HEIGHT; y++) - { - int iy = top + (y * height + height / 2) / MATRIX_HEIGHT; - for (int x = 0; x < MATRIX_WIDTH; x++) - { - int ix = left + (x * width + width / 2 + (y & 0x01) * width / 2) / MATRIX_WIDTH; - if (image[ix, iy]) - { - bits[x, y] = true; - } - } - } - return bits; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/maxicode/decoder/BitMatrixParser.cs b/zxing.core/xx/maxicode/decoder/BitMatrixParser.cs deleted file mode 100644 index 9d7723c..0000000 --- a/zxing.core/xx/maxicode/decoder/BitMatrixParser.cs +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 ZXing.Common; - -namespace ZXing.Maxicode.Internal -{ - /// - /// mike32767 - /// Manuel Kasten - /// - sealed class BitMatrixParser - { - private static readonly int[][] BITNR = new int[][] { - new[] {121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2}, - new[] {123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3}, - new[] {125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817}, - new[] {283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3}, - new[] {285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820}, - new[] {287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3}, - new[] {289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823}, - new[] {291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3}, - new[] {293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826}, - new[] {409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3}, - new[] {411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829}, - new[] {413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3}, - new[] {415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832}, - new[] {417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3}, - new[] {419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835}, - new[] {481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3}, - new[] {483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838}, - new[] {485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3}, - new[] {487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841}, - new[] {489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3}, - new[] {491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844}, - new[] {559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3}, - new[] {561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847}, - new[] {563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3}, - new[] {565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850}, - new[] {567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3}, - new[] {569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853}, - new[] {727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3}, - new[] {729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856}, - new[] {731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3}, - new[] {733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859}, - new[] {735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3}, - new[] {737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862} - }; - - private readonly BitMatrix bitMatrix; - - /// - /// to parse - /// - internal BitMatrixParser(BitMatrix bitMatrix) - { - this.bitMatrix = bitMatrix; - } - - internal byte[] readCodewords() - { - byte[] result = new byte[144]; - int height = bitMatrix.Height; - int width = bitMatrix.Width; - for (int y = 0; y < height; y++) - { - int[] bitnrRow = BITNR[y]; - for (int x = 0; x < width; x++) - { - int bit = bitnrRow[x]; - if (bit >= 0 && bitMatrix[x, y]) - { - result[bit / 6] |= (byte)(1 << (5 - (bit % 6))); - } - } - } - return result; - } - } -} diff --git a/zxing.core/xx/maxicode/decoder/DecodedBitStreamParser.cs b/zxing.core/xx/maxicode/decoder/DecodedBitStreamParser.cs deleted file mode 100644 index c991898..0000000 --- a/zxing.core/xx/maxicode/decoder/DecodedBitStreamParser.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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.Text; -using ZXing.QrCode.Internal; -using ZXing.Common; - -namespace ZXing.Maxicode.Internal -{ - /// - ///

MaxiCodes can encode text or structured information as bits in one of several modes, - /// with multiple character sets in one code. This class decodes the bits back into text.

- /// - /// mike32767 - /// Manuel Kasten - ///
- internal static class DecodedBitStreamParser - { - private const char SHIFTA = '\uFFF0'; - private const char SHIFTB = '\uFFF1'; - private const char SHIFTC = '\uFFF2'; - private const char SHIFTD = '\uFFF3'; - private const char SHIFTE = '\uFFF4'; - private const char TWOSHIFTA = '\uFFF5'; - private const char THREESHIFTA = '\uFFF6'; - private const char LATCHA = '\uFFF7'; - private const char LATCHB = '\uFFF8'; - private const char LOCK = '\uFFF9'; - private const char ECI = '\uFFFA'; - private const char NS = '\uFFFB'; - private const char PAD = '\uFFFC'; - private const char FS = '\u001C'; - private const char GS = '\u001D'; - private const char RS = '\u001E'; - private const string NINE_DIGITS = "000000000"; - private const string THREE_DIGITS = "000"; - - private static String[] SETS = { - "\nABCDEFGHIJKLMNOPQRSTUVWXYZ"+ECI+FS+GS+RS+NS+' '+PAD+"\"#$%&'()*+,-./0123456789:"+SHIFTB+SHIFTC+SHIFTD+SHIFTE+LATCHB, - "`abcdefghijklmnopqrstuvwxyz"+ECI+FS+GS+RS+NS+'{'+PAD+"}~\u007F;<=>?[\\]^_ ,./:@!|"+PAD+TWOSHIFTA+THREESHIFTA+PAD+SHIFTA+SHIFTC+SHIFTD+SHIFTE+LATCHA, - "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA"+ECI+FS+GS+RS+"\u00DB\u00DC\u00DD\u00DE\u00DF\u00AA\u00AC\u00B1\u00B2\u00B3\u00B5\u00B9\u00BA\u00BC\u00BD\u00BE\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089"+LATCHA+' '+LOCK+SHIFTD+SHIFTE+LATCHB, - "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA"+ECI+FS+GS+RS+NS+"\u00FB\u00FC\u00FD\u00FE\u00FF\u00A1\u00A8\u00AB\u00AF\u00B0\u00B4\u00B7\u00B8\u00BB\u00BF\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094"+LATCHA+' '+SHIFTC+LOCK+SHIFTE+LATCHB, - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A"+ECI+PAD+PAD+'\u001B'+NS+FS+GS+RS+"\u001F\u009F\u00A0\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A9\u00AD\u00AE\u00B6\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E"+LATCHA+' '+SHIFTC+SHIFTD+LOCK+LATCHB, - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F" - }; - - internal static DecoderResult decode(byte[] bytes, int mode) - { - StringBuilder result = new StringBuilder(144); - switch (mode) - { - case 2: - case 3: - String postcode; - if (mode == 2) - { - int pc = getPostCode2(bytes); - var df = "0000000000".Substring(0, getPostCode2Length(bytes)); - postcode = pc.ToString(df); - } - else - { - postcode = getPostCode3(bytes); - } - String country = getCountry(bytes).ToString(THREE_DIGITS); - String service = getServiceClass(bytes).ToString(THREE_DIGITS); - result.Append(getMessage(bytes, 10, 84)); - if (result.ToString().StartsWith("[)>" + RS + "01" + GS)) - { - result.Insert(9, postcode + GS + country + GS + service + GS); - } - else - { - result.Insert(0, postcode + GS + country + GS + service + GS); - } - break; - case 4: - result.Append(getMessage(bytes, 1, 93)); - break; - case 5: - result.Append(getMessage(bytes, 1, 77)); - break; - } - - return new DecoderResult(bytes, result.ToString(), null, mode.ToString()); - } - - private static int getBit(int bit, byte[] bytes) - { - bit--; - return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1; - } - - private static int getInt(byte[] bytes, byte[] x) - { - if (x.Length == 0) - throw new ArgumentException("x"); - - int val = 0; - for (int i = 0; i < x.Length; i++) - { - val += getBit(x[i], bytes) << (x.Length - i - 1); - } - return val; - } - - private static int getCountry(byte[] bytes) - { - return getInt(bytes, new byte[] { 53, 54, 43, 44, 45, 46, 47, 48, 37, 38 }); - } - - private static int getServiceClass(byte[] bytes) - { - return getInt(bytes, new byte[] { 55, 56, 57, 58, 59, 60, 49, 50, 51, 52 }); - } - - private static int getPostCode2Length(byte[] bytes) - { - return getInt(bytes, new byte[] { 39, 40, 41, 42, 31, 32 }); - } - - private static int getPostCode2(byte[] bytes) - { - return getInt(bytes, new byte[] {33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, - 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2}); - } - - private static String getPostCode3(byte[] bytes) - { - return new String( - new char[] - { - SETS[0][getInt(bytes, new byte[] {39, 40, 41, 42, 31, 32})], - SETS[0][getInt(bytes, new byte[] {33, 34, 35, 36, 25, 26})], - SETS[0][getInt(bytes, new byte[] {27, 28, 29, 30, 19, 20})], - SETS[0][getInt(bytes, new byte[] {21, 22, 23, 24, 13, 14})], - SETS[0][getInt(bytes, new byte[] {15, 16, 17, 18, 7, 8})], - SETS[0][getInt(bytes, new byte[] {9, 10, 11, 12, 1, 2})], - } - ); - } - - private static String getMessage(byte[] bytes, int start, int len) - { - StringBuilder sb = new StringBuilder(); - int shift = -1; - int set = 0; - int lastset = 0; - for (int i = start; i < start + len; i++) - { - char c = SETS[set][bytes[i]]; - switch (c) - { - case LATCHA: - set = 0; - shift = -1; - break; - case LATCHB: - set = 1; - shift = -1; - break; - case SHIFTA: - case SHIFTB: - case SHIFTC: - case SHIFTD: - case SHIFTE: - lastset = set; - set = c - SHIFTA; - shift = 1; - break; - case TWOSHIFTA: - lastset = set; - set = 0; - shift = 2; - break; - case THREESHIFTA: - lastset = set; - set = 0; - shift = 3; - break; - case NS: - int nsval = (bytes[++i] << 24) + (bytes[++i] << 18) + (bytes[++i] << 12) + (bytes[++i] << 6) + bytes[++i]; - sb.Append(nsval.ToString(NINE_DIGITS)); - break; - case LOCK: - shift = -1; - break; - default: - sb.Append(c); - break; - } - if (shift-- == 0) - { - set = lastset; - } - } - while (sb.Length > 0 && sb[sb.Length - 1] == PAD) - { - sb.Length = sb.Length - 1; - } - return sb.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/maxicode/decoder/Decoder.cs b/zxing.core/xx/maxicode/decoder/Decoder.cs deleted file mode 100644 index 9d02680..0000000 --- a/zxing.core/xx/maxicode/decoder/Decoder.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.Generic; -using ZXing.Common; -using ZXing.Common.ReedSolomon; - -namespace ZXing.Maxicode.Internal -{ - /// - ///

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

- /// - /// Manuel Kasten - ///
- public sealed class Decoder - { - private const int ALL = 0; - private const int EVEN = 1; - private const int ODD = 2; - - private readonly ReedSolomonDecoder rsDecoder; - - public Decoder() - { - rsDecoder = new ReedSolomonDecoder(GenericGF.MAXICODE_FIELD_64); - } - - public DecoderResult decode(BitMatrix bits) - { - return decode(bits, null); - } - - public DecoderResult decode(BitMatrix bits, - IDictionary hints) - { - BitMatrixParser parser = new BitMatrixParser(bits); - byte[] codewords = parser.readCodewords(); - - if (!correctErrors(codewords, 0, 10, 10, ALL)) - return null; - - int mode = codewords[0] & 0x0F; - byte[] datawords; - switch (mode) - { - case 2: - case 3: - case 4: - if (!correctErrors(codewords, 20, 84, 40, EVEN)) - return null; - if (!correctErrors(codewords, 20, 84, 40, ODD)) - return null; - datawords = new byte[94]; - break; - case 5: - if (!correctErrors(codewords, 20, 68, 56, EVEN)) - return null; - if (!correctErrors(codewords, 20, 68, 56, ODD)) - return null; - datawords = new byte[78]; - break; - default: - return null; - } - - Array.Copy(codewords, 0, datawords, 0, 10); - Array.Copy(codewords, 20, datawords, 10, datawords.Length - 10); - - return DecodedBitStreamParser.decode(datawords, mode); - } - - private bool correctErrors(byte[] codewordBytes, - int start, - int dataCodewords, - int ecCodewords, - int mode) - { - int codewords = dataCodewords + ecCodewords; - - // in EVEN or ODD mode only half the codewords - int divisor = mode == ALL ? 1 : 2; - - // First read into an array of ints - int[] codewordsInts = new int[codewords / divisor]; - for (int i = 0; i < codewords; i++) - { - if ((mode == ALL) || (i % 2 == (mode - 1))) - { - codewordsInts[i / divisor] = codewordBytes[i + start] & 0xFF; - } - } - - if (!rsDecoder.decode(codewordsInts, ecCodewords / divisor)) - return false; - - // 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 < dataCodewords; i++) - { - if ((mode == ALL) || (i % 2 == (mode - 1))) - { - codewordBytes[i + start] = (byte)codewordsInts[i / divisor]; - } - } - - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/multi/ByQuadrantReader.cs b/zxing.core/xx/multi/ByQuadrantReader.cs deleted file mode 100644 index fdf3215..0000000 --- a/zxing.core/xx/multi/ByQuadrantReader.cs +++ /dev/null @@ -1,128 +0,0 @@ -/* -* Copyright 2009 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System.Collections.Generic; - -namespace ZXing.Multi -{ - /// - /// 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 - { - private readonly Reader @delegate; - - /// - /// Initializes a new instance of the class. - /// - /// The @delegate. - public ByQuadrantReader(Reader @delegate) - { - this.@delegate = @delegate; - } - - /// - /// Locates and decodes a barcode in some format within an image. - /// - /// image of barcode to decode - /// - /// String which the barcode encodes - /// - public Result decode(BinaryBitmap image) - { - return decode(image, null); - } - - /// - /// 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 - /// - public Result decode(BinaryBitmap image, IDictionary hints) - { - int width = image.Width; - int height = image.Height; - int halfWidth = width/2; - int halfHeight = height/2; - - // No need to call makeAbsolute as results will be relative to original top left here - var result = @delegate.decode(image.crop(0, 0, halfWidth, halfHeight), hints); - if (result != null) - return result; - - result = @delegate.decode(image.crop(halfWidth, 0, halfWidth, halfHeight), hints); - if (result != null) - { - makeAbsolute(result.ResultPoints, halfWidth, 0); - return result; - } - - result = @delegate.decode(image.crop(0, halfHeight, halfWidth, halfHeight), hints); - if (result != null) - { - makeAbsolute(result.ResultPoints, 0, halfHeight); - return result; - } - - result = @delegate.decode(image.crop(halfWidth, halfHeight, halfWidth, halfHeight), hints); - if (result != null) - { - makeAbsolute(result.ResultPoints, halfWidth, halfHeight); - return result; - } - - int quarterWidth = halfWidth/2; - int quarterHeight = halfHeight/2; - var center = image.crop(quarterWidth, quarterHeight, halfWidth, halfHeight); - result = @delegate.decode(center, hints); - makeAbsolute(result.ResultPoints, quarterWidth, quarterHeight); - return result; - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - public void reset() - { - @delegate.reset(); - } - - private static void makeAbsolute(ResultPoint[] points, int leftOffset, int topOffset) - { - if (points != null) - { - for (int i = 0; i < points.Length; i++) - { - ResultPoint relative = points[i]; - points[i] = new ResultPoint(relative.X + leftOffset, relative.Y + topOffset); - } - } - } - } -} diff --git a/zxing.core/xx/multi/GenericMultipleBarcodeReader.cs b/zxing.core/xx/multi/GenericMultipleBarcodeReader.cs deleted file mode 100644 index 0013ab4..0000000 --- a/zxing.core/xx/multi/GenericMultipleBarcodeReader.cs +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright 2009 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System.Collections.Generic; - -namespace ZXing.Multi -{ - /// - ///

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.

- ///

A caller may want to also employ {@link ByQuadrantReader} 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).

- /// Sean Owen - ///
- public sealed class GenericMultipleBarcodeReader : MultipleBarcodeReader, Reader - { - private const int MIN_DIMENSION_TO_RECUR = 30; - private const int MAX_DEPTH = 4; - - private readonly Reader _delegate; - - /// - /// Initializes a new instance of the class. - /// - /// The @delegate. - public GenericMultipleBarcodeReader(Reader @delegate) - { - this._delegate = @delegate; - } - - /// - /// Decodes the multiple. - /// - /// The image. - /// - public Result[] decodeMultiple(BinaryBitmap image) - { - return decodeMultiple(image, null); - } - - /// - /// Decodes the multiple. - /// - /// The image. - /// The hints. - /// - public Result[] decodeMultiple(BinaryBitmap image, IDictionary hints) - { - var results = new List(); - doDecodeMultiple(image, hints, results, 0, 0, 0); - if ((results.Count == 0)) - { - return null; - } - int numResults = results.Count; - Result[] resultArray = new Result[numResults]; - for (int i = 0; i < numResults; i++) - { - resultArray[i] = (Result)results[i]; - } - return resultArray; - } - - private void doDecodeMultiple(BinaryBitmap image, IDictionary hints, IList results, int xOffset, int yOffset, int currentDepth) - { - if (currentDepth > MAX_DEPTH) - { - return; - } - - Result result = _delegate.decode(image, hints); - if (result == null) - 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) - { - 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]; - if (point == null) - { - continue; - } - 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, currentDepth + 1); - } - // Decode above barcode - if (minY > MIN_DIMENSION_TO_RECUR) - { - doDecodeMultiple(image.crop(0, 0, width, (int)minY), hints, results, xOffset, yOffset, currentDepth + 1); - } - // 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, currentDepth + 1); - } - // 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, currentDepth + 1); - } - } - - private static Result translateResultPoints(Result result, int xOffset, int yOffset) - { - var oldResultPoints = result.ResultPoints; - var newResultPoints = new ResultPoint[oldResultPoints.Length]; - for (int i = 0; i < oldResultPoints.Length; i++) - { - var oldPoint = oldResultPoints[i]; - if (oldPoint != null) - { - newResultPoints[i] = new ResultPoint(oldPoint.X + xOffset, oldPoint.Y + yOffset); - } - } - var newResult = new Result(result.Text, result.RawBytes, newResultPoints, result.BarcodeFormat); - newResult.putAllMetadata(result.ResultMetadata); - return newResult; - } - - /// - /// Locates and decodes a barcode in some format within an image. - /// - /// image of barcode to decode - /// - /// String which the barcode encodes - /// - public Result decode(BinaryBitmap image) - { - return _delegate.decode(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 - /// - public Result decode(BinaryBitmap image, IDictionary hints) - { - return _delegate.decode(image, hints); - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - public void reset() - { - _delegate.reset(); - } - } -} diff --git a/zxing.core/xx/multi/MultipleBarcodeReader.cs b/zxing.core/xx/multi/MultipleBarcodeReader.cs deleted file mode 100644 index 65fac63..0000000 --- a/zxing.core/xx/multi/MultipleBarcodeReader.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright 2009 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System.Collections.Generic; - -namespace ZXing.Multi -{ - /// - /// Implementation of this interface attempt to read several barcodes from one image. - /// Sean Owen - /// - /// - public interface MultipleBarcodeReader - { - /// - /// Decodes the multiple. - /// - /// The image. - /// - Result[] decodeMultiple(BinaryBitmap image); - - /// - /// Decodes the multiple. - /// - /// The image. - /// The hints. - /// - Result[] decodeMultiple(BinaryBitmap image, IDictionary hints); - } -} \ No newline at end of file diff --git a/zxing.core/xx/multi/qrcode/QRCodeMultiReader.cs b/zxing.core/xx/multi/qrcode/QRCodeMultiReader.cs deleted file mode 100644 index 92f53b7..0000000 --- a/zxing.core/xx/multi/qrcode/QRCodeMultiReader.cs +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; -using ZXing.Multi.QrCode.Internal; -using ZXing.QrCode; -using ZXing.QrCode.Internal; - -namespace ZXing.Multi.QrCode -{ - /// - /// This implementation can detect and decode multiple QR Codes in an image. - /// - public sealed class QRCodeMultiReader : QRCodeReader, MultipleBarcodeReader - { - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - - /// - /// Decodes the multiple. - /// - /// The image. - /// - public Result[] decodeMultiple(BinaryBitmap image) - { - return decodeMultiple(image, null); - } - - /// - /// Decodes the multiple. - /// - /// The image. - /// The hints. - /// - public Result[] decodeMultiple(BinaryBitmap image, IDictionary hints) - { - var results = new List(); - var detectorResults = new MultiDetector(image.BlackMatrix).detectMulti(hints); - foreach (DetectorResult detectorResult in detectorResults) - { - var decoderResult = getDecoder().decode(detectorResult.Bits, hints); - if (decoderResult == null) - continue; - - var points = detectorResult.Points; - // If the code was mirrored: swap the bottom-left and the top-right points. - var data = decoderResult.Other as QRCodeDecoderMetaData; - if (data != null) - { - data.applyMirroredCorrection(points); - } - var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); - var byteSegments = decoderResult.ByteSegments; - if (byteSegments != null) - { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); - } - var ecLevel = decoderResult.ECLevel; - if (ecLevel != null) - { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); - } - if (decoderResult.StructuredAppend) - { - result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE, decoderResult.StructuredAppendSequenceNumber); - result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_PARITY, decoderResult.StructuredAppendParity); - } - results.Add(result); - } - if (results.Count == 0) - { - return null; - } - results = ProcessStructuredAppend(results); - return results.ToArray(); - } - - private List ProcessStructuredAppend(List results) - { - bool hasSA = false; - // first, check, if there is at least on SA result in the list - foreach (var result in results) - { - if (result.ResultMetadata.ContainsKey(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE)) - { - hasSA = true; - break; - } - } - if (!hasSA) - { - return results; - } - // it is, second, split the lists and built a new result list - var newResults = new List(); - var saResults = new List(); - foreach (var result in results) - { - newResults.Add(result); - if (result.ResultMetadata.ContainsKey(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE)) - { - saResults.Add(result); - } - } - // sort and concatenate the SA list items - saResults.Sort(SaSequenceSort); - var concatedText = String.Empty; - var rawBytesLen = 0; - int byteSegmentLength = 0; - foreach (var saResult in saResults) - { - concatedText += saResult.Text; - rawBytesLen += saResult.RawBytes.Length; - if (saResult.ResultMetadata.ContainsKey(ResultMetadataType.BYTE_SEGMENTS)) - { - foreach (var segment in (IEnumerable) saResult.ResultMetadata[ResultMetadataType.BYTE_SEGMENTS]) - { - byteSegmentLength += segment.Length; - } - } - } - var newRawBytes = new byte[rawBytesLen]; - byte[] newByteSegment = new byte[byteSegmentLength]; - int newRawBytesIndex = 0; - int byteSegmentIndex = 0; - foreach (var saResult in saResults) - { - Array.Copy(saResult.RawBytes, 0, newRawBytes, newRawBytesIndex, saResult.RawBytes.Length); - newRawBytesIndex += saResult.RawBytes.Length; - if (saResult.ResultMetadata.ContainsKey(ResultMetadataType.BYTE_SEGMENTS)) - { - foreach (var segment in (IEnumerable) saResult.ResultMetadata[ResultMetadataType.BYTE_SEGMENTS]) - { - Array.Copy(segment, 0, newByteSegment, byteSegmentIndex, segment.Length); - byteSegmentIndex += segment.Length; - } - } - } - Result newResult = new Result(concatedText, newRawBytes, NO_POINTS, BarcodeFormat.QR_CODE); - if (byteSegmentLength > 0) - { - var byteSegmentList = new List(); - byteSegmentList.Add(newByteSegment); - newResult.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegmentList); - } - newResults.Add(newResult); - return newResults; - } - - private int SaSequenceSort(Result a, Result b) - { - var aNumber = (int)(a.ResultMetadata[ResultMetadataType.STRUCTURED_APPEND_SEQUENCE]); - var bNumber = (int)(b.ResultMetadata[ResultMetadataType.STRUCTURED_APPEND_SEQUENCE]); - return aNumber - bNumber; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/multi/qrcode/detector/MultiDetector.cs b/zxing.core/xx/multi/qrcode/detector/MultiDetector.cs deleted file mode 100644 index 7c8142d..0000000 --- a/zxing.core/xx/multi/qrcode/detector/MultiDetector.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Collections.Generic; -using ZXing.Common; -using ZXing.QrCode.Internal; - -namespace ZXing.Multi.QrCode.Internal -{ - /// - ///

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.

- /// - /// Sean Owen - /// Hannes Erven - ///
- public sealed class MultiDetector : Detector - { - private static readonly DetectorResult[] EMPTY_DETECTOR_RESULTS = new DetectorResult[0]; - - /// - /// Initializes a new instance of the class. - /// - /// The image. - public MultiDetector(BitMatrix image) - : base(image) - { - } - - /// - /// Detects the multi. - /// - /// The hints. - /// - public DetectorResult[] detectMulti(IDictionary hints) - { - var image = Image; - var resultPointCallback = - hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - var finder = new MultiFinderPatternFinder(image, resultPointCallback); - var infos = finder.findMulti(hints); - - if (infos.Length == 0) - { - return EMPTY_DETECTOR_RESULTS; - } - - var result = new List(); - foreach (FinderPatternInfo info in infos) - { - var oneResult = processFinderPatternInfo(info); - if (oneResult != null) - result.Add(oneResult); - } - if (result.Count == 0) - { - return EMPTY_DETECTOR_RESULTS; - } - else - { - return result.ToArray(); - } - } - } -} diff --git a/zxing.core/xx/multi/qrcode/detector/MultiFinderPatternFinder.cs b/zxing.core/xx/multi/qrcode/detector/MultiFinderPatternFinder.cs deleted file mode 100644 index 542d0ec..0000000 --- a/zxing.core/xx/multi/qrcode/detector/MultiFinderPatternFinder.cs +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; -using ZXing.QrCode.Internal; - -namespace ZXing.Multi.QrCode.Internal -{ - /// - ///

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 , 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.

- /// - /// Sean Owen - /// Hannes Erven - ///
- sealed class MultiFinderPatternFinder : FinderPatternFinder - { - - private static 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 static float MAX_MODULE_COUNT_PER_EDGE = 180; - // min. legal count per modules per QR code edge (11) - private static 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 static 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 sealed class ModuleSizeComparator : IComparer - { - public int Compare(FinderPattern center1, FinderPattern center2) - { - 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) - { - } - - 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 CENTER_QUORUM times, and whose module - /// size differs from the average among those patterns the least - /// - private FinderPattern[][] selectMutipleBestPatterns() - { - List possibleCenters = PossibleCenters; - int size = possibleCenters.Count; - - if (size < 3) - { - // Couldn't find enough finder patterns - return null; - } - - /* - * 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] - } - }; - } - - // 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++) - { - FinderPattern p1 = possibleCenters[i1]; - if (p1 == null) - { - continue; - } - - for (int i2 = i1 + 1; i2 < (size - 1); i2++) - { - FinderPattern p2 = possibleCenters[i2]; - if (p2 == null) - { - continue; - } - - // 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) - { - // 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 = 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(); - } - - // Nothing found! - return null; - } - - public FinderPatternInfo[] findMulti(IDictionary hints) - { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - bool pureBarcode = hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE); - 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) - { - 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[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) && handlePossibleCenter(stateCount, i, j, pureBarcode)) - { // Yes - // 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, pureBarcode); - } // end if foundPatternCross - } // for i=iSkip-1 ... - FinderPattern[][] patternInfo = selectMutipleBestPatterns(); - if (patternInfo == null) - return EMPTY_RESULT_ARRAY; - 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/zxing.core/xx/oned/CodaBarReader.cs b/zxing.core/xx/oned/CodaBarReader.cs deleted file mode 100644 index a0b5db5..0000000 --- a/zxing.core/xx/oned/CodaBarReader.cs +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Decodes Codabar barcodes.

- /// - /// Bas Vijfwinkel - ///
- public sealed class CodaBarReader : OneDReader - { - // These values are critical for determining how permissive the decoding - // will be. All stripe sizes must be within the window these define, as - // compared to the average stripe size. - private static readonly int MAX_ACCEPTABLE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 2.0f); - private static readonly int PADDING = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 1.5f); - - private const String ALPHABET_STRING = "0123456789-$:/.+ABCD"; - internal static readonly char[] ALPHABET = ALPHABET_STRING.ToCharArray(); - - /** - * These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of - * each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. - */ - - internal static int[] CHARACTER_ENCODINGS = { - 0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9 - 0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD - }; - - // minimal number of characters that should be present (inclusing start and stop characters) - // under normal circumstances this should be set to 3, but can be set higher - // as a last-ditch attempt to reduce false positives. - private const int MIN_CHARACTER_LENGTH = 3; - - // official start and end patterns - private static readonly char[] STARTEND_ENCODING = { 'A', 'B', 'C', 'D' }; - // some codabar generator allow the codabar string to be closed by every - // character. This will cause lots of false positives! - - // some industries use a checksum standard but this is not part of the original codabar standard - // for more information see : http://www.mecsw.com/specs/codabar.html - - // Keep some instance variables to avoid reallocations - private readonly StringBuilder decodeRowResult; - private int[] counters; - private int counterLength; - - public CodaBarReader() - { - decodeRowResult = new StringBuilder(20); - counters = new int[80]; - counterLength = 0; - } - - public override Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - for (var index = 0; index < counters.Length; index++) - counters[index] = 0; - - if (!setCounters(row)) - return null; - - int startOffset = findStartPattern(); - if (startOffset < 0) - return null; - - int nextStart = startOffset; - - decodeRowResult.Length = 0; - do - { - int charOffset = toNarrowWidePattern(nextStart); - if (charOffset == -1) - { - return null; - } - // Hack: We store the position in the alphabet table into a - // StringBuilder, so that we can access the decoded patterns in - // validatePattern. We'll translate to the actual characters later. - decodeRowResult.Append((char) charOffset); - nextStart += 8; - // Stop as soon as we see the end character. - if (decodeRowResult.Length > 1 && - arrayContains(STARTEND_ENCODING, ALPHABET[charOffset])) - { - break; - } - } while (nextStart < counterLength); // no fixed end pattern so keep on reading while data is available - - // Look for whitespace after pattern: - int trailingWhitespace = counters[nextStart - 1]; - int lastPatternSize = 0; - for (int i = -8; i < -1; i++) - { - lastPatternSize += counters[nextStart + i]; - } - - // We need to see whitespace equal to 50% of the last pattern size, - // otherwise this is probably a false positive. The exception is if we are - // at the end of the row. (I.e. the barcode barely fits.) - if (nextStart < counterLength && trailingWhitespace < lastPatternSize/2) - { - return null; - } - - if (!validatePattern(startOffset)) - return null; - - // Translate character table offsets to actual characters. - for (int i = 0; i < decodeRowResult.Length; i++) - { - decodeRowResult[i] = ALPHABET[decodeRowResult[i]]; - } - // Ensure a valid start and end character - char startchar = decodeRowResult[0]; - if (!arrayContains(STARTEND_ENCODING, startchar)) - { - return null; - } - char endchar = decodeRowResult[decodeRowResult.Length - 1]; - if (!arrayContains(STARTEND_ENCODING, endchar)) - { - return null; - } - - // remove stop/start characters character and check if a long enough string is contained - if (decodeRowResult.Length <= MIN_CHARACTER_LENGTH) - { - // Almost surely a false positive ( start + stop + at least 1 character) - return null; - } - - if (!SupportClass.GetValue(hints, DecodeHintType.RETURN_CODABAR_START_END, false)) - { - decodeRowResult.Remove(decodeRowResult.Length - 1, 1); - decodeRowResult.Remove(0, 1); - } - - int runningCount = 0; - for (int i = 0; i < startOffset; i++) - { - runningCount += counters[i]; - } - float left = runningCount; - for (int i = startOffset; i < nextStart - 1; i++) - { - runningCount += counters[i]; - } - float right = runningCount; - - var resultPointCallback = SupportClass.GetValue(hints, DecodeHintType.NEED_RESULT_POINT_CALLBACK, (ResultPointCallback) null); - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(left, rowNumber)); - resultPointCallback(new ResultPoint(right, rowNumber)); - } - - return new Result( - decodeRowResult.ToString(), - null, - new[] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - BarcodeFormat.CODABAR); - } - - private bool validatePattern(int start) - { - // First, sum up the total size of our four categories of stripe sizes; - int[] sizes = { 0, 0, 0, 0 }; - int[] counts = { 0, 0, 0, 0 }; - int end = decodeRowResult.Length - 1; - - // We break out of this loop in the middle, in order to handle - // inter-character spaces properly. - int pos = start; - for (int i = 0; true; i++) - { - int pattern = CHARACTER_ENCODINGS[decodeRowResult[i]]; - for (int j = 6; j >= 0; j--) - { - // Even j = bars, while odd j = spaces. Categories 2 and 3 are for - // long stripes, while 0 and 1 are for short stripes. - int category = (j & 1) + (pattern & 1) * 2; - sizes[category] += counters[pos + j]; - counts[category]++; - pattern >>= 1; - } - if (i >= end) - { - break; - } - // We ignore the inter-character space - it could be of any size. - pos += 8; - } - - // Calculate our allowable size thresholds using fixed-point math. - int[] maxes = new int[4]; - int[] mins = new int[4]; - // Define the threshold of acceptability to be the midpoint between the - // average small stripe and the average large stripe. No stripe lengths - // should be on the "wrong" side of that line. - for (int i = 0; i < 2; i++) - { - mins[i] = 0; // Accept arbitrarily small "short" stripes. - mins[i + 2] = ((sizes[i] << INTEGER_MATH_SHIFT) / counts[i] + - (sizes[i + 2] << INTEGER_MATH_SHIFT) / counts[i + 2]) >> 1; - maxes[i] = mins[i + 2]; - maxes[i + 2] = (sizes[i + 2] * MAX_ACCEPTABLE + PADDING) / counts[i + 2]; - } - - // Now verify that all of the stripes are within the thresholds. - pos = start; - for (int i = 0; true; i++) - { - int pattern = CHARACTER_ENCODINGS[decodeRowResult[i]]; - for (int j = 6; j >= 0; j--) - { - // Even j = bars, while odd j = spaces. Categories 2 and 3 are for - // long stripes, while 0 and 1 are for short stripes. - int category = (j & 1) + (pattern & 1) * 2; - int size = counters[pos + j] << INTEGER_MATH_SHIFT; - if (size < mins[category] || size > maxes[category]) - { - return false; - } - pattern >>= 1; - } - if (i >= end) - { - break; - } - pos += 8; - } - - return true; - } - - /// - /// Records the size of all runs of white and black pixels, starting with white. - /// This is just like recordPattern, except it records all the counters, and - /// uses our builtin "counters" member for storage. - /// - /// row to count from - private bool setCounters(BitArray row) - { - counterLength = 0; - // Start from the first white bit. - int i = row.getNextUnset(0); - int end = row.Size; - if (i >= end) - { - return false; - } - bool isWhite = true; - int count = 0; - while (i < end) - { - if (row[i] ^ isWhite) - { - // that is, exactly one is true - count++; - } - else - { - counterAppend(count); - count = 1; - isWhite = !isWhite; - } - i++; - } - counterAppend(count); - return true; - } - - private void counterAppend(int e) - { - counters[counterLength] = e; - counterLength++; - if (counterLength >= counters.Length) - { - int[] temp = new int[counterLength * 2]; - Array.Copy(counters, 0, temp, 0, counterLength); - counters = temp; - } - } - - private int findStartPattern() - { - for (int i = 1; i < counterLength; i += 2) - { - int charOffset = toNarrowWidePattern(i); - if (charOffset != -1 && arrayContains(STARTEND_ENCODING, ALPHABET[charOffset])) - { - // Look for whitespace before start pattern, >= 50% of width of start pattern - // We make an exception if the whitespace is the first element. - int patternSize = 0; - for (int j = i; j < i + 7; j++) - { - patternSize += counters[j]; - } - if (i == 1 || counters[i - 1] >= patternSize / 2) - { - return i; - } - } - } - return -1; - } - - internal static bool arrayContains(char[] array, char key) - { - if (array != null) - { - foreach (char c in array) - { - if (c == key) - { - return true; - } - } - } - return false; - } - - // Assumes that counters[position] is a bar. - private int toNarrowWidePattern(int position) - { - int end = position + 7; - if (end >= counterLength) - { - return -1; - } - int[] theCounters = counters; - - int maxBar = 0; - int minBar = Int32.MaxValue; - for (int j = position; j < end; j += 2) - { - int currentCounter = theCounters[j]; - if (currentCounter < minBar) - { - minBar = currentCounter; - } - if (currentCounter > maxBar) - { - maxBar = currentCounter; - } - } - int thresholdBar = (minBar + maxBar) / 2; - - int maxSpace = 0; - int minSpace = Int32.MaxValue; - for (int j = position + 1; j < end; j += 2) - { - int currentCounter = theCounters[j]; - if (currentCounter < minSpace) - { - minSpace = currentCounter; - } - if (currentCounter > maxSpace) - { - maxSpace = currentCounter; - } - } - int thresholdSpace = (minSpace + maxSpace) / 2; - - int bitmask = 1 << 7; - int pattern = 0; - for (int i = 0; i < 7; i++) - { - int threshold = (i & 1) == 0 ? thresholdBar : thresholdSpace; - bitmask >>= 1; - if (theCounters[position + i] > threshold) - { - pattern |= bitmask; - } - } - - for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) - { - if (CHARACTER_ENCODINGS[i] == pattern) - { - return i; - } - } - return -1; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/CodaBarWriter.cs b/zxing.core/xx/oned/CodaBarWriter.cs deleted file mode 100644 index 1fbe0ed..0000000 --- a/zxing.core/xx/oned/CodaBarWriter.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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; - -namespace ZXing.OneD -{ - /// - /// This class renders CodaBar as []. - /// - /// dsbnatut@gmail.com (Kazuki Nishiura) - public sealed class CodaBarWriter : OneDimensionalCodeWriter - { - private static readonly char[] START_END_CHARS = {'A', 'B', 'C', 'D'}; - private static readonly char[] ALT_START_END_CHARS = {'T', 'N', '*', 'E'}; - private static readonly char[] CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED = {'/', ':', '+', '.'}; - private static readonly char DEFAULT_GUARD = START_END_CHARS[0]; - - public override bool[] encode(String contents) - { - if (contents.Length < 2) - { - // Can't have a start/end guard, so tentatively add default guards - contents = DEFAULT_GUARD + contents + DEFAULT_GUARD; - } - else - { - // Verify input and calculate decoded length. - char firstChar = Char.ToUpper(contents[0]); - char lastChar = Char.ToUpper(contents[contents.Length - 1]); - bool startsNormal = CodaBarReader.arrayContains(START_END_CHARS, firstChar); - bool endsNormal = CodaBarReader.arrayContains(START_END_CHARS, lastChar); - bool startsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar); - bool endsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar); - if (startsNormal) - { - if (!endsNormal) - { - throw new ArgumentException("Invalid start/end guards: " + contents); - } - // else already has valid start/end - } - else if (startsAlt) - { - if (!endsAlt) - { - throw new ArgumentException("Invalid start/end guards: " + contents); - } - // else already has valid start/end - } - else - { - // Doesn't start with a guard - if (endsNormal || endsAlt) - { - throw new ArgumentException("Invalid start/end guards: " + contents); - } - // else doesn't end with guard either, so add a default - contents = DEFAULT_GUARD + contents + DEFAULT_GUARD; - } - } - - // The start character and the end character are decoded to 10 length each. - int resultLength = 20; - for (int i = 1; i < contents.Length - 1; i++) - { - if (Char.IsDigit(contents[i]) || contents[i] == '-' || contents[i] == '$') - { - resultLength += 9; - } - else if (CodaBarReader.arrayContains(CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED, contents[i])) - { - resultLength += 10; - } - else - { - throw new ArgumentException("Cannot encode : '" + contents[i] + '\''); - } - } - // A blank is placed between each character. - resultLength += contents.Length - 1; - - var result = new bool[resultLength]; - int position = 0; - for (int index = 0; index < contents.Length; index++) - { - char c = Char.ToUpper(contents[index]); - if (index == 0 || index == contents.Length - 1) - { - // The start/end chars are not in the CodaBarReader.ALPHABET. - switch (c) - { - case 'T': - c = 'A'; - break; - case 'N': - c = 'B'; - break; - case '*': - c = 'C'; - break; - case 'E': - c = 'D'; - break; - } - } - int code = 0; - for (int i = 0; i < CodaBarReader.ALPHABET.Length; i++) - { - // Found any, because I checked above. - if (c == CodaBarReader.ALPHABET[i]) - { - code = CodaBarReader.CHARACTER_ENCODINGS[i]; - break; - } - } - bool color = true; - int counter = 0; - int bit = 0; - while (bit < 7) - { - // A character consists of 7 digit. - result[position] = color; - position++; - if (((code >> (6 - bit)) & 1) == 0 || counter == 1) - { - color = !color; // Flip the color. - bit++; - counter = 0; - } - else - { - counter++; - } - } - if (index < contents.Length - 1) - { - result[position] = false; - position++; - } - } - return result; - } - } -} diff --git a/zxing.core/xx/oned/Code128EncodingOptions.cs b/zxing.core/xx/oned/Code128EncodingOptions.cs deleted file mode 100644 index a681759..0000000 --- a/zxing.core/xx/oned/Code128EncodingOptions.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// The class holds the available options for the QrCodeWriter - /// - public class Code128EncodingOptions : EncodingOptions - { - /// - /// if true, don't switch to codeset C for numbers - /// - public bool ForceCodesetB - { - get - { - if (Hints.ContainsKey(EncodeHintType.CODE128_FORCE_CODESET_B)) - { - return (bool)Hints[EncodeHintType.CODE128_FORCE_CODESET_B]; - } - return false; - } - set - { - Hints[EncodeHintType.CODE128_FORCE_CODESET_B] = value; - } - } - } -} diff --git a/zxing.core/xx/oned/Code128Reader.cs b/zxing.core/xx/oned/Code128Reader.cs deleted file mode 100644 index 69108f5..0000000 --- a/zxing.core/xx/oned/Code128Reader.cs +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Decodes Code 128 barcodes.

- /// - /// Sean Owen - ///
- public sealed class Code128Reader : OneDReader - { - internal static int[][] CODE_PATTERNS = { - new[] {2, 1, 2, 2, 2, 2}, // 0 - new[] {2, 2, 2, 1, 2, 2}, - new[] {2, 2, 2, 2, 2, 1}, - new[] {1, 2, 1, 2, 2, 3}, - new[] {1, 2, 1, 3, 2, 2}, - new[] {1, 3, 1, 2, 2, 2}, // 5 - new[] {1, 2, 2, 2, 1, 3}, - new[] {1, 2, 2, 3, 1, 2}, - new[] {1, 3, 2, 2, 1, 2}, - new[] {2, 2, 1, 2, 1, 3}, - new[] {2, 2, 1, 3, 1, 2}, // 10 - new[] {2, 3, 1, 2, 1, 2}, - new[] {1, 1, 2, 2, 3, 2}, - new[] {1, 2, 2, 1, 3, 2}, - new[] {1, 2, 2, 2, 3, 1}, - new[] {1, 1, 3, 2, 2, 2}, // 15 - new[] {1, 2, 3, 1, 2, 2}, - new[] {1, 2, 3, 2, 2, 1}, - new[] {2, 2, 3, 2, 1, 1}, - new[] {2, 2, 1, 1, 3, 2}, - new[] {2, 2, 1, 2, 3, 1}, // 20 - new[] {2, 1, 3, 2, 1, 2}, - new[] {2, 2, 3, 1, 1, 2}, - new[] {3, 1, 2, 1, 3, 1}, - new[] {3, 1, 1, 2, 2, 2}, - new[] {3, 2, 1, 1, 2, 2}, // 25 - new[] {3, 2, 1, 2, 2, 1}, - new[] {3, 1, 2, 2, 1, 2}, - new[] {3, 2, 2, 1, 1, 2}, - new[] {3, 2, 2, 2, 1, 1}, - new[] {2, 1, 2, 1, 2, 3}, // 30 - new[] {2, 1, 2, 3, 2, 1}, - new[] {2, 3, 2, 1, 2, 1}, - new[] {1, 1, 1, 3, 2, 3}, - new[] {1, 3, 1, 1, 2, 3}, - new[] {1, 3, 1, 3, 2, 1}, // 35 - new[] {1, 1, 2, 3, 1, 3}, - new[] {1, 3, 2, 1, 1, 3}, - new[] {1, 3, 2, 3, 1, 1}, - new[] {2, 1, 1, 3, 1, 3}, - new[] {2, 3, 1, 1, 1, 3}, // 40 - new[] {2, 3, 1, 3, 1, 1}, - new[] {1, 1, 2, 1, 3, 3}, - new[] {1, 1, 2, 3, 3, 1}, - new[] {1, 3, 2, 1, 3, 1}, - new[] {1, 1, 3, 1, 2, 3}, // 45 - new[] {1, 1, 3, 3, 2, 1}, - new[] {1, 3, 3, 1, 2, 1}, - new[] {3, 1, 3, 1, 2, 1}, - new[] {2, 1, 1, 3, 3, 1}, - new[] {2, 3, 1, 1, 3, 1}, // 50 - new[] {2, 1, 3, 1, 1, 3}, - new[] {2, 1, 3, 3, 1, 1}, - new[] {2, 1, 3, 1, 3, 1}, - new[] {3, 1, 1, 1, 2, 3}, - new[] {3, 1, 1, 3, 2, 1}, // 55 - new[] {3, 3, 1, 1, 2, 1}, - new[] {3, 1, 2, 1, 1, 3}, - new[] {3, 1, 2, 3, 1, 1}, - new[] {3, 3, 2, 1, 1, 1}, - new[] {3, 1, 4, 1, 1, 1}, // 60 - new[] {2, 2, 1, 4, 1, 1}, - new[] {4, 3, 1, 1, 1, 1}, - new[] {1, 1, 1, 2, 2, 4}, - new[] {1, 1, 1, 4, 2, 2}, - new[] {1, 2, 1, 1, 2, 4}, // 65 - new[] {1, 2, 1, 4, 2, 1}, - new[] {1, 4, 1, 1, 2, 2}, - new[] {1, 4, 1, 2, 2, 1}, - new[] {1, 1, 2, 2, 1, 4}, - new[] {1, 1, 2, 4, 1, 2}, // 70 - new[] {1, 2, 2, 1, 1, 4}, - new[] {1, 2, 2, 4, 1, 1}, - new[] {1, 4, 2, 1, 1, 2}, - new[] {1, 4, 2, 2, 1, 1}, - new[] {2, 4, 1, 2, 1, 1}, // 75 - new[] {2, 2, 1, 1, 1, 4}, - new[] {4, 1, 3, 1, 1, 1}, - new[] {2, 4, 1, 1, 1, 2}, - new[] {1, 3, 4, 1, 1, 1}, - new[] {1, 1, 1, 2, 4, 2}, // 80 - new[] {1, 2, 1, 1, 4, 2}, - new[] {1, 2, 1, 2, 4, 1}, - new[] {1, 1, 4, 2, 1, 2}, - new[] {1, 2, 4, 1, 1, 2}, - new[] {1, 2, 4, 2, 1, 1}, // 85 - new[] {4, 1, 1, 2, 1, 2}, - new[] {4, 2, 1, 1, 1, 2}, - new[] {4, 2, 1, 2, 1, 1}, - new[] {2, 1, 2, 1, 4, 1}, - new[] {2, 1, 4, 1, 2, 1}, // 90 - new[] {4, 1, 2, 1, 2, 1}, - new[] {1, 1, 1, 1, 4, 3}, - new[] {1, 1, 1, 3, 4, 1}, - new[] {1, 3, 1, 1, 4, 1}, - new[] {1, 1, 4, 1, 1, 3}, // 95 - new[] {1, 1, 4, 3, 1, 1}, - new[] {4, 1, 1, 1, 1, 3}, - new[] {4, 1, 1, 3, 1, 1}, - new[] {1, 1, 3, 1, 4, 1}, - new[] {1, 1, 4, 1, 3, 1}, // 100 - new[] {3, 1, 1, 1, 4, 1}, - new[] {4, 1, 1, 1, 3, 1}, - new[] {2, 1, 1, 4, 1, 2}, - new[] {2, 1, 1, 2, 1, 4}, - new[] {2, 1, 1, 2, 3, 2}, // 105 - new[] {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; - - 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++) - { - if (row[i] ^ 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(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 - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - private static bool decodeCode(BitArray row, int[] counters, int rowOffset, out int code) - { - code = -1; - if (!recordPattern(row, rowOffset, counters)) - return false; - - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - for (int d = 0; d < CODE_PATTERNS.Length; d++) - { - int[] pattern = CODE_PATTERNS[d]; - int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE); - if (variance < bestVariance) - { - bestVariance = variance; - code = d; - } - } - // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. - return code >= 0; - } - - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - bool convertFNC1 = hints != null && hints.ContainsKey(DecodeHintType.ASSUME_GS1); - - int[] startPatternInfo = findStartPattern(row); - if (startPatternInfo == null) - return null; - int startCode = startPatternInfo[2]; - - var rawCodes = new List(20); - rawCodes.Add((byte)startCode); - - 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: - return null; - } - - bool done = false; - bool isNextShifted = false; - - var result = new 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; - bool upperMode = false; - bool shiftUpperMode = false; - - while (!done) - { - bool unshift = isNextShifted; - isNextShifted = false; - - // Save off last code - lastCode = code; - - // Decode another code from image - if (!decodeCode(row, counters, nextStart, out code)) - return null; - - rawCodes.Add((byte)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: - return null; - } - - switch (codeSet) - { - - case CODE_CODE_A: - if (code < 64) - { - if (shiftUpperMode == upperMode) - { - result.Append((char) (' ' + code)); - } - else - { - result.Append((char) (' ' + code + 128)); - } - shiftUpperMode = false; - } - else if (code < 96) - { - if (shiftUpperMode == upperMode) - { - result.Append((char) (code - 64)); - } - else - { - result.Append((char) (code + 64)); - } - shiftUpperMode = false; - } - 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: - if (convertFNC1) - { - if (result.Length == 0) - { - // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code - // is FNC1 then this is GS1-128. We add the symbology identifier. - result.Append("]C1"); - } - else - { - // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) - result.Append((char) 29); - } - } - break; - case CODE_FNC_2: - case CODE_FNC_3: - // do nothing? - break; - case CODE_FNC_4_A: - if (!upperMode && shiftUpperMode) - { - upperMode = true; - shiftUpperMode = false; - } - else if (upperMode && shiftUpperMode) - { - upperMode = false; - shiftUpperMode = false; - } - else - { - shiftUpperMode = true; - } - 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) - { - if (shiftUpperMode == upperMode) - { - result.Append((char)(' ' + code)); - } - else - { - result.Append((char)(' ' + code + 128)); - } - shiftUpperMode = false; - } - else - { - if (code != CODE_STOP) - { - lastCharacterWasPrintable = false; - } - switch (code) - { - case CODE_FNC_1: - if (convertFNC1) - { - if (result.Length == 0) - { - // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code - // is FNC1 then this is GS1-128. We add the symbology identifier. - result.Append("]C1"); - } - else - { - // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) - result.Append((char)29); - } - } - break; - case CODE_FNC_2: - case CODE_FNC_3: - // do nothing? - break; - case CODE_FNC_4_B: - if (!upperMode && shiftUpperMode) - { - upperMode = true; - shiftUpperMode = false; - } - else if (upperMode && shiftUpperMode) - { - upperMode = false; - shiftUpperMode = false; - } - else - { - shiftUpperMode = true; - } - 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; - } - } - 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: - if (convertFNC1) - { - if (result.Length == 0) - { - // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code - // is FNC1 then this is GS1-128. We add the symbology identifier. - result.Append("]C1"); - } - else - { - // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) - result.Append((char) 29); - } - } - 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; - } - - } - - int lastPatternSize = nextStart - lastStart; - - // 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)) - { - return null; - } - - // Pull out from sum the value of the penultimate check code - checksumTotal -= multiplier * lastCode; - // lastCode is the checksum then: - if (checksumTotal % 103 != lastCode) - { - return null; - } - - // Need to pull out the check digits from string - int resultLength = result.Length; - if (resultLength == 0) - { - // false positive - return null; - } - - // 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 = (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; - float right = lastStart + lastPatternSize / 2.0f; - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(left, rowNumber)); - resultPointCallback(new ResultPoint(right, rowNumber)); - } - - int rawCodesSize = rawCodes.Count; - var rawBytes = new byte[rawCodesSize]; - for (int i = 0; i < rawCodesSize; i++) - { - rawBytes[i] = rawCodes[i]; - } - - return new Result( - result.ToString(), - rawBytes, - new [] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - BarcodeFormat.CODE_128); - } - } -} diff --git a/zxing.core/xx/oned/Code128Writer.cs b/zxing.core/xx/oned/Code128Writer.cs deleted file mode 100644 index 023380d..0000000 --- a/zxing.core/xx/oned/Code128Writer.cs +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a CODE128 code as a . - /// - /// erik.barbara@gmail.com (Erik Barbara) - /// - public sealed class Code128Writer : OneDimensionalCodeWriter - { - private const int CODE_START_B = 104; - private const int CODE_START_C = 105; - private const int CODE_CODE_B = 100; - private const int CODE_CODE_C = 99; - private const int CODE_STOP = 106; - - // Dummy characters used to specify control characters in input - private const char ESCAPE_FNC_1 = '\u00f1'; - private const char ESCAPE_FNC_2 = '\u00f2'; - private const char ESCAPE_FNC_3 = '\u00f3'; - private const char ESCAPE_FNC_4 = '\u00f4'; - - private const int CODE_FNC_1 = 102; // Code A, Code B, Code C - private const int CODE_FNC_2 = 97; // Code A, Code B - private const int CODE_FNC_3 = 96; // Code A, Code B - private const int CODE_FNC_4_B = 100; // Code B - - private bool forceCodesetB; - - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.CODE_128) - { - throw new ArgumentException("Can only encode CODE_128, but got " + format); - } - - forceCodesetB = (hints != null && - hints.ContainsKey(EncodeHintType.CODE128_FORCE_CODESET_B) && - (bool) hints[EncodeHintType.CODE128_FORCE_CODESET_B]); - - return base.encode(contents, format, width, height, hints); - } - - override public bool[] encode(String contents) - { - int length = contents.Length; - // Check length - if (length < 1 || length > 80) - { - throw new ArgumentException( - "Contents length should be between 1 and 80 characters, but got " + length); - } - // Check content - for (int i = 0; i < length; i++) - { - char c = contents[i]; - if (c < ' ' || c > '~') - { - switch (c) - { - case ESCAPE_FNC_1: - case ESCAPE_FNC_2: - case ESCAPE_FNC_3: - case ESCAPE_FNC_4: - break; - default: - throw new ArgumentException("Bad character in input: " + c); - } - } - } - - var patterns = new List(); // temporary storage for patterns - int checkSum = 0; - int checkWeight = 1; - int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C) - int position = 0; // position in contents - - while (position < length) - { - //Select code to use - int requiredDigitCount = codeSet == CODE_CODE_C ? 2 : 4; - int newCodeSet; - if (isDigits(contents, position, requiredDigitCount)) - { - newCodeSet = forceCodesetB ? CODE_CODE_B : CODE_CODE_C; - } - else - { - newCodeSet = CODE_CODE_B; - } - - //Get the pattern index - int patternIndex; - if (newCodeSet == codeSet) - { - // Encode the current character - // First handle escapes - switch (contents[position]) - { - case ESCAPE_FNC_1: - patternIndex = CODE_FNC_1; - break; - case ESCAPE_FNC_2: - patternIndex = CODE_FNC_2; - break; - case ESCAPE_FNC_3: - patternIndex = CODE_FNC_3; - break; - case ESCAPE_FNC_4: - patternIndex = CODE_FNC_4_B; // FIXME if this ever outputs Code A - break; - default: - // Then handle normal characters otherwise - if (codeSet == CODE_CODE_B) - { - patternIndex = contents[position] - ' '; - } - else - { // CODE_CODE_C - patternIndex = Int32.Parse(contents.Substring(position, 2)); - position++; // Also incremented below - } - break; - } - position++; - } - else - { - // Should we change the current code? - // Do we have a code set? - if (codeSet == 0) - { - // No, we don't have a code set - if (newCodeSet == CODE_CODE_B) - { - patternIndex = CODE_START_B; - } - else - { - // CODE_CODE_C - patternIndex = CODE_START_C; - } - } - else - { - // Yes, we have a code set - patternIndex = newCodeSet; - } - codeSet = newCodeSet; - } - - // Get the pattern - patterns.Add(Code128Reader.CODE_PATTERNS[patternIndex]); - - // Compute checksum - checkSum += patternIndex * checkWeight; - if (position != 0) - { - checkWeight++; - } - } - - // Compute and append checksum - checkSum %= 103; - patterns.Add(Code128Reader.CODE_PATTERNS[checkSum]); - - // Append stop code - patterns.Add(Code128Reader.CODE_PATTERNS[CODE_STOP]); - - // Compute code width - int codeWidth = 0; - foreach (int[] pattern in patterns) - { - foreach (int width in pattern) - { - codeWidth += width; - } - } - - // Compute result - var result = new bool[codeWidth]; - int pos = 0; - foreach (int[] pattern in patterns) - { - pos += appendPattern(result, pos, pattern, true); - } - - return result; - } - - private static bool isDigits(String value, int start, int length) - { - int end = start + length; - int last = value.Length; - for (int i = start; i < end && i < last; i++) - { - char c = value[i]; - if (c < '0' || c > '9') - { - if (c != ESCAPE_FNC_1) - { - return false; - } - end++; // ignore FNC_1 - } - } - return end <= last; // end > last if we've run out of string - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/Code39Reader.cs b/zxing.core/xx/oned/Code39Reader.cs deleted file mode 100644 index 8d18f64..0000000 --- a/zxing.core/xx/oned/Code39Reader.cs +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

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

- /// Sean Owen - /// @see Code93Reader - ///
- public sealed class Code39Reader : OneDReader - { - internal static String ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; - private static readonly char[] ALPHABET = ALPHABET_STRING.ToCharArray(); - - /// - /// Returns a string with all possible characters - /// - public static string Alphabet - { - get { return ALPHABET_STRING; } - } - - /// - /// 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 int[] CHARACTER_ENCODINGS = { - 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9 - 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J - 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T - 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-* - 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]; - } - - /// - ///

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 - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - for (var index = 0; index < counters.Length; index++) - counters[index] = 0; - decodeRowResult.Length = 0; - - int[] start = findAsteriskPattern(row, counters); - if (start == null) - return null; - - // Read off white space - int nextStart = row.getNextSet(start[1]); - int end = row.Size; - - char decodedChar; - int lastStart; - do - { - if (!recordPattern(row, nextStart, counters)) - return null; - - int pattern = toNarrowWidePattern(counters); - if (pattern < 0) - { - return null; - } - if (!patternToChar(pattern, out decodedChar)) - return null; - decodeRowResult.Append(decodedChar); - lastStart = nextStart; - foreach (int counter in counters) - { - nextStart += counter; - } - // Read off white space - nextStart = row.getNextSet(nextStart); - } while (decodedChar != '*'); - decodeRowResult.Length = decodeRowResult.Length - 1; // remove asterisk - - // Look for whitespace after pattern: - int lastPatternSize = 0; - foreach (int counter in counters) - { - lastPatternSize += counter; - } - 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) - { - return null; - } - - // overriding constructor value is possible - bool useCode39CheckDigit = usingCheckDigit; - if (hints != null && hints.ContainsKey(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT)) - { - useCode39CheckDigit = (bool) hints[DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT]; - } - - if (useCode39CheckDigit) - { - int max = decodeRowResult.Length - 1; - int total = 0; - for (int i = 0; i < max; i++) - { - total += ALPHABET_STRING.IndexOf(decodeRowResult[i]); - } - if (decodeRowResult[max] != ALPHABET[total % 43]) - { - return null; - } - decodeRowResult.Length = max; - } - - if (decodeRowResult.Length == 0) - { - // false positive - return null; - } - - // overriding constructor value is possible - bool useCode39ExtendedMode = extendedMode; - if (hints != null && hints.ContainsKey(DecodeHintType.USE_CODE_39_EXTENDED_MODE)) - { - useCode39ExtendedMode = (bool)hints[DecodeHintType.USE_CODE_39_EXTENDED_MODE]; - } - - String resultString; - if (useCode39ExtendedMode) - { - resultString = decodeExtended(decodeRowResult.ToString()); - if (resultString == null) - { - if (hints != null && - hints.ContainsKey(DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE) && - Convert.ToBoolean(hints[DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE])) - resultString = decodeRowResult.ToString(); - else - return null; - } - } - else - { - resultString = decodeRowResult.ToString(); - } - - float left = (start[1] + start[0])/2.0f; - float right = lastStart + lastPatternSize / 2.0f; - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(left, rowNumber)); - resultPointCallback(new ResultPoint(right, rowNumber)); - } - - return new Result( - resultString, - null, - new[] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - BarcodeFormat.CODE_39); - } - - 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[i] ^ isWhite) - { - counters[counterPosition]++; - } - 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(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--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - // 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 = Int32.MaxValue; - foreach (var 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) - { - return -1; - } - } - } - return pattern; - } - } while (wideCounters > 3); - return -1; - } - - private static bool patternToChar(int pattern, out char c) - { - for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) - { - if (CHARACTER_ENCODINGS[i] == pattern) - { - c = ALPHABET[i]; - return true; - } - } - c = '*'; - return false; - } - - 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 == '/') - { - if (i + 1 >= encoded.Length) - { - return null; - } - - 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 - { - return null; - } - break; - case '$': - // $A to $Z map to control codes SH to SB - if (next >= 'A' && next <= 'Z') - { - decodedChar = (char)(next - 64); - } - else - { - return null; - } - 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 - { - return null; - } - 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 - { - return null; - } - break; - } - 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/zxing.core/xx/oned/Code39Writer.cs b/zxing.core/xx/oned/Code39Writer.cs deleted file mode 100644 index d0ed277..0000000 --- a/zxing.core/xx/oned/Code39Writer.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a CODE39 code as a . - /// erik.barbara@gmail.com (Erik Barbara) - /// - public sealed class Code39Writer : OneDimensionalCodeWriter - { - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary 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); - } - - /// - /// Encode the contents to byte array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// a {@code boolean[]} of horizontal pixels (false = white, true = black) - /// - /// - /// - public override bool[] 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); - } - for (int i = 0; i < length; i++) - { - int indexInString = Code39Reader.ALPHABET_STRING.IndexOf(contents[i]); - if (indexInString < 0) - throw new ArgumentException("Requested contents contains a not encodable character: '" + contents[i] + "'"); - } - - 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]); - if (indexInString < 0) - { - throw new ArgumentException("Bad contents: " + contents); - } - toIntArray(Code39Reader.CHARACTER_ENCODINGS[indexInString], widths); - foreach (int width in widths) - { - codeWidth += width; - } - } - var 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 byte matrix - for (int i = 0; i < length; 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); - 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 << (8 - i)); - toReturn[i] = temp == 0 ? 1 : 2; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/Code93Reader.cs b/zxing.core/xx/oned/Code93Reader.cs deleted file mode 100644 index d22dd30..0000000 --- a/zxing.core/xx/oned/Code93Reader.cs +++ /dev/null @@ -1,362 +0,0 @@ -/* - * 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. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Decodes Code 93 barcodes.

- /// Sean Owen - /// - ///
- public sealed class Code93Reader : OneDReader - { - // Note that 'abcd' are dummy characters in place of control characters. - private const String ALPHABET_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*"; - 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. - /// - private static readonly int[] CHARACTER_ENCODINGS = { - 0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, // 0-9 - 0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, // A-J - 0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, // K-T - 0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, // U-Z - 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - % - 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-* - }; - private static readonly int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47]; - - private readonly StringBuilder decodeRowResult; - private readonly int[] counters; - - /// - /// Initializes a new instance of the class. - /// - public Code93Reader() - { - decodeRowResult = new StringBuilder(20); - counters = new int[6]; - } - - /// - ///

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 - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - for (var index = 0; index < counters.Length; index++) - counters[index] = 0; - decodeRowResult.Length = 0; - - int[] start = findAsteriskPattern(row); - if (start == null) - return null; - - // Read off white space - int nextStart = row.getNextSet(start[1]); - int end = row.Size; - - char decodedChar; - int lastStart; - do - { - if (!recordPattern(row, nextStart, counters)) - return null; - - int pattern = toPattern(counters); - if (pattern < 0) - { - return null; - } - if (!patternToChar(pattern, out decodedChar)) - return null; - decodeRowResult.Append(decodedChar); - lastStart = nextStart; - foreach (int counter in counters) - { - nextStart += counter; - } - // Read off white space - nextStart = row.getNextSet(nextStart); - } while (decodedChar != '*'); - decodeRowResult.Remove(decodeRowResult.Length - 1, 1); // remove asterisk - - int lastPatternSize = 0; - foreach (int counter in counters) - { - lastPatternSize += counter; - } - - // Should be at least one more black module - if (nextStart == end || !row[nextStart]) - { - return null; - } - - if (decodeRowResult.Length < 2) - { - // false positive -- need at least 2 checksum digits - return null; - } - - if (!checkChecksums(decodeRowResult)) - return null; - // Remove checksum digits - decodeRowResult.Length = decodeRowResult.Length - 2; - - String resultString = decodeExtended(decodeRowResult); - if (resultString == null) - return null; - - float left = (start[1] + start[0])/2.0f; - float right = lastStart + lastPatternSize / 2.0f; - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(left, rowNumber)); - resultPointCallback(new ResultPoint(right, rowNumber)); - } - - return new Result( - resultString, - null, - new[] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - BarcodeFormat.CODE_93); - } - - private int[] findAsteriskPattern(BitArray row) - { - int width = row.Size; - int rowOffset = row.getNextSet(0); - - for (var index = 0; index < counters.Length; index++) - counters[index] = 0; - int counterPosition = 0; - int patternStart = rowOffset; - bool isWhite = false; - int patternLength = counters.Length; - - for (int i = rowOffset; i < width; i++) - { - if (row[i] ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - if (toPattern(counters) == ASTERISK_ENCODING) - { - 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--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - private static int toPattern(int[] counters) - { - int max = counters.Length; - int sum = 0; - foreach (var counter in counters) - { - sum += counter; - } - int pattern = 0; - for (int i = 0; i < max; i++) - { - int scaledShifted = (counters[i] << INTEGER_MATH_SHIFT) * 9 / sum; - int scaledUnshifted = scaledShifted >> INTEGER_MATH_SHIFT; - if ((scaledShifted & 0xFF) > 0x7F) - { - scaledUnshifted++; - } - if (scaledUnshifted < 1 || scaledUnshifted > 4) - { - return -1; - } - if ((i & 0x01) == 0) - { - for (int j = 0; j < scaledUnshifted; j++) - { - pattern = (pattern << 1) | 0x01; - } - } - else - { - pattern <<= scaledUnshifted; - } - } - return pattern; - } - - private static bool patternToChar(int pattern, out char c) - { - for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) - { - if (CHARACTER_ENCODINGS[i] == pattern) - { - c = ALPHABET[i]; - return true; - } - } - c = '*'; - return false; - } - - private static String decodeExtended(StringBuilder encoded) - { - int length = encoded.Length; - StringBuilder decoded = new StringBuilder(length); - for (int i = 0; i < length; i++) - { - char c = encoded[i]; - if (c >= 'a' && c <= 'd') - { - if (i >= length - 1) - { - return null; - } - char next = encoded[i + 1]; - char decodedChar = '\0'; - switch (c) - { - case 'd': - // +A to +Z map to a to z - if (next >= 'A' && next <= 'Z') - { - decodedChar = (char)(next + 32); - } - else - { - return null; - } - break; - case 'a': - // $A to $Z map to control codes SH to SB - if (next >= 'A' && next <= 'Z') - { - decodedChar = (char)(next - 64); - } - else - { - return null; - } - break; - case 'b': - // %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 - { - return null; - } - break; - case 'c': - // /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 - { - return null; - } - break; - } - decoded.Append(decodedChar); - // bump up i again since we read two characters - i++; - } - else - { - decoded.Append(c); - } - } - return decoded.ToString(); - } - - private static bool checkChecksums(StringBuilder result) - { - int length = result.Length; - if (!checkOneChecksum(result, length - 2, 20)) - return false; - if (!checkOneChecksum(result, length - 1, 15)) - return false; - return true; - } - - private static bool checkOneChecksum(StringBuilder result, int checkPosition, int weightMax) - { - int weight = 1; - int total = 0; - for (int i = checkPosition - 1; i >= 0; i--) - { - total += weight * ALPHABET_STRING.IndexOf(result[i]); - if (++weight > weightMax) - { - weight = 1; - } - } - if (result[checkPosition] != ALPHABET[total % 47]) - { - return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/EAN13Reader.cs b/zxing.core/xx/oned/EAN13Reader.cs deleted file mode 100644 index 7550b9c..0000000 --- a/zxing.core/xx/oned/EAN13Reader.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Implements decoding of the EAN-13 format.

- /// - /// dswitkin@google.com (Daniel Switkin) - /// Sean Owen - /// alasdair@google.com (Alasdair Mackintosh) - ///
- public sealed class EAN13Reader : UPCEANReader - { - // 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 int[] FIRST_DIGIT_ENCODINGS = { - 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A - }; - - private readonly int[] decodeMiddleCounters; - - /// - /// Initializes a new instance of the class. - /// - public EAN13Reader() - { - decodeMiddleCounters = new int[4]; - } - - /// - /// 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 or -1 if decoding could not complete successfully - /// - override protected internal 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++) - { - int bestMatch; - if (!decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS, out bestMatch)) - return -1; - resultString.Append((char) ('0' + bestMatch%10)); - foreach (int counter in counters) - { - rowOffset += counter; - } - if (bestMatch >= 10) - { - lgPatternFound |= 1 << (5 - x); - } - } - - if (!determineFirstDigit(resultString, lgPatternFound)) - return -1; - - int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); - if (middleRange == null) - return -1; - rowOffset = middleRange[1]; - - for (int x = 0; x < 6 && rowOffset < end; x++) - { - int bestMatch; - if (!decodeDigit(row, counters, rowOffset, L_PATTERNS, out bestMatch)) - return -1; - resultString.Append((char) ('0' + bestMatch)); - foreach (int counter in counters) - { - rowOffset += counter; - } - } - - return rowOffset; - } - - /// - /// Get the format of this decoder. - /// The 1D format. - /// - override internal 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 - /// -1 if first digit cannot be determined - private static bool determineFirstDigit(StringBuilder resultString, int lgPatternFound) - { - for (int d = 0; d < 10; d++) - { - if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) - { - resultString.Insert(0, new[] { (char)('0' + d) }); - return true; - } - } - return false; - } - } -} diff --git a/zxing.core/xx/oned/EAN13Writer.cs b/zxing.core/xx/oned/EAN13Writer.cs deleted file mode 100644 index 2036a09..0000000 --- a/zxing.core/xx/oned/EAN13Writer.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders an EAN13 code as a . - /// aripollak@gmail.com (Ari Pollak) - /// - public sealed class EAN13Writer : UPCEANWriter - { - private const int CODE_WIDTH = 3 + // start guard - (7 * 6) + // left bars - 5 + // middle guard - (7 * 6) + // right bars - 3; // end guard - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.EAN_13) - { - throw new ArgumentException("Can only encode EAN_13, but got " + format); - } - - return base.encode(contents, format, width, height, hints); - } - - /// - /// Encode the contents to byte array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// a {@code boolean[]} of horizontal pixels (false = white, true = black) - /// - /// - /// - override public bool[] encode(String contents) - { - if (contents.Length < 12 || contents.Length > 13) - { - throw new ArgumentException( - "Requested contents should be 12 (without checksum digit) or 13 digits long, but got " + contents.Length); - } - foreach (var ch in contents) - { - if (!Char.IsDigit(ch)) - throw new ArgumentException("Requested contents should only contain digits, but got '" + ch + "'"); - } - - if (contents.Length == 12) - { - contents = CalculateChecksumDigitModulo10(contents); - } - else - { - if (!UPCEANReader.checkStandardUPCEANChecksum(contents)) - { - throw new ArgumentException("Contents do not pass checksum"); - } - } - - int firstDigit = Int32.Parse(contents.Substring(0, 1)); - int parities = EAN13Reader.FIRST_DIGIT_ENCODINGS[firstDigit]; - var 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 = Int32.Parse(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 = Int32.Parse(contents.Substring(i, 1)); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); - } - appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - return result; - } - } -} diff --git a/zxing.core/xx/oned/EAN8Reader.cs b/zxing.core/xx/oned/EAN8Reader.cs deleted file mode 100644 index e855ace..0000000 --- a/zxing.core/xx/oned/EAN8Reader.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Implements decoding of the EAN-8 format.

- /// Sean Owen - ///
- public sealed class EAN8Reader : UPCEANReader - { - private readonly int[] decodeMiddleCounters; - - /// - /// Initializes a new instance of the class. - /// - public EAN8Reader() - { - decodeMiddleCounters = new int[4]; - } - - /// - /// Decodes the middle. - /// - /// The row. - /// The start range. - /// The result. - /// - override protected internal 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++) - { - int bestMatch; - if (!decodeDigit(row, counters, rowOffset, L_PATTERNS, out bestMatch)) - return -1; - result.Append((char)('0' + bestMatch)); - foreach (int counter in counters) - { - rowOffset += counter; - } - } - - int[] middleRange = findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); - if (middleRange == null) - return -1; - rowOffset = middleRange[1]; - - for (int x = 0; x < 4 && rowOffset < end; x++) - { - int bestMatch; - if (!decodeDigit(row, counters, rowOffset, L_PATTERNS, out bestMatch)) - return -1; - result.Append((char)('0' + bestMatch)); - foreach (int counter in counters) - { - rowOffset += counter; - } - } - - return rowOffset; - } - - /// - /// Get the format of this decoder. - /// The 1D format. - /// - override internal BarcodeFormat BarcodeFormat - { - get { return BarcodeFormat.EAN_8; } - } - } -} diff --git a/zxing.core/xx/oned/EAN8Writer.cs b/zxing.core/xx/oned/EAN8Writer.cs deleted file mode 100644 index 0220f2e..0000000 --- a/zxing.core/xx/oned/EAN8Writer.cs +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders an EAN8 code as a . - /// aripollak@gmail.com (Ari Pollak) - /// - public sealed class EAN8Writer : UPCEANWriter - { - private const int CODE_WIDTH = 3 + // start guard - (7 * 4) + // left bars - 5 + // middle guard - (7 * 4) + // right bars - 3; // end guard - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.EAN_8) - { - throw new ArgumentException("Can only encode EAN_8, but got " - + format); - } - - return base.encode(contents, format, width, height, hints); - } - - /// - /// - /// - /// a byte array of horizontal pixels (false = white, true = black) - /// - override public bool[] encode(String contents) - { - if (contents.Length < 7 || contents.Length > 8) - { - throw new ArgumentException( - "Requested contents should be 7 (without checksum digit) or 8 digits long, but got " + contents.Length); - } - foreach (var ch in contents) - { - if (!Char.IsDigit(ch)) - throw new ArgumentException("Requested contents should only contain digits, but got '" + ch + "'"); - } - if (contents.Length == 7) - contents = CalculateChecksumDigitModulo10(contents); - - var 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 = Int32.Parse(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 = Int32.Parse(contents.Substring(i, 1)); - pos += appendPattern(result, pos, UPCEANReader.L_PATTERNS[digit], true); - } - appendPattern(result, pos, UPCEANReader.START_END_PATTERN, true); - - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/EANManufacturerOrgSupport.cs b/zxing.core/xx/oned/EANManufacturerOrgSupport.cs deleted file mode 100644 index adad206..0000000 --- a/zxing.core/xx/oned/EANManufacturerOrgSupport.cs +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -namespace ZXing.OneD -{ - ///
- internal sealed class EANManufacturerOrgSupport - { - private List ranges = new List(); - private List countryIdentifiers = new List(); - - internal String lookupCountryIdentifier(String productCode) - { - initIfNeeded(); - int prefix = Int32.Parse(productCode.Substring(0, 3)); - int max = ranges.Count; - for (int i = 0; i < max; i++) - { - int[] range = ranges[i]; - int start = range[0]; - if (prefix < start) - { - return null; - } - int end = range.Length == 1 ? start : range[1]; - if (prefix <= end) - { - return countryIdentifiers[i]; - } - } - return null; - } - - private void add(int[] range, String id) - { - ranges.Add(range); - countryIdentifiers.Add(id); - } - - private void initIfNeeded() - { - if (ranges.Count != 0) - { - return; - } - add(new int[] {0, 19}, "US/CA"); - add(new int[] {30, 39}, "US"); - add(new int[] {60, 139}, "US/CA"); - add(new int[] {300, 379}, "FR"); - add(new int[] {380}, "BG"); - add(new int[] {383}, "SI"); - add(new int[] {385}, "HR"); - add(new int[] {387}, "BA"); - add(new int[] {400, 440}, "DE"); - add(new int[] {450, 459}, "JP"); - add(new int[] {460, 469}, "RU"); - add(new int[] {471}, "TW"); - add(new int[] {474}, "EE"); - add(new int[] {475}, "LV"); - add(new int[] {476}, "AZ"); - add(new int[] {477}, "LT"); - add(new int[] {478}, "UZ"); - add(new int[] {479}, "LK"); - add(new int[] {480}, "PH"); - add(new int[] {481}, "BY"); - add(new int[] {482}, "UA"); - add(new int[] {484}, "MD"); - add(new int[] {485}, "AM"); - add(new int[] {486}, "GE"); - add(new int[] {487}, "KZ"); - add(new int[] {489}, "HK"); - add(new int[] {490, 499}, "JP"); - add(new int[] {500, 509}, "GB"); - add(new int[] {520}, "GR"); - add(new int[] {528}, "LB"); - add(new int[] {529}, "CY"); - add(new int[] {531}, "MK"); - add(new int[] {535}, "MT"); - add(new int[] {539}, "IE"); - add(new int[] {540, 549}, "BE/LU"); - add(new int[] {560}, "PT"); - add(new int[] {569}, "IS"); - add(new int[] {570, 579}, "DK"); - add(new int[] {590}, "PL"); - add(new int[] {594}, "RO"); - add(new int[] {599}, "HU"); - add(new int[] {600, 601}, "ZA"); - add(new int[] {603}, "GH"); - add(new int[] {608}, "BH"); - add(new int[] {609}, "MU"); - add(new int[] {611}, "MA"); - add(new int[] {613}, "DZ"); - add(new int[] {616}, "KE"); - add(new int[] {618}, "CI"); - add(new int[] {619}, "TN"); - add(new int[] {621}, "SY"); - add(new int[] {622}, "EG"); - add(new int[] {624}, "LY"); - add(new int[] {625}, "JO"); - add(new int[] {626}, "IR"); - add(new int[] {627}, "KW"); - add(new int[] {628}, "SA"); - add(new int[] {629}, "AE"); - add(new int[] {640, 649}, "FI"); - add(new int[] {690, 695}, "CN"); - add(new int[] {700, 709}, "NO"); - add(new int[] {729}, "IL"); - add(new int[] {730, 739}, "SE"); - add(new int[] {740}, "GT"); - add(new int[] {741}, "SV"); - add(new int[] {742}, "HN"); - add(new int[] {743}, "NI"); - add(new int[] {744}, "CR"); - add(new int[] {745}, "PA"); - add(new int[] {746}, "DO"); - add(new int[] {750}, "MX"); - add(new int[] {754, 755}, "CA"); - add(new int[] {759}, "VE"); - add(new int[] {760, 769}, "CH"); - add(new int[] {770}, "CO"); - add(new int[] {773}, "UY"); - add(new int[] {775}, "PE"); - add(new int[] {777}, "BO"); - add(new int[] {779}, "AR"); - add(new int[] {780}, "CL"); - add(new int[] {784}, "PY"); - add(new int[] {785}, "PE"); - add(new int[] {786}, "EC"); - add(new int[] {789, 790}, "BR"); - add(new int[] {800, 839}, "IT"); - add(new int[] {840, 849}, "ES"); - add(new int[] {850}, "CU"); - add(new int[] {858}, "SK"); - add(new int[] {859}, "CZ"); - add(new int[] {860}, "YU"); - add(new int[] {865}, "MN"); - add(new int[] {867}, "KP"); - add(new int[] {868, 869}, "TR"); - add(new int[] {870, 879}, "NL"); - add(new int[] {880}, "KR"); - add(new int[] {885}, "TH"); - add(new int[] {888}, "SG"); - add(new int[] {890}, "IN"); - add(new int[] {893}, "VN"); - add(new int[] {896}, "PK"); - add(new int[] {899}, "ID"); - add(new int[] {900, 919}, "AT"); - add(new int[] {930, 939}, "AU"); - add(new int[] {940, 949}, "AZ"); - add(new int[] {955}, "MY"); - add(new int[] {958}, "MO"); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/ITFReader.cs b/zxing.core/xx/oned/ITFReader.cs deleted file mode 100644 index 48115c9..0000000 --- a/zxing.core/xx/oned/ITFReader.cs +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

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

- /// - ///

This Reader will scan ITF barcodes of certain lengths only. - /// At the moment it reads length 6, 8, 10, 12, 14, 16, 18, 20, 24, 44 and 48 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.

- /// - /// kevin.osullivan@sita.aero, SITA Lab. - ///
- public sealed class ITFReader : OneDReader - { - 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.78f); - - private const int W = 3; // Pixel width of a wide line - private const int N = 1; // Pixed width of a narrow line - - /// - /// Valid ITF lengths. Anything longer than the largest value is also allowed. - /// - private static readonly int[] DEFAULT_ALLOWED_LENGTHS = { 6, 8, 10, 12, 14 }; - private const int LARGEST_DEFAULT_ALLOWED_LENGTH = 14; - - // 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 int[][] PATTERNS = new int[][] - { - new int[] {N, N, W, W, N}, // 0 - new int[] {W, N, N, N, W}, // 1 - new int[] {N, W, N, N, W}, // 2 - new int[] {W, W, N, N, N}, // 3 - new int[] {N, N, W, N, W}, // 4 - new int[] {W, N, W, N, N}, // 5 - new int[] {N, W, W, N, N}, // 6 - new int[] {N, N, N, W, W}, // 7 - new int[] {W, N, N, W, N}, // 8 - new int[] {N, W, N, W, N} // 9 - }; - - /// - /// 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 - /// - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - // Find out where the Middle section (payload) starts & ends - int[] startRange = decodeStart(row); - if (startRange == null) - return null; - - int[] endRange = decodeEnd(row); - if (endRange == null) - return null; - - StringBuilder result = new StringBuilder(20); - if (!decodeMiddle(row, startRange[1], endRange[0], result)) - return null; - - String resultString = result.ToString(); - - int[] allowedLengths = null; - int maxAllowedLength = LARGEST_DEFAULT_ALLOWED_LENGTH; - if (hints != null && hints.ContainsKey(DecodeHintType.ALLOWED_LENGTHS)) - { - allowedLengths = (int[]) hints[DecodeHintType.ALLOWED_LENGTHS]; - maxAllowedLength = 0; - } - if (allowedLengths == null) - { - allowedLengths = DEFAULT_ALLOWED_LENGTHS; - maxAllowedLength = LARGEST_DEFAULT_ALLOWED_LENGTH; - } - - // To avoid false positives with 2D barcodes (and other patterns), make - // an assumption that the decoded string must be a 'standard' length if it's short - int length = resultString.Length; - bool lengthOK = length > LARGEST_DEFAULT_ALLOWED_LENGTH; - if (!lengthOK) - { - foreach (int allowedLength in allowedLengths) - { - if (length == allowedLength) - { - lengthOK = true; - break; - } - if (allowedLength > maxAllowedLength) - { - maxAllowedLength = allowedLength; - } - } - if (!lengthOK && length > maxAllowedLength) - { - lengthOK = true; - } - if (!lengthOK) - { - return null; - } - } - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(startRange[1], rowNumber)); - resultPointCallback(new ResultPoint(endRange[0], rowNumber)); - } - - return new Result( - resultString, - null, // no natural byte representation for these barcodes - new ResultPoint[] - { - new ResultPoint(startRange[1], rowNumber), - new ResultPoint(endRange[0], rowNumber) - }, - BarcodeFormat.ITF); - } - - /// - /// - /// row of black/white values to search - /// offset of start pattern - /// The payload end. - /// to append decoded chars to - /// - /// false, if decoding could not complete successfully - /// - private static bool 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) - { - // Get 10 runs of black/white. - if (!recordPattern(row, payloadStart, counterDigitPair)) - return false; - - // 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; - if (!decodeDigit(counterBlack, out bestMatch)) - return false; - resultString.Append((char)('0' + bestMatch)); - if (!decodeDigit(counterWhite, out bestMatch)) - return false; - resultString.Append((char)('0' + bestMatch)); - - foreach (int counterDigit in counterDigitPair) - { - payloadStart += counterDigit; - } - } - - return true; - } - - /// - /// 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' - int[] decodeStart(BitArray row) - { - int endStart = skipWhiteSpace(row); - if (endStart < 0) - return null; - - int[] startPattern = findGuardPattern(row, endStart, START_PATTERN); - if (startPattern == null) - return null; - - // 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. - narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; - - if (!validateQuietZone(row, startPattern[0])) - return null; - - 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. - /// false, if the quiet zone cannot be found - private bool validateQuietZone(BitArray row, int startPattern) - { - int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone - - // if there are not so many pixel at all let's try as many as possible - quietCount = quietCount < startPattern ? quietCount : startPattern; - - for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) - { - if (row[i]) - { - break; - } - quietCount--; - } - if (quietCount != 0) - { - // Unable to find the necessary number of quiet zone pixels. - return false; - } - return true; - } - - /// - /// Skip all whitespace until we get to the first black line. - /// - /// row of black/white values to search - /// index of the first black line or -1 if no black lines are found in the row. - private static int skipWhiteSpace(BitArray row) - { - int width = row.Size; - int endStart = row.getNextSet(0); - if (endStart == width) - { - return -1; - } - - 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' or null, if nothing found - int[] decodeEnd(BitArray row) - { - // For convenience, reverse the row and then - // search from 'the start' for the end block - row.reverse(); - int endStart = skipWhiteSpace(row); - if (endStart < 0) - return null; - int[] endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED); - if (endPattern == null) - { - row.reverse(); - return null; - } - - // 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 - if (!validateQuietZone(row, endPattern[0])) - { - row.reverse(); - return null; - } - - // 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; - - row.reverse(); - return endPattern; - } - - /// - /// - /// 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 - 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[x] ^ 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 - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - /// - /// 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 - /// - /// false, if digit cannot be decoded - /// - private static bool decodeDigit(int[] counters, out int bestMatch) - { - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - 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; - } - } - return bestMatch >= 0; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/ITFWriter.cs b/zxing.core/xx/oned/ITFWriter.cs deleted file mode 100644 index f2f816e..0000000 --- a/zxing.core/xx/oned/ITFWriter.cs +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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. - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a ITF code as a . - /// - /// erik.barbara@gmail.com (Erik Barbara) - /// - public sealed class ITFWriter : OneDimensionalCodeWriter - { - private static readonly int[] START_PATTERN = {1, 1, 1, 1}; - private static readonly int[] END_PATTERN = {3, 1, 1}; - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.ITF) - { - throw new ArgumentException("Can only encode ITF, but got " + format); - } - - return base.encode(contents, format, width, height, hints); - } - - /// - /// Encode the contents to bool array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// a {@code bool[]} of horizontal pixels (false = white, true = black) - /// - /// - /// - override public bool[] encode(String contents) - { - int length = contents.Length; - if (length % 2 != 0) - { - throw new ArgumentException("The lenght of the input should be even"); - } - if (length > 80) - { - throw new ArgumentException( - "Requested contents should be less than 80 digits long, but got " + length); - } - for (var i = 0; i < length; i++) - { - if (!Char.IsDigit(contents[i])) - throw new ArgumentException("Requested contents should only contain digits, but got '" + contents[i] + "'"); - } - - var result = new bool[9 + 9 * length]; - int pos = appendPattern(result, 0, START_PATTERN, true); - for (int i = 0; i < length; i += 2) - { - int one = Convert.ToInt32(contents[i].ToString(), 10); - int two = Convert.ToInt32(contents[i + 1].ToString(), 10); - int[] encoding = new int[18]; - for (int j = 0; j < 5; j++) - { - encoding[j << 1] = ITFReader.PATTERNS[one][j]; - encoding[(j << 1) + 1] = ITFReader.PATTERNS[two][j]; - } - pos += appendPattern(result, pos, encoding, true); - } - appendPattern(result, pos, END_PATTERN, true); - - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/MSIReader.cs b/zxing.core/xx/oned/MSIReader.cs deleted file mode 100644 index 8ce6d8d..0000000 --- a/zxing.core/xx/oned/MSIReader.cs +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright 2013 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// Decodes MSI barcodes. - /// - public sealed class MSIReader : OneDReader - { - internal static String ALPHABET_STRING = "0123456789"; - 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 int[] CHARACTER_ENCODINGS = { - 0x924, 0x926, 0x934, 0x936, 0x9A4, 0x9A6, 0x9B4, 0x9B6, 0xD24, 0xD26 // 0-9 - }; - - private const int START_ENCODING = 0x06; - private const int END_ENCODING = 0x09; - - private readonly bool usingCheckDigit; - private readonly StringBuilder decodeRowResult; - private readonly int[] counters; - private int averageCounterWidth; - - /// - /// Creates a reader that assumes all encoded data is data, and does not treat the final - /// character as a check digit. - /// - public MSIReader() - : this(false) - { - } - - /// - /// Creates a reader that can be configured to check the last character as a check digit, - /// - /// if true, treat the last data character as a check digit, not - /// data, and verify that the checksum passes. - public MSIReader(bool usingCheckDigit) - { - this.usingCheckDigit = usingCheckDigit; - decodeRowResult = new StringBuilder(20); - counters = new int[8]; - } - - /// - ///

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 - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - for (var index = 0; index < counters.Length; index++) - counters[index] = 0; - decodeRowResult.Length = 0; - - int[] start = findStartPattern(row, counters); - if (start == null) - return null; - - // Read off white space - int nextStart = row.getNextSet(start[1]); - - char decodedChar; - int lastStart = nextStart; - int pattern; - do - { - if (!recordPattern(row, nextStart, counters, 8)) - { - // not enough bars for a number but perhaps enough for the end pattern - var endPattern = findEndPattern(row, nextStart, counters); - if (endPattern == null) - return null; - lastStart = nextStart; - nextStart = endPattern[1]; - break; - } - pattern = toPattern(counters, 8); - if (!patternToChar(pattern, out decodedChar)) - { - // pattern doesn't result in an encoded number - // but it could be the end pattern followed by some black areas - var endPattern = findEndPattern(row, nextStart, counters); - if (endPattern == null) - return null; - lastStart = nextStart; - nextStart = endPattern[1]; - break; - } - decodeRowResult.Append(decodedChar); - lastStart = nextStart; - foreach (int counter in counters) - { - nextStart += counter; - } - // Read off white space - nextStart = row.getNextSet(nextStart); - } while (decodedChar != '*'); - - // at least 3 digits to prevent false positives within other kind - // of codes like PDF417 - if (decodeRowResult.Length < 3) - { - return null; - } - - var rawBytes = Encoding.UTF8.GetBytes(decodeRowResult.ToString()); - var resultString = decodeRowResult.ToString(); - - if (usingCheckDigit) - { - var resultStringWithoutChecksum = resultString.Substring(0, resultString.Length - 1); - int checkSum = CalculateChecksumLuhn(resultStringWithoutChecksum); - if ((char)(checkSum + 48) != resultString[resultStringWithoutChecksum.Length]) - { - return null; - } - } - - float left = (float)(start[1] + start[0]) / 2.0f; - float right = (float)(nextStart + lastStart) / 2.0f; - - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) - ? null - : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint(left, rowNumber)); - resultPointCallback(new ResultPoint(right, rowNumber)); - } - - return new Result( - resultString, - rawBytes, - new[] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - BarcodeFormat.MSI); - } - - private int[] findStartPattern(BitArray row, int[] counters) - { - const int patternLength = 2; - - int width = row.Size; - int rowOffset = row.getNextSet(0); - - int counterPosition = 0; - int patternStart = rowOffset; - bool isWhite = false; - - counters[0] = 0; - counters[1] = 0; - for (int i = rowOffset; i < width; i++) - { - if (row[i] ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - // narrow and wide areas should be as near as possible to factor 2 - // lets say we will check 1.5 <= factor <= 5 - var factorNarrowToWide = ((float)counters[0]) / ((float)counters[1]); - if (factorNarrowToWide >= 1.5 && factorNarrowToWide <= 5) - { - calculateAverageCounterWidth(counters, patternLength); - if (toPattern(counters, patternLength) == START_ENCODING) - { - // Look for whitespace before start pattern, >= 50% of width of start pattern - if (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--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - private int[] findEndPattern(BitArray row, int rowOffset, int[] counters) - { - const int patternLength = 3; - - int width = row.Size; - - int counterPosition = 0; - int patternStart = rowOffset; - bool isWhite = false; - - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - for (int i = rowOffset; i < width; i++) - { - if (row[i] ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == patternLength - 1) - { - var factorNarrowToWide = ((float)counters[1]) / ((float)counters[0]); - if (factorNarrowToWide >= 1.5 && factorNarrowToWide <= 5) - { - if (toPattern(counters, patternLength) == END_ENCODING) - { - // Look for whitespace after end pattern, >= 50% of width of end pattern - var minEndOfWhite = Math.Min(row.Size - 1, i + ((i - patternStart) >> 1)); - if (row.isRange(i, minEndOfWhite, false)) - { - return new int[] {patternStart, i}; - } - } - } - return null; - } - counterPosition++; - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - private void calculateAverageCounterWidth(int[] counters, int patternLength) - { - // look for the minimum and the maximum width of the bars - // there are only two sizes for MSI barcodes - // all numbers are encoded as a chain of the pattern 100 and 110 - // the complete pattern of one number always starts with 1 or 11 (black bar(s)) - int minCounter = Int32.MaxValue; - int maxCounter = 0; - for (var index = 0; index < patternLength; index++) - { - var counter = counters[index]; - if (counter < minCounter) - { - minCounter = counter; - } - if (counter > maxCounter) - { - maxCounter = counter; - } - } - // calculate the average of the minimum and maximum width - // using some bit shift to get a higher resolution without floating point arithmetic - averageCounterWidth = ((maxCounter << 8) + (minCounter << 8)) / 2; - } - - private int toPattern(int[] counters, int patternLength) - { - // calculating the encoded value from the pattern - int pattern = 0; - int bit = 1; - int doubleBit = 3; - for (var index = 0; index < patternLength; index++) - { - var counter = counters[index]; - if ((counter << 8) < averageCounterWidth) - { - pattern = (pattern << 1) | bit; - } - else - { - pattern = (pattern << 2) | doubleBit; - } - bit = bit ^ 1; - doubleBit = doubleBit ^ 3; - } - - return pattern; - } - - private static bool patternToChar(int pattern, out char c) - { - for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) - { - if (CHARACTER_ENCODINGS[i] == pattern) - { - c = ALPHABET[i]; - return true; - } - } - c = '*'; - return false; - } - - private static readonly int[] doubleAndCrossSum = new [] { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 }; - - private static int CalculateChecksumLuhn(string number) - { - var checksum = 0; - - for (var index = number.Length - 2; index >= 0; index -= 2) - { - var digit = number[index] - 48; - checksum += digit; - } - for (var index = number.Length - 1; index >= 0; index -= 2) - { - var digit = doubleAndCrossSum[number[index] - 48]; - checksum += digit; - } - - return (10 - (checksum % 10)) % 10; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/MSIWriter.cs b/zxing.core/xx/oned/MSIWriter.cs deleted file mode 100644 index e90fb38..0000000 --- a/zxing.core/xx/oned/MSIWriter.cs +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2013 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a MSI code as a . - /// - public sealed class MSIWriter : OneDimensionalCodeWriter - { - private static readonly int[] startWidths = new [] { 2, 1 }; - private static readonly int[] endWidths = new[] { 1, 2, 1 }; - private static readonly int[][] numberWidths = new[] - { - new[] { 1, 2, 1, 2, 1, 2, 1, 2 }, - new[] { 1, 2, 1, 2, 1, 2, 2, 1 }, - new[] { 1, 2, 1, 2, 2, 1, 1, 2 }, - new[] { 1, 2, 1, 2, 2, 1, 2, 1 }, - new[] { 1, 2, 2, 1, 1, 2, 1, 2 }, - new[] { 1, 2, 2, 1, 1, 2, 2, 1 }, - new[] { 1, 2, 2, 1, 2, 1, 1, 2 }, - new[] { 1, 2, 2, 1, 2, 1, 2, 1 }, - new[] { 2, 1, 1, 2, 1, 2, 1, 2 }, - new[] { 2, 1, 1, 2, 1, 2, 2, 1 } - }; - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.MSI) - { - throw new ArgumentException("Can only encode MSI, but got " + format); - } - return base.encode(contents, format, width, height, hints); - } - - /// - /// Encode the contents to byte array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// a {@code boolean[]} of horizontal pixels (false = white, true = black) - /// - /// - /// - override public bool[] encode(String contents) - { - var length = contents.Length; - for (var i = 0; i < length; i++) - { - int indexInString = MSIReader.ALPHABET_STRING.IndexOf(contents[i]); - if (indexInString < 0) - throw new ArgumentException("Requested contents contains a not encodable character: '" + contents[i] + "'"); - } - - var codeWidth = 3 + length*12 + 4; - var result = new bool[codeWidth]; - var pos = appendPattern(result, 0, startWidths, true); - for (var i = 0; i < length; i++) - { - var indexInString = MSIReader.ALPHABET_STRING.IndexOf(contents[i]); - var widths = numberWidths[indexInString]; - pos += appendPattern(result, pos, widths, true); - } - appendPattern(result, pos, endWidths, true); - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/MultiFormatOneDReader.cs b/zxing.core/xx/oned/MultiFormatOneDReader.cs deleted file mode 100644 index 32bc9c0..0000000 --- a/zxing.core/xx/oned/MultiFormatOneDReader.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Collections.Generic; - -using ZXing.Common; -using ZXing.OneD.RSS; -using ZXing.OneD.RSS.Expanded; - -namespace ZXing.OneD -{ - /// - /// dswitkin@google.com (Daniel Switkin) - /// Sean Owen - /// - public sealed class MultiFormatOneDReader : OneDReader - { - private readonly IList readers; - - /// - /// Initializes a new instance of the class. - /// - /// The hints. - public MultiFormatOneDReader(IDictionary hints) - { - var possibleFormats = hints == null || !hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS) ? null : - (IList)hints[DecodeHintType.POSSIBLE_FORMATS]; - readers = new List(); - if (possibleFormats != null) - { - if (possibleFormats.Contains(BarcodeFormat.All_1D) || - 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.MSI)) - { - // MSI needs to be activated explicit - bool useMsiCheckDigit = (hints.ContainsKey(DecodeHintType.ASSUME_MSI_CHECK_DIGIT) - ? (bool)hints[DecodeHintType.ASSUME_MSI_CHECK_DIGIT] - : false); - readers.Add(new MSIReader(useMsiCheckDigit)); - } - if (possibleFormats.Contains(BarcodeFormat.CODE_39) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - bool useCode39CheckDigit = hints.ContainsKey(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) && - (bool) hints[DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT]; - bool useCode39ExtendedMode = hints.ContainsKey(DecodeHintType.USE_CODE_39_EXTENDED_MODE) && - (bool) hints[DecodeHintType.USE_CODE_39_EXTENDED_MODE]; - readers.Add(new Code39Reader(useCode39CheckDigit, useCode39ExtendedMode)); - } - if (possibleFormats.Contains(BarcodeFormat.CODE_93) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new Code93Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.CODE_128) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new Code128Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.ITF) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new ITFReader()); - } - if (possibleFormats.Contains(BarcodeFormat.CODABAR) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new CodaBarReader()); - } - if (possibleFormats.Contains(BarcodeFormat.RSS_14) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new RSS14Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.RSS_EXPANDED) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new RSSExpandedReader()); - } - } - if (readers.Count == 0) - { - bool useCode39CheckDigit = hints != null && hints.ContainsKey(DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) && - (bool) hints[DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT]; - bool useCode39ExtendedMode = hints != null && hints.ContainsKey(DecodeHintType.USE_CODE_39_EXTENDED_MODE) && - (bool) hints[DecodeHintType.USE_CODE_39_EXTENDED_MODE]; - // MSI needs to be activated explicit - - readers.Add(new MultiFormatUPCEANReader(hints)); - readers.Add(new Code39Reader(useCode39CheckDigit, useCode39ExtendedMode)); - readers.Add(new CodaBarReader()); - readers.Add(new Code93Reader()); - readers.Add(new Code128Reader()); - readers.Add(new ITFReader()); - readers.Add(new RSS14Reader()); - readers.Add(new RSSExpandedReader()); - } - } - - /// - ///

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 or null, if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, - BitArray row, - IDictionary hints) - { - foreach (OneDReader reader in readers) - { - var result = reader.decodeRow(rowNumber, row, hints); - if (result != null) - return result; - } - - return null; - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - public override void reset() - { - foreach (Reader reader in readers) - { - reader.reset(); - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/MultiFormatUPCEANReader.cs b/zxing.core/xx/oned/MultiFormatUPCEANReader.cs deleted file mode 100644 index 90beae9..0000000 --- a/zxing.core/xx/oned/MultiFormatUPCEANReader.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

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.

- /// Sean Owen - ///
- public sealed class MultiFormatUPCEANReader : OneDReader - { - private readonly UPCEANReader[] readers; - - /// - /// Initializes a new instance of the class. - /// - /// The hints. - public MultiFormatUPCEANReader(IDictionary hints) - { - var possibleFormats = hints == null || !hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS) ? null : - (IList)hints[DecodeHintType.POSSIBLE_FORMATS]; - var readers = new List(); - if (possibleFormats != null) - { - if (possibleFormats.Contains(BarcodeFormat.EAN_13) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new EAN13Reader()); - } - else if (possibleFormats.Contains(BarcodeFormat.UPC_A) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new UPCAReader()); - } - if (possibleFormats.Contains(BarcodeFormat.EAN_8) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - readers.Add(new EAN8Reader()); - } - if (possibleFormats.Contains(BarcodeFormat.UPC_E) || possibleFormats.Contains(BarcodeFormat.All_1D)) - { - 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()); - } - this.readers = readers.ToArray(); - } - - /// - ///

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 or null if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, - BitArray row, - IDictionary hints) - { - // Compute this location once and reuse it on multiple implementations - int[] startGuardPattern = UPCEANReader.findStartGuardPattern(row); - if (startGuardPattern == null) - return null; - - foreach (UPCEANReader reader in readers) - { - Result result = reader.decodeRow(rowNumber, row, startGuardPattern, hints); - if (result == null) - 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'; - var possibleFormats = - hints == null || !hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS) ? null : (IList)hints[DecodeHintType.POSSIBLE_FORMATS]; - bool canReturnUPCA = possibleFormats == null || possibleFormats.Contains(BarcodeFormat.UPC_A) || possibleFormats.Contains(BarcodeFormat.All_1D); - - if (ean13MayBeUPCA && canReturnUPCA) - { - // Transfer the metdata across - var resultUPCA = new Result(result.Text.Substring(1), - result.RawBytes, - result.ResultPoints, - BarcodeFormat.UPC_A); - resultUPCA.putAllMetadata(result.ResultMetadata); - return resultUPCA; - } - return result; - } - - return null; - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - public override void reset() - { - foreach (Reader reader in readers) - { - reader.reset(); - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/OneDReader.cs b/zxing.core/xx/oned/OneDReader.cs deleted file mode 100644 index 871f056..0000000 --- a/zxing.core/xx/oned/OneDReader.cs +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// Encapsulates functionality and implementation that is common to all families - /// of one-dimensional barcodes. - /// dswitkin@google.com (Daniel Switkin) - /// Sean Owen - /// - public abstract class OneDReader : Reader - { - /// - /// - /// - protected static int INTEGER_MATH_SHIFT = 8; - /// - /// - /// - protected static int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; - - /// - /// Locates and decodes a barcode in some format within an image. - /// - /// image of barcode to decode - /// - /// String which the barcode encodes - /// - public Result decode(BinaryBitmap image) - { - return decode(image, null); - } - - /// - /// 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. - /// Note that we don't try rotation without the try harder flag, even if rotation was supported. - /// - /// 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 - /// - virtual public Result decode(BinaryBitmap image, IDictionary hints) - { - var result = doDecode(image, hints); - if (result == null) - { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - bool tryHarderWithoutRotation = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER_WITHOUT_ROTATION); - if (tryHarder && !tryHarderWithoutRotation && image.RotateSupported) - { - BinaryBitmap rotatedImage = image.rotateCounterClockwise(); - result = doDecode(rotatedImage, hints); - if (result == null) - return null; - // Record that we found it rotated 90 degrees CCW / 270 degrees CW - 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; - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - virtual public 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 - virtual protected 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: - row = image.getBlackRow(rowNumber, row); - if (row == null) - 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 Dictionary(); - foreach (var hint in hints) - { - if (hint.Key != DecodeHintType.NEED_RESULT_POINT_CALLBACK) - newHints.Add(hint.Key, hint.Value); - } - hints = newHints; - } - } - // Look for a barcode - Result result = decodeRow(rowNumber, row, hints); - if (result == null) - continue; - - // 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; - } - } - - return null; - } - - /// - /// 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 - protected static bool recordPattern(BitArray row, - int start, - int[] counters) - { - return recordPattern(row, start, counters, counters.Length); - } - - /// - /// 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 - protected static bool recordPattern(BitArray row, - int start, - int[] counters, - int numCounters) - { - for (int idx = 0; idx < numCounters; idx++) - { - counters[idx] = 0; - } - int end = row.Size; - if (start >= end) - { - return false; - } - bool isWhite = !row[start]; - int counterPosition = 0; - int i = start; - while (i < end) - { - if (row[i] ^ isWhite) - { // that is, exactly one is true - counters[counterPosition]++; - } - else - { - counterPosition++; - if (counterPosition == numCounters) - { - break; - } - else - { - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - i++; - } - // If we read fully the last section of pixels and filled up our counters -- or filled - // the last counter but ran off the side of the image, OK. Otherwise, a problem. - return (counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end)); - } - - /// - /// Records the pattern in reverse. - /// - /// The row. - /// The start. - /// The counters. - /// - protected static bool recordPatternInReverse(BitArray row, int start, int[] counters) - { - // This could be more efficient I guess - int numTransitionsLeft = counters.Length; - bool last = row[start]; - while (start > 0 && numTransitionsLeft >= 0) - { - if (row[--start] != last) - { - numTransitionsLeft--; - last = !last; - } - } - if (numTransitionsLeft >= 0) - { - return false; - } - return 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 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 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 Int32.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 - /// - public abstract Result decodeRow(int rowNumber, BitArray row, IDictionary hints); - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/OneDimensionalCodeWriter.cs b/zxing.core/xx/oned/OneDimensionalCodeWriter.cs deleted file mode 100644 index 062e8dc..0000000 --- a/zxing.core/xx/oned/OneDimensionalCodeWriter.cs +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.Generic; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Encapsulates functionality and implementation that is common to one-dimensional barcodes.

- /// dsbnatut@gmail.com (Kazuki Nishiura) - ///
- public abstract class OneDimensionalCodeWriter : 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) - /// - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) - { - return encode(contents, format, width, height, null); - } - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - public virtual BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (String.IsNullOrEmpty(contents)) - { - throw new ArgumentException("Found empty contents"); - } - - if (width < 0 || height < 0) - { - throw new ArgumentException("Negative size is not allowed. Input: " - + width + 'x' + height); - } - - int sidesMargin = DefaultMargin; - if (hints != null) - { - var sidesMarginInt = hints.ContainsKey(EncodeHintType.MARGIN) ? (int)hints[EncodeHintType.MARGIN] : (int?)null; - if (sidesMarginInt != null) - { - sidesMargin = sidesMarginInt.Value; - } - } - - var code = encode(contents); - return renderResult(code, width, height, sidesMargin); - } - - /// - /// - /// a byte array of horizontal pixels (0 = white, 1 = black) - private static BitMatrix renderResult(bool[] code, int width, int height, int sidesMargin) - { - int inputWidth = code.Length; - // Add quiet zone on both sides. - int fullWidth = inputWidth + sidesMargin; - int outputWidth = Math.Max(width, fullWidth); - int outputHeight = Math.Max(1, height); - - int multiple = outputWidth / fullWidth; - int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; - - BitMatrix output = new BitMatrix(outputWidth, outputHeight); - for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) - { - if (code[inputX]) - { - output.setRegion(outputX, 0, multiple, outputHeight); - } - } - return output; - } - - - /// - /// Appends the given pattern to the target array starting at pos. - /// - /// encode black/white pattern into this array - /// position to start encoding at in target - /// lengths of black/white runs to encode - /// starting color - false for white, true for black - /// the number of elements added to target. - protected static int appendPattern(bool[] target, int pos, int[] pattern, bool startColor) - { - bool color = startColor; - int numAdded = 0; - foreach (int len in pattern) - { - for (int j = 0; j < len; j++) - { - target[pos++] = color; - } - numAdded += len; - color = !color; // flip color after each segment - } - return numAdded; - } - - /// - /// Gets the default margin. - /// - virtual public int DefaultMargin - { - get - { - // CodaBar spec requires a side margin to be more than ten times wider than narrow space. - // This seems like a decent idea for a default for all formats. - return 10; - } - } - - /// - /// Encode the contents to bool array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// - /// barcode contents to encode - /// a bool[] of horizontal pixels (false = white, true = black) - public abstract bool[] encode(String contents); - - /// - /// Calculates the checksum digit modulo10. - /// - /// The contents. - /// - public static String CalculateChecksumDigitModulo10(String contents) - { - var oddsum = 0; - var evensum = 0; - - for (var index = contents.Length - 1; index >= 0; index -= 2) - { - oddsum += (contents[index] - '0'); - } - for (var index = contents.Length - 2; index >= 0; index -= 2) - { - evensum += (contents[index] - '0'); - } - - return contents + ((10 - ((oddsum * 3 + evensum) % 10)) % 10); - } - } -} diff --git a/zxing.core/xx/oned/PlesseyWriter.cs b/zxing.core/xx/oned/PlesseyWriter.cs deleted file mode 100644 index 6a37e65..0000000 --- a/zxing.core/xx/oned/PlesseyWriter.cs +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2013 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a Plessey code as a . - /// - public sealed class PlesseyWriter : OneDimensionalCodeWriter - { - private const String ALPHABET_STRING = "0123456789ABCDEF"; - private static readonly int[] startWidths = new[] { 14, 11, 14, 11, 5, 20, 14, 11 }; - private static readonly int[] terminationWidths = new[] { 25 }; - private static readonly int[] endWidths = new[] { 20, 5, 20, 5, 14, 11, 14, 11 }; - private static readonly int[][] numberWidths = new[] - { - new[] { 5, 20, 5, 20, 5, 20, 5, 20 }, // 0 - new[] { 14, 11, 5, 20, 5, 20, 5, 20 }, // 1 - new[] { 5, 20, 14, 11, 5, 20, 5, 20 }, // 2 - new[] { 14, 11, 14, 11, 5, 20, 5, 20 }, // 3 - new[] { 5, 20, 5, 20, 14, 11, 5, 20 }, // 4 - new[] { 14, 11, 5, 20, 14, 11, 5, 20 }, // 5 - new[] { 5, 20, 14, 11, 14, 11, 5, 20 }, // 6 - new[] { 14, 11, 14, 11, 14, 11, 5, 20 }, // 7 - new[] { 5, 20, 5, 20, 5, 20, 14, 11 }, // 8 - new[] { 14, 11, 5, 20, 5, 20, 14, 11 }, // 9 - new[] { 5, 20, 14, 11, 5, 20, 14, 11 }, // A / 10 - new[] { 14, 11, 14, 11, 5, 20, 14, 11 }, // B / 11 - new[] { 5, 20, 5, 20, 14, 11, 14, 11 }, // C / 12 - new[] { 14, 11, 5, 20, 14, 11, 14, 11 }, // D / 13 - new[] { 5, 20, 14, 11, 14, 11, 14, 11 }, // E / 14 - new[] { 14, 11, 14, 11, 14, 11, 14, 11 }, // F / 15 - }; - private static readonly byte[] crcGrid = new byte[] { 1, 1, 1, 1, 0, 1, 0, 0, 1 }; - private static readonly int[] crc0Widths = new[] {5, 20}; - private static readonly int[] crc1Widths = new[] {14, 11}; - - /// - /// Encode the contents following specified format. - /// {@code width} and {@code height} are required size. This method may return bigger size - /// {@code BitMatrix} when specified size is too small. The user can set both {@code width} and - /// {@code height} to zero to get minimum size barcode. If negative value is set to {@code width} - /// or {@code height}, {@code IllegalArgumentException} is thrown. - /// - /// - /// - /// - /// - /// - /// - public override BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.PLESSEY) - { - throw new ArgumentException("Can only encode Plessey, but got " + format); - } - return base.encode(contents, format, width, height, hints); - } - - /// - /// Encode the contents to byte array expression of one-dimensional barcode. - /// Start code and end code should be included in result, and side margins should not be included. - /// a {@code boolean[]} of horizontal pixels (false = white, true = black) - /// - /// - /// - override public bool[] encode(String contents) - { - var length = contents.Length; - for (var i = 0; i < length; i++) - { - int indexInString = ALPHABET_STRING.IndexOf(contents[i]); - if (indexInString < 0) - throw new ArgumentException("Requested contents contains a not encodable character: '" + contents[i] + "'"); - } - - // quiet zone + start pattern + data + crc + termination bar + end pattern + quiet zone - var codeWidth = 100 + 100 + length * 100 + 25 * 8 + 25 + 100 + 100; - var result = new bool[codeWidth]; - var crcBuffer = new byte[4*length + 8]; - var crcBufferPos = 0; - var pos = 100; - // start pattern - pos += appendPattern(result, pos, startWidths, true); - // data - for (var i = 0; i < length; i++) - { - var indexInString = ALPHABET_STRING.IndexOf(contents[i]); - var widths = numberWidths[indexInString]; - pos += appendPattern(result, pos, widths, true); - // remember the position number for crc calculation - crcBuffer[crcBufferPos++] = (byte)(indexInString & 1); - crcBuffer[crcBufferPos++] = (byte)((indexInString >> 1) & 1); - crcBuffer[crcBufferPos++] = (byte)((indexInString >> 2) & 1); - crcBuffer[crcBufferPos++] = (byte)((indexInString >> 3) & 1); - } - // CRC calculation - for (var i = 0; i < (4 * length); i++) - { - if (crcBuffer[i] != 0) - { - for (var j = 0; j < 9; j++) - { - crcBuffer[i + j] ^= crcGrid[j]; - } - } - } - // append CRC pattern - for (var i = 0; i < 8; i++) - { - switch (crcBuffer[length * 4 + i]) - { - case 0: - pos += appendPattern(result, pos, crc0Widths, true); - break; - case 1: - pos += appendPattern(result, pos, crc1Widths, true); - break; - } - } - // termination bar - pos += appendPattern(result, pos, terminationWidths, true); - // end pattern - appendPattern(result, pos, endWidths, false); - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCAReader.cs b/zxing.core/xx/oned/UPCAReader.cs deleted file mode 100644 index 2eb1e4c..0000000 --- a/zxing.core/xx/oned/UPCAReader.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Implements decoding of the UPC-A format.

- /// dswitkin@google.com (Daniel Switkin) - /// Sean Owen - ///
- public sealed class UPCAReader : UPCEANReader - { - private readonly UPCEANReader ean13Reader = new EAN13Reader(); - - /// - ///

Like decodeRow(int, BitArray, java.util.Map), 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.

- ///
- /// - /// - /// - /// - /// - override public Result decodeRow(int rowNumber, - BitArray row, - int[] startGuardRange, - IDictionary hints) - { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, startGuardRange, hints)); - } - - /// - ///

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 or null, if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - return maybeReturnResult(ean13Reader.decodeRow(rowNumber, row, hints)); - } - - /// - /// Decodes the specified image. - /// - /// The image. - /// The hints. - /// - override public Result decode(BinaryBitmap image, IDictionary hints) - { - return maybeReturnResult(ean13Reader.decode(image, hints)); - } - - /// - /// Get the format of this decoder. - /// The 1D format. - /// - override internal BarcodeFormat BarcodeFormat - { - get { return BarcodeFormat.UPC_A; } - } - - /// - /// 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 or -1 if decoding could not complete successfully - /// - override protected internal int decodeMiddle(BitArray row, int[] startRange, StringBuilder resultString) - { - return ean13Reader.decodeMiddle(row, startRange, resultString); - } - - private static Result maybeReturnResult(Result result) - { - if (result == null) - return null; - - String text = result.Text; - if (text[0] == '0') - { - return new Result(text.Substring(1), null, result.ResultPoints, BarcodeFormat.UPC_A); - } - else - { - return null; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCAWriter.cs b/zxing.core/xx/oned/UPCAWriter.cs deleted file mode 100644 index 3227302..0000000 --- a/zxing.core/xx/oned/UPCAWriter.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -using System; -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// This object renders a UPC-A code as a . - /// qwandor@google.com (Andrew Walbran) - /// - public class UPCAWriter : Writer - { - private readonly EAN13Writer subWriter = new EAN13Writer(); - - /// - /// 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) - /// - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) - { - return encode(contents, format, width, height, null); - } - - /// - /// - /// 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) - /// - public BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.UPC_A) - { - throw new ArgumentException("Can only encode UPC-A, but got " + format); - } - return subWriter.encode(preencode(contents), BarcodeFormat.EAN_13, width, height, hints); - } - - /// - /// Transform a UPC-A code into the equivalent EAN-13 code, and add a check digit if it is not - /// already present. - /// - private static String preencode(String contents) - { - int length = contents.Length; - if (length == 11) - { - // No check digit present, calculate it and add it - int sum = 0; - for (int i = 0; i < 11; ++i) - { - sum += (contents[i] - '0') * (i % 2 == 0 ? 3 : 1); - } - contents += (1000 - sum) % 10; - } - else if (length != 12) - { - throw new ArgumentException( - "Requested contents should be 11 or 12 digits long, but got " + contents.Length); - } - return '0' + contents; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCEANExtension2Support.cs b/zxing.core/xx/oned/UPCEANExtension2Support.cs deleted file mode 100644 index 8ff4ea6..0000000 --- a/zxing.core/xx/oned/UPCEANExtension2Support.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - /// @see UPCEANExtension5Support - /// - sealed class UPCEANExtension2Support - { - private readonly int[] decodeMiddleCounters = new int[4]; - private readonly StringBuilder decodeRowStringBuffer = new StringBuilder(); - - internal Result decodeRow(int rowNumber, BitArray row, int[] extensionStartRange) - { - StringBuilder result = decodeRowStringBuffer; - result.Length = 0; - int end = decodeMiddle(row, extensionStartRange, result); - if (end < 0) - return null; - - String resultString = result.ToString(); - IDictionary extensionData = parseExtensionString(resultString); - - Result extensionResult = - new Result(resultString, - null, - new ResultPoint[] { - new ResultPoint((extensionStartRange[0] + extensionStartRange[1]) / 2.0f, (float) rowNumber), - new ResultPoint((float) end, (float) rowNumber), - }, - BarcodeFormat.UPC_EAN_EXTENSION); - if (extensionData != null) - { - extensionResult.putAllMetadata(extensionData); - } - return extensionResult; - } - - 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 checkParity = 0; - - for (int x = 0; x < 2 && rowOffset < end; x++) - { - int bestMatch; - if (!UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS, out bestMatch)) - return -1; - resultString.Append((char)('0' + bestMatch % 10)); - foreach (int counter in counters) - { - rowOffset += counter; - } - if (bestMatch >= 10) - { - checkParity |= 1 << (1 - x); - } - if (x != 1) - { - // Read off separator if not last - rowOffset = row.getNextSet(rowOffset); - rowOffset = row.getNextUnset(rowOffset); - } - } - - if (resultString.Length != 2) - { - return -1; - } - - if (int.Parse(resultString.ToString()) % 4 != checkParity) - { - return -1; - } - - return rowOffset; - } - - /// - /// Parses the extension string. - /// - /// raw content of extension - /// formatted interpretation of raw content as a {@link Map} mapping - private static IDictionary parseExtensionString(String raw) - { - if (raw.Length != 2) - { - return null; - } - IDictionary result = new Dictionary(); - result[ResultMetadataType.ISSUE_NUMBER] = Convert.ToInt32(raw); - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCEANExtension5Support.cs b/zxing.core/xx/oned/UPCEANExtension5Support.cs deleted file mode 100644 index ba6a6ff..0000000 --- a/zxing.core/xx/oned/UPCEANExtension5Support.cs +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -using System; -using System.Collections.Generic; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /** - * @see UPCEANExtension2Support - */ - sealed class UPCEANExtension5Support - { - - private static readonly int[] CHECK_DIGIT_ENCODINGS = { - 0x18, 0x14, 0x12, 0x11, 0x0C, 0x06, 0x03, 0x0A, 0x09, 0x05 - }; - - private readonly int[] decodeMiddleCounters = new int[4]; - private readonly StringBuilder decodeRowStringBuffer = new StringBuilder(); - - internal Result decodeRow(int rowNumber, BitArray row, int[] extensionStartRange) - { - StringBuilder result = decodeRowStringBuffer; - result.Length = 0; - int end = decodeMiddle(row, extensionStartRange, result); - if (end < 0) - return null; - - String resultString = result.ToString(); - IDictionary extensionData = parseExtensionString(resultString); - - Result extensionResult = - new Result(resultString, - null, - new ResultPoint[] { - new ResultPoint((extensionStartRange[0] + extensionStartRange[1]) / 2.0f, (float) rowNumber), - new ResultPoint((float) end, (float) rowNumber), - }, - BarcodeFormat.UPC_EAN_EXTENSION); - if (extensionData != null) - { - extensionResult.putAllMetadata(extensionData); - } - return extensionResult; - } - - 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 < 5 && rowOffset < end; x++) - { - int bestMatch; - if (!UPCEANReader.decodeDigit(row, counters, rowOffset, UPCEANReader.L_AND_G_PATTERNS, out bestMatch)) - return -1; - resultString.Append((char)('0' + bestMatch % 10)); - foreach (int counter in counters) - { - rowOffset += counter; - } - if (bestMatch >= 10) - { - lgPatternFound |= 1 << (4 - x); - } - if (x != 4) - { - // Read off separator if not last - rowOffset = row.getNextSet(rowOffset); - rowOffset = row.getNextUnset(rowOffset); - } - } - - if (resultString.Length != 5) - { - return -1; - } - - int checkDigit; - if (!determineCheckDigit(lgPatternFound, out checkDigit)) - return -1; - - if (extensionChecksum(resultString.ToString()) != checkDigit) - { - return -1; - } - - return rowOffset; - } - - private static int extensionChecksum(String s) - { - int length = s.Length; - int sum = 0; - for (int i = length - 2; i >= 0; i -= 2) - { - sum += (int)s[i] - (int)'0'; - } - sum *= 3; - for (int i = length - 1; i >= 0; i -= 2) - { - sum += (int)s[i] - (int)'0'; - } - sum *= 3; - return sum % 10; - } - - private static bool determineCheckDigit(int lgPatternFound, out int checkDigit) - { - for (checkDigit = 0; checkDigit < 10; checkDigit++) - { - if (lgPatternFound == CHECK_DIGIT_ENCODINGS[checkDigit]) - { - return true; - } - } - return false; - } - - /// - /// Parses the extension string. - /// - /// raw content of extension - /// formatted interpretation of raw content as a {@link Map} mapping - /// one {@link ResultMetadataType} to appropriate value, or {@code null} if not known - private static IDictionary parseExtensionString(String raw) - { - if (raw.Length != 5) - { - return null; - } - Object value = parseExtension5String(raw); - if (value == null) - { - return null; - } - IDictionary result = new Dictionary(); - result[ResultMetadataType.SUGGESTED_PRICE] = value; - return result; - } - - private static String parseExtension5String(String raw) - { - String currency; - switch (raw[0]) - { - case '0': - currency = "£"; - break; - case '5': - currency = "$"; - break; - case '9': - // Reference: http://www.jollytech.com - if ("90000".Equals(raw)) - { - // No suggested retail price - return null; - } - if ("99991".Equals(raw)) - { - // Complementary - return "0.00"; - } - if ("99990".Equals(raw)) - { - return "Used"; - } - // Otherwise... unknown currency? - currency = ""; - break; - default: - currency = ""; - break; - } - int rawAmount = int.Parse(raw.Substring(1)); - String unitsString = (rawAmount / 100).ToString(); - int hundredths = rawAmount % 100; - String hundredthsString = hundredths < 10 ? "0" + hundredths : hundredths.ToString(); - return currency + unitsString + '.' + hundredthsString; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCEANExtensionSupport.cs b/zxing.core/xx/oned/UPCEANExtensionSupport.cs deleted file mode 100644 index 3992bb1..0000000 --- a/zxing.core/xx/oned/UPCEANExtensionSupport.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using ZXing.Common; - -namespace ZXing.OneD -{ - sealed class UPCEANExtensionSupport - { - private static readonly int[] EXTENSION_START_PATTERN = { 1, 1, 2 }; - - private readonly UPCEANExtension2Support twoSupport = new UPCEANExtension2Support(); - private readonly UPCEANExtension5Support fiveSupport = new UPCEANExtension5Support(); - - internal Result decodeRow(int rowNumber, BitArray row, int rowOffset) - { - int[] extensionStartRange = UPCEANReader.findGuardPattern(row, rowOffset, false, EXTENSION_START_PATTERN); - if (extensionStartRange == null) - return null; - var result = fiveSupport.decodeRow(rowNumber, row, extensionStartRange); - if (result == null) - result = twoSupport.decodeRow(rowNumber, row, extensionStartRange); - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCEANReader.cs b/zxing.core/xx/oned/UPCEANReader.cs deleted file mode 100644 index 24942df..0000000 --- a/zxing.core/xx/oned/UPCEANReader.cs +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

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

- /// dswitkin@google.com (Daniel Switkin) - /// Sean Owen - /// alasdair@google.com (Alasdair Mackintosh) - ///
- public abstract class UPCEANReader : OneDReader - { - - // 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 int[] START_END_PATTERN = { 1, 1, 1, }; - - /// - /// Pattern marking the middle of a UPC/EAN pattern, separating the two halves. - /// - internal static int[] MIDDLE_PATTERN = { 1, 1, 1, 1, 1 }; - - /// - /// "Odd", or "L" patterns used to encode UPC/EAN digits. - /// - internal static int[][] L_PATTERNS = { - new[] {3, 2, 1, 1}, // 0 - new[] {2, 2, 2, 1}, // 1 - new[] {2, 1, 2, 2}, // 2 - new[] {1, 4, 1, 1}, // 3 - new[] {1, 1, 3, 2}, // 4 - new[] {1, 2, 3, 1}, // 5 - new[] {1, 1, 1, 4}, // 6 - new[] {1, 3, 1, 2}, // 7 - new[] {1, 2, 1, 3}, // 8 - new[] {3, 1, 1, 2} // 9 - }; - - /// - /// As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. - /// - internal static 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++) - { - 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; - } - } - - private readonly StringBuilder decodeRowStringBuffer; - private readonly UPCEANExtensionSupport extensionReader; - private readonly EANManufacturerOrgSupport eanManSupport; - - /// - /// Initializes a new instance of the class. - /// - protected UPCEANReader() - { - decodeRowStringBuffer = new StringBuilder(20); - extensionReader = new UPCEANExtensionSupport(); - eanManSupport = new EANManufacturerOrgSupport(); - } - - 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) - { - for (int idx = 0; idx < START_END_PATTERN.Length; idx++) - counters[idx] = 0; - startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, counters); - if (startRange == null) - return null; - 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; - } - - /// - ///

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 or null, if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, BitArray row, IDictionary hints) - { - return decodeRow(rowNumber, row, findStartGuardPattern(row), hints); - } - - /// - ///

Like decodeRow(int, BitArray, java.util.Map), 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.

- ///
- /// row index into the image - /// encoding of the row of the barcode image - /// start/end column where the opening start pattern was found - /// optional hints that influence decoding - /// encapsulating the result of decoding a barcode in the row - virtual public Result decodeRow(int rowNumber, - BitArray row, - int[] startGuardRange, - IDictionary hints) - { - var resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : - (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint( - (startGuardRange[0] + startGuardRange[1]) / 2.0f, rowNumber - )); - } - - var result = decodeRowStringBuffer; - result.Length = 0; - var endStart = decodeMiddle(row, startGuardRange, result); - if (endStart < 0) - return null; - - if (resultPointCallback != null) - { - resultPointCallback(new ResultPoint( - endStart, rowNumber - )); - } - - var endRange = decodeEnd(row, endStart); - if (endRange == null) - return null; - - if (resultPointCallback != null) - { - resultPointCallback(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. - var end = endRange[1]; - var quietEnd = end + (end - endRange[0]); - if (quietEnd >= row.Size || !row.isRange(end, quietEnd, false)) - { - return null; - } - - var resultString = result.ToString(); - // UPC/EAN should never be less than 8 chars anyway - if (resultString.Length < 8) - { - return null; - } - if (!checkChecksum(resultString)) - { - return null; - } - - var left = (startGuardRange[1] + startGuardRange[0]) / 2.0f; - var right = (endRange[1] + endRange[0]) / 2.0f; - var format = BarcodeFormat; - var decodeResult = new Result(resultString, - null, // no natural byte representation for these barcodes - new ResultPoint[] - { - new ResultPoint(left, rowNumber), - new ResultPoint(right, rowNumber) - }, - format); - - var extensionResult = extensionReader.decodeRow(rowNumber, row, endRange[1]); - if (extensionResult != null) - { - decodeResult.putMetadata(ResultMetadataType.UPC_EAN_EXTENSION, extensionResult.Text); - decodeResult.putAllMetadata(extensionResult.ResultMetadata); - decodeResult.addResultPoints(extensionResult.ResultPoints); - int extensionLength = extensionResult.Text.Length; - int[] allowedExtensions = hints != null && hints.ContainsKey(DecodeHintType.ALLOWED_EAN_EXTENSIONS) ? - (int[]) hints[DecodeHintType.ALLOWED_EAN_EXTENSIONS] : null; - if (allowedExtensions != null) - { - bool valid = false; - foreach (int length in allowedExtensions) - { - if (extensionLength == length) - { - valid = true; - break; - } - } - if (!valid) - { - return null; - } - } - } - - 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; - } - - /// - /// - /// string of digits to check - /// see - virtual protected 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 - 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) - { - return false; - } - 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) - { - return false; - } - sum += digit; - } - return sum % 10 == 0; - } - - /// - /// Decodes the end. - /// - /// The row. - /// The end start. - /// - virtual protected int[] decodeEnd(BitArray row, int endStart) - { - return findGuardPattern(row, endStart, false, START_END_PATTERN); - } - - 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 - internal 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[x] ^ 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 - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - /// - /// 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 - internal static bool decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns, out int digit) - { - digit = -1; - - if (!recordPattern(row, rowOffset, counters)) - return false; - - int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept - 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; - digit = i; - } - } - return digit >= 0; - } - - /// - /// 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 or -1 if decoding could not complete successfully - protected internal abstract int decodeMiddle(BitArray row, - int[] startRange, - StringBuilder resultString); - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/UPCEANWriter.cs b/zxing.core/xx/oned/UPCEANWriter.cs deleted file mode 100644 index b56475b..0000000 --- a/zxing.core/xx/oned/UPCEANWriter.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace ZXing.OneD -{ - /// - ///

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

- /// aripollak@gmail.com (Ari Pollak) - /// dsbnatut@gmail.com (Kazuki Nishiura) - ///
- public abstract class UPCEANWriter : OneDimensionalCodeWriter - { - /// - /// Gets the default margin. - /// - 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/zxing.core/xx/oned/UPCEReader.cs b/zxing.core/xx/oned/UPCEReader.cs deleted file mode 100644 index 10d61e5..0000000 --- a/zxing.core/xx/oned/UPCEReader.cs +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Text; - -using ZXing.Common; - -namespace ZXing.OneD -{ - /// - ///

Implements decoding of the UPC-E format.

- ///

Thisis a great reference for - /// UPC-E information.

- /// Sean Owen - ///
- public sealed class UPCEReader : UPCEANReader - { - /// - /// 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 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. - /// - private static readonly int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = { - new[] { 0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25 }, - new[] { 0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A } - }; - - private readonly int[] decodeMiddleCounters; - - /// - /// Initializes a new instance of the class. - /// - public UPCEReader() - { - decodeMiddleCounters = new int[4]; - } - - /// - /// Decodes the middle. - /// - /// The row. - /// The start range. - /// The result. - /// - override internal protected 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++) - { - int bestMatch; - if (!decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS, out bestMatch)) - return -1; - result.Append((char)('0' + bestMatch % 10)); - foreach (int counter in counters) - { - rowOffset += counter; - } - if (bestMatch >= 10) - { - lgPatternFound |= 1 << (5 - x); - } - } - - if (!determineNumSysAndCheckDigit(result, lgPatternFound)) - return -1; - - return rowOffset; - } - - /// - /// Decodes the end. - /// - /// The row. - /// The end start. - /// - override protected int[] decodeEnd(BitArray row, int endStart) - { - return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN); - } - - /// - /// see checkStandardUPCEANChecksum(String) - /// - /// - /// - override protected bool checkChecksum(String s) - { - return base.checkChecksum(convertUPCEtoUPCA(s)); - } - - /// - /// Determines the num sys and check digit. - /// - /// The result string. - /// The lg pattern found. - /// - private static bool 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]) - { - resultString.Insert(0, new[] { (char)('0' + numSys) }); - resultString.Append((char)('0' + d)); - return true; - } - } - } - return false; - } - - /// - /// Get the format of this decoder. - /// The 1D format. - /// - override internal 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) - { - var upceChars = upce.Substring(1, 6); - StringBuilder result = new 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(); - } - } -} diff --git a/zxing.core/xx/oned/rss/AbstractRSSReader.cs b/zxing.core/xx/oned/rss/AbstractRSSReader.cs deleted file mode 100644 index 89ffa71..0000000 --- a/zxing.core/xx/oned/rss/AbstractRSSReader.cs +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; - -namespace ZXing.OneD.RSS -{ - /// - /// - /// - public abstract class AbstractRSSReader : OneDReader - { - private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.2f); - private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.45f); - - private const float MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f; - private const float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f; - - private readonly int[] decodeFinderCounters; - private readonly int[] dataCharacterCounters; - private readonly float[] oddRoundingErrors; - private readonly float[] evenRoundingErrors; - private readonly int[] oddCounts; - private readonly int[] evenCounts; - - /// - /// Initializes a new instance of the class. - /// - protected AbstractRSSReader() - { - decodeFinderCounters = new int[4]; - dataCharacterCounters = new int[8]; - oddRoundingErrors = new float[4]; - evenRoundingErrors = new float[4]; - oddCounts = new int[dataCharacterCounters.Length / 2]; - evenCounts = new int[dataCharacterCounters.Length / 2]; - } - - /// - /// Gets the decode finder counters. - /// - /// - protected int[] getDecodeFinderCounters() - { - return decodeFinderCounters; - } - - /// - /// Gets the data character counters. - /// - /// - protected int[] getDataCharacterCounters() - { - return dataCharacterCounters; - } - - /// - /// Gets the odd rounding errors. - /// - /// - protected float[] getOddRoundingErrors() - { - return oddRoundingErrors; - } - - /// - /// Gets the even rounding errors. - /// - /// - protected float[] getEvenRoundingErrors() - { - return evenRoundingErrors; - } - - /// - /// Gets the odd counts. - /// - /// - protected int[] getOddCounts() - { - return oddCounts; - } - - /// - /// Gets the even counts. - /// - /// - protected int[] getEvenCounts() - { - return evenCounts; - } - - /// - /// Parses the finder value. - /// - /// The counters. - /// The finder patterns. - /// The value. - /// - protected static bool parseFinderValue(int[] counters, - int[][] finderPatterns, - out int value) - { - for (value = 0; value < finderPatterns.Length; value++) - { - if (patternMatchVariance(counters, finderPatterns[value], MAX_INDIVIDUAL_VARIANCE) < - MAX_AVG_VARIANCE) - { - return true; - } - } - return false; - } - - /// - /// Counts the specified array. - /// - /// The array. - /// - protected static int count(int[] array) - { - int count = 0; - foreach (int a in array) - { - count += a; - } - return count; - } - - /// - /// Increments the specified array. - /// - /// The array. - /// The errors. - protected static void increment(int[] array, float[] errors) - { - int index = 0; - float biggestError = errors[0]; - for (int i = 1; i < array.Length; i++) - { - if (errors[i] > biggestError) - { - biggestError = errors[i]; - index = i; - } - } - array[index]++; - } - - /// - /// Decrements the specified array. - /// - /// The array. - /// The errors. - protected static void decrement(int[] array, float[] errors) - { - int index = 0; - float biggestError = errors[0]; - for (int i = 1; i < array.Length; i++) - { - if (errors[i] < biggestError) - { - biggestError = errors[i]; - index = i; - } - } - array[index]--; - } - - /// - /// Determines whether [is finder pattern] [the specified counters]. - /// - /// The counters. - /// - /// true if [is finder pattern] [the specified counters]; otherwise, false. - /// - protected static bool isFinderPattern(int[] counters) - { - int firstTwoSum = counters[0] + counters[1]; - int sum = firstTwoSum + counters[2] + counters[3]; - float ratio = (float)firstTwoSum / (float)sum; - if (ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO) - { - // passes ratio test in spec, but see if the counts are unreasonable - int minCounter = Int32.MaxValue; - int maxCounter = Int32.MinValue; - foreach (int counter in counters) - { - if (counter > maxCounter) - { - maxCounter = counter; - } - if (counter < minCounter) - { - minCounter = counter; - } - } - return maxCounter < 10 * minCounter; - } - return false; - } - } -} diff --git a/zxing.core/xx/oned/rss/DataCharacter.cs b/zxing.core/xx/oned/rss/DataCharacter.cs deleted file mode 100644 index c0601bf..0000000 --- a/zxing.core/xx/oned/rss/DataCharacter.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; - -namespace ZXing.OneD.RSS -{ - /// - /// - /// - public class DataCharacter - { - /// - /// Gets the value. - /// - public int Value { get; private set; } - /// - /// Gets the checksum portion. - /// - public int ChecksumPortion { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The value. - /// The checksum portion. - public DataCharacter(int value, int checksumPortion) - { - Value = value; - ChecksumPortion = checksumPortion; - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - override public String ToString() - { - return Value + "(" + ChecksumPortion + ')'; - } - - /// - /// Determines whether the specified is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - override public bool Equals(Object o) - { - if (!(o is DataCharacter)) - { - return false; - } - DataCharacter that = (DataCharacter)o; - return Value == that.Value && ChecksumPortion == that.ChecksumPortion; - } - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - override public int GetHashCode() - { - return Value ^ ChecksumPortion; - } - } -} diff --git a/zxing.core/xx/oned/rss/FinderPattern.cs b/zxing.core/xx/oned/rss/FinderPattern.cs deleted file mode 100644 index 4e8259c..0000000 --- a/zxing.core/xx/oned/rss/FinderPattern.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; - -namespace ZXing.OneD.RSS -{ - /// - /// - /// - public sealed class FinderPattern - { - /// - /// Gets the value. - /// - public int Value { get; private set; } - /// - /// Gets the start end. - /// - public int[] StartEnd { get; private set; } - /// - /// Gets the result points. - /// - public ResultPoint[] ResultPoints { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The value. - /// The start end. - /// The start. - /// The end. - /// The row number. - public FinderPattern(int value, int[] startEnd, int start, int end, int rowNumber) - { - Value = value; - StartEnd = startEnd; - ResultPoints = new ResultPoint[] - { - new ResultPoint(start, rowNumber), - new ResultPoint(end, rowNumber), - }; - } - - /// - /// Determines whether the specified is equal to this instance. - /// - /// The to compare with this instance. - /// - /// true if the specified is equal to this instance; otherwise, false. - /// - override public bool Equals(Object o) - { - if (!(o is FinderPattern)) - { - return false; - } - FinderPattern that = (FinderPattern)o; - return Value == that.Value; - } - - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - /// - override public int GetHashCode() - { - return Value; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/Pair.cs b/zxing.core/xx/oned/rss/Pair.cs deleted file mode 100644 index c8f79d9..0000000 --- a/zxing.core/xx/oned/rss/Pair.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace ZXing.OneD.RSS -{ - internal sealed class Pair : DataCharacter - { - public FinderPattern FinderPattern { get; private set; } - public int Count { get; private set; } - - internal Pair(int value, int checksumPortion, FinderPattern finderPattern) - : base(value, checksumPortion) - { - FinderPattern = finderPattern; - } - - public void incrementCount() - { - Count++; - } - } -} diff --git a/zxing.core/xx/oned/rss/RSS14Reader.cs b/zxing.core/xx/oned/rss/RSS14Reader.cs deleted file mode 100644 index b72af15..0000000 --- a/zxing.core/xx/oned/rss/RSS14Reader.cs +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS -{ - /// - /// Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006. - /// - public sealed class RSS14Reader : AbstractRSSReader - { - private static readonly int[] OUTSIDE_EVEN_TOTAL_SUBSET = { 1, 10, 34, 70, 126 }; - private static readonly int[] INSIDE_ODD_TOTAL_SUBSET = { 4, 20, 48, 81 }; - private static readonly int[] OUTSIDE_GSUM = { 0, 161, 961, 2015, 2715 }; - private static readonly int[] INSIDE_GSUM = { 0, 336, 1036, 1516 }; - private static readonly int[] OUTSIDE_ODD_WIDEST = { 8, 6, 4, 3, 1 }; - private static readonly int[] INSIDE_ODD_WIDEST = { 2, 4, 6, 8 }; - - private static readonly int[][] FINDER_PATTERNS = { - new[] {3, 8, 2, 1}, - new[] {3, 5, 5, 1}, - new[] {3, 3, 7, 1}, - new[] {3, 1, 9, 1}, - new[] {2, 7, 4, 1}, - new[] {2, 5, 6, 1}, - new[] {2, 3, 8, 1}, - new[] {1, 5, 7, 1}, - new[] {1, 3, 9, 1}, - }; - - private readonly List possibleLeftPairs; - private readonly List possibleRightPairs; - - /// - /// Initializes a new instance of the class. - /// - public RSS14Reader() - { - possibleLeftPairs = new List(); - possibleRightPairs = new List(); - } - - /// - ///

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 or null, if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, - BitArray row, - IDictionary hints) - { - Pair leftPair = decodePair(row, false, rowNumber, hints); - addOrTally(possibleLeftPairs, leftPair); - row.reverse(); - Pair rightPair = decodePair(row, true, rowNumber, hints); - addOrTally(possibleRightPairs, rightPair); - row.reverse(); - int lefSize = possibleLeftPairs.Count; - for (int i = 0; i < lefSize; i++) - { - Pair left = possibleLeftPairs[i]; - if (left.Count > 1) - { - int rightSize = possibleRightPairs.Count; - for (int j = 0; j < rightSize; j++) - { - Pair right = possibleRightPairs[j]; - if (right.Count > 1) - { - if (checkChecksum(left, right)) - { - return constructResult(left, right); - } - } - } - } - } - return null; - } - - private static void addOrTally(IList possiblePairs, Pair pair) - { - if (pair == null) - { - return; - } - bool found = false; - foreach (Pair other in possiblePairs) - { - if (other.Value == pair.Value) - { - other.incrementCount(); - found = true; - break; - } - } - if (!found) - { - possiblePairs.Add(pair); - } - } - - /// - /// Resets this instance. - /// - public override void reset() - { - possibleLeftPairs.Clear(); - possibleRightPairs.Clear(); - } - - private static Result constructResult(Pair leftPair, Pair rightPair) - { - long symbolValue = 4537077L * leftPair.Value + rightPair.Value; - String text = symbolValue.ToString(); - - StringBuilder buffer = new StringBuilder(14); - for (int i = 13 - text.Length; i > 0; i--) - { - buffer.Append('0'); - } - buffer.Append(text); - - int checkDigit = 0; - for (int i = 0; i < 13; i++) - { - int digit = buffer[i] - '0'; - checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; - } - checkDigit = 10 - (checkDigit % 10); - if (checkDigit == 10) - { - checkDigit = 0; - } - buffer.Append(checkDigit); - - ResultPoint[] leftPoints = leftPair.FinderPattern.ResultPoints; - ResultPoint[] rightPoints = rightPair.FinderPattern.ResultPoints; - return new Result( - buffer.ToString(), - null, - new ResultPoint[] { leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1], }, - BarcodeFormat.RSS_14); - } - - private static bool checkChecksum(Pair leftPair, Pair rightPair) - { - //int leftFPValue = leftPair.FinderPattern.Value; - //int rightFPValue = rightPair.FinderPattern.Value; - //if ((leftFPValue == 0 && rightFPValue == 8) || - // (leftFPValue == 8 && rightFPValue == 0)) - //{ - //} - int checkValue = (leftPair.ChecksumPortion + 16 * rightPair.ChecksumPortion) % 79; - int targetCheckValue = - 9 * leftPair.FinderPattern.Value + rightPair.FinderPattern.Value; - if (targetCheckValue > 72) - { - targetCheckValue--; - } - if (targetCheckValue > 8) - { - targetCheckValue--; - } - return checkValue == targetCheckValue; - } - - private Pair decodePair(BitArray row, bool right, int rowNumber, IDictionary hints) - { - int[] startEnd = findFinderPattern(row, 0, right); - if (startEnd == null) - return null; - FinderPattern pattern = parseFoundFinderPattern(row, rowNumber, right, startEnd); - if (pattern == null) - return null; - - ResultPointCallback resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : - (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - - if (resultPointCallback != null) - { - float center = (startEnd[0] + startEnd[1]) / 2.0f; - if (right) - { - // row is actually reversed - center = row.Size - 1 - center; - } - resultPointCallback(new ResultPoint(center, rowNumber)); - } - - DataCharacter outside = decodeDataCharacter(row, pattern, true); - if (outside == null) - return null; - DataCharacter inside = decodeDataCharacter(row, pattern, false); - if (inside == null) - return null; - return new Pair(1597*outside.Value + inside.Value, - outside.ChecksumPortion + 4*inside.ChecksumPortion, - pattern); - } - - private DataCharacter decodeDataCharacter(BitArray row, FinderPattern pattern, bool outsideChar) - { - int[] counters = getDataCharacterCounters(); - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - counters[4] = 0; - counters[5] = 0; - counters[6] = 0; - counters[7] = 0; - - if (outsideChar) - { - recordPatternInReverse(row, pattern.StartEnd[0], counters); - } - else - { - recordPattern(row, pattern.StartEnd[1] + 1, counters); - // reverse it - for (int i = 0, j = counters.Length - 1; i < j; i++, j--) - { - int temp = counters[i]; - counters[i] = counters[j]; - counters[j] = temp; - } - } - - int numModules = outsideChar ? 16 : 15; - float elementWidth = (float)count(counters) / (float)numModules; - - int[] oddCounts = this.getOddCounts(); - int[] evenCounts = this.getEvenCounts(); - float[] oddRoundingErrors = this.getOddRoundingErrors(); - float[] evenRoundingErrors = this.getEvenRoundingErrors(); - - for (int i = 0; i < counters.Length; i++) - { - float value = (float)counters[i] / elementWidth; - int rounded = (int)(value + 0.5f); // Round - if (rounded < 1) - { - rounded = 1; - } - else if (rounded > 8) - { - rounded = 8; - } - int offset = i >> 1; - if ((i & 0x01) == 0) - { - oddCounts[offset] = rounded; - oddRoundingErrors[offset] = value - rounded; - } - else - { - evenCounts[offset] = rounded; - evenRoundingErrors[offset] = value - rounded; - } - } - - if (!adjustOddEvenCounts(outsideChar, numModules)) - return null; - - int oddSum = 0; - int oddChecksumPortion = 0; - for (int i = oddCounts.Length - 1; i >= 0; i--) - { - oddChecksumPortion *= 9; - oddChecksumPortion += oddCounts[i]; - oddSum += oddCounts[i]; - } - int evenChecksumPortion = 0; - int evenSum = 0; - for (int i = evenCounts.Length - 1; i >= 0; i--) - { - evenChecksumPortion *= 9; - evenChecksumPortion += evenCounts[i]; - evenSum += evenCounts[i]; - } - int checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion; - - if (outsideChar) - { - if ((oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4) - { - return null; - } - int group = (12 - oddSum) / 2; - int oddWidest = OUTSIDE_ODD_WIDEST[group]; - int evenWidest = 9 - oddWidest; - int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, false); - int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, true); - int tEven = OUTSIDE_EVEN_TOTAL_SUBSET[group]; - int gSum = OUTSIDE_GSUM[group]; - return new DataCharacter(vOdd * tEven + vEven + gSum, checksumPortion); - } - else - { - if ((evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4) - { - return null; - } - int group = (10 - evenSum) / 2; - int oddWidest = INSIDE_ODD_WIDEST[group]; - int evenWidest = 9 - oddWidest; - int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); - int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); - int tOdd = INSIDE_ODD_TOTAL_SUBSET[group]; - int gSum = INSIDE_GSUM[group]; - return new DataCharacter(vEven * tOdd + vOdd + gSum, checksumPortion); - } - } - - private int[] findFinderPattern(BitArray row, int rowOffset, bool rightFinderPattern) - { - - int[] counters = getDecodeFinderCounters(); - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - - int width = row.Size; - bool isWhite = false; - while (rowOffset < width) - { - isWhite = !row[rowOffset]; - if (rightFinderPattern == isWhite) - { - // Will encounter white first when searching for right finder pattern - break; - } - rowOffset++; - } - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) - { - if (row[x] ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == 3) - { - if (isFinderPattern(counters)) - { - return new int[] { patternStart, x }; - } - patternStart += counters[0] + counters[1]; - counters[0] = counters[2]; - counters[1] = counters[3]; - counters[2] = 0; - counters[3] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return null; - } - - private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, bool right, int[] startEnd) - { - // Actually we found elements 2-5 - bool firstIsBlack = row[startEnd[0]]; - int firstElementStart = startEnd[0] - 1; - // Locate element 1 - while (firstElementStart >= 0 && firstIsBlack ^ row[firstElementStart]) - { - firstElementStart--; - } - firstElementStart++; - int firstCounter = startEnd[0] - firstElementStart; - // Make 'counters' hold 1-4 - int[] counters = getDecodeFinderCounters(); - Array.Copy(counters, 0, counters, 1, counters.Length - 1); - counters[0] = firstCounter; - int value; - if (!parseFinderValue(counters, FINDER_PATTERNS, out value)) - return null; - int start = firstElementStart; - int end = startEnd[1]; - if (right) - { - // row is actually reversed - start = row.Size - 1 - start; - end = row.Size - 1 - end; - } - return new FinderPattern(value, new int[] { firstElementStart, startEnd[1] }, start, end, rowNumber); - } - - private bool adjustOddEvenCounts(bool outsideChar, int numModules) - { - int oddSum = count(getOddCounts()); - int evenSum = count(getEvenCounts()); - int mismatch = oddSum + evenSum - numModules; - bool oddParityBad = (oddSum & 0x01) == (outsideChar ? 1 : 0); - bool evenParityBad = (evenSum & 0x01) == 1; - - bool incrementOdd = false; - bool decrementOdd = false; - bool incrementEven = false; - bool decrementEven = false; - - if (outsideChar) - { - if (oddSum > 12) - { - decrementOdd = true; - } - else if (oddSum < 4) - { - incrementOdd = true; - } - if (evenSum > 12) - { - decrementEven = true; - } - else if (evenSum < 4) - { - incrementEven = true; - } - } - else - { - if (oddSum > 11) - { - decrementOdd = true; - } - else if (oddSum < 5) - { - incrementOdd = true; - } - if (evenSum > 10) - { - decrementEven = true; - } - else if (evenSum < 4) - { - incrementEven = true; - } - } - - /*if (mismatch == 2) { - if (!(oddParityBad && evenParityBad)) { - throw ReaderException.Instance; - } - decrementOdd = true; - decrementEven = true; - } else if (mismatch == -2) { - if (!(oddParityBad && evenParityBad)) { - throw ReaderException.Instance; - } - incrementOdd = true; - incrementEven = true; - } else */ - if (mismatch == 1) - { - if (oddParityBad) - { - if (evenParityBad) - { - return false; - } - decrementOdd = true; - } - else - { - if (!evenParityBad) - { - return false; - } - decrementEven = true; - } - } - else if (mismatch == -1) - { - if (oddParityBad) - { - if (evenParityBad) - { - return false; - } - incrementOdd = true; - } - else - { - if (!evenParityBad) - { - return false; - } - incrementEven = true; - } - } - else if (mismatch == 0) - { - if (oddParityBad) - { - if (!evenParityBad) - { - return false; - } - // Both bad - if (oddSum < evenSum) - { - incrementOdd = true; - decrementEven = true; - } - else - { - decrementOdd = true; - incrementEven = true; - } - } - else - { - if (evenParityBad) - { - return false; - } - // Nothing to do! - } - } - else - { - return false; - } - - if (incrementOdd) - { - if (decrementOdd) - { - return false; - } - increment(getOddCounts(), getOddRoundingErrors()); - } - if (decrementOdd) - { - decrement(getOddCounts(), getOddRoundingErrors()); - } - if (incrementEven) - { - if (decrementEven) - { - return false; - } - increment(getEvenCounts(), getOddRoundingErrors()); - } - if (decrementEven) - { - decrement(getEvenCounts(), getEvenRoundingErrors()); - } - - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/RSSUtils.cs b/zxing.core/xx/oned/rss/RSSUtils.cs deleted file mode 100644 index 37c5d27..0000000 --- a/zxing.core/xx/oned/rss/RSSUtils.cs +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace ZXing.OneD.RSS -{ - /// - /// Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. - /// - public static class RSSUtils - { - /* - /// - /// Gets the RS swidths. - /// - /// The val. - /// The n. - /// The elements. - /// Width of the max. - /// if set to true [no narrow]. - /// - public static int[] getRSSwidths(int val, int n, int elements, int maxWidth, bool noNarrow) - { - int[] widths = new int[elements]; - int bar; - int narrowMask = 0; - for (bar = 0; bar < elements - 1; bar++) - { - narrowMask |= 1 << bar; - int elmWidth = 1; - int subVal; - while (true) - { - subVal = combins(n - elmWidth - 1, elements - bar - 2); - if (noNarrow && (narrowMask == 0) && - (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) - { - subVal -= combins(n - elmWidth - (elements - bar), elements - bar - 2); - } - if (elements - bar - 1 > 1) - { - int lessVal = 0; - for (int mxwElement = n - elmWidth - (elements - bar - 2); - mxwElement > maxWidth; - mxwElement--) - { - lessVal += combins(n - elmWidth - mxwElement - 1, elements - bar - 3); - } - subVal -= lessVal * (elements - 1 - bar); - } - else if (n - elmWidth > maxWidth) - { - subVal--; - } - val -= subVal; - if (val < 0) - { - break; - } - elmWidth++; - narrowMask &= ~(1 << bar); - } - val += subVal; - n -= elmWidth; - widths[bar] = elmWidth; - } - widths[bar] = n; - return widths; - } - */ - - /// - /// Gets the RS svalue. - /// - /// The widths. - /// Width of the max. - /// if set to true [no narrow]. - /// - public static int getRSSvalue(int[] widths, int maxWidth, bool noNarrow) - { - int elements = widths.Length; - int n = 0; - foreach (var width in widths) - { - n += width; - } - int val = 0; - int narrowMask = 0; - for (int bar = 0; bar < elements - 1; bar++) - { - int elmWidth; - for (elmWidth = 1, narrowMask |= 1 << bar; - elmWidth < widths[bar]; - elmWidth++, narrowMask &= ~(1 << bar)) - { - int subVal = combins(n - elmWidth - 1, elements - bar - 2); - if (noNarrow && (narrowMask == 0) && - (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) - { - subVal -= combins(n - elmWidth - (elements - bar), - elements - bar - 2); - } - if (elements - bar - 1 > 1) - { - int lessVal = 0; - for (int mxwElement = n - elmWidth - (elements - bar - 2); - mxwElement > maxWidth; mxwElement--) - { - lessVal += combins(n - elmWidth - mxwElement - 1, - elements - bar - 3); - } - subVal -= lessVal * (elements - 1 - bar); - } - else if (n - elmWidth > maxWidth) - { - subVal--; - } - val += subVal; - } - n -= elmWidth; - } - return val; - } - - private static int combins(int n, int r) - { - int maxDenom; - int minDenom; - if (n - r > r) - { - minDenom = r; - maxDenom = n - r; - } - else - { - minDenom = n - r; - maxDenom = r; - } - int val = 1; - int j = 1; - for (int i = n; i > maxDenom; i--) - { - val *= i; - if (j <= minDenom) - { - val /= j; - j++; - } - } - while (j <= minDenom) - { - val /= j; - j++; - } - return val; - } - /* - internal static int[] elements(int[] eDist, int N, int K) - { - int[] widths = new int[eDist.Length + 2]; - int twoK = K << 1; - widths[0] = 1; - int i; - int minEven = 10; - int barSum = 1; - for (i = 1; i < twoK - 2; i += 2) - { - widths[i] = eDist[i - 1] - widths[i - 1]; - widths[i + 1] = eDist[i] - widths[i]; - barSum += widths[i] + widths[i + 1]; - if (widths[i] < minEven) - { - minEven = widths[i]; - } - } - widths[twoK - 1] = N - barSum; - if (widths[twoK - 1] < minEven) - { - minEven = widths[twoK - 1]; - } - if (minEven > 1) - { - for (i = 0; i < twoK; i += 2) - { - widths[i] += minEven - 1; - widths[i + 1] -= minEven - 1; - } - } - return widths; - } - */ - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/BitArrayBuilder.cs b/zxing.core/xx/oned/rss/expanded/BitArrayBuilder.cs deleted file mode 100644 index 4ef1a46..0000000 --- a/zxing.core/xx/oned/rss/expanded/BitArrayBuilder.cs +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System.Collections.Generic; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - static class BitArrayBuilder - { - internal static BitArray buildBitArray(List pairs) - { - int charNumber = (pairs.Count << 1) - 1; - if (pairs[pairs.Count - 1].RightChar == null) - { - charNumber -= 1; - } - - int size = 12 * charNumber; - - BitArray binary = new BitArray(size); - int accPos = 0; - - ExpandedPair firstPair = pairs[0]; - int firstValue = firstPair.RightChar.Value; - for (int i = 11; i >= 0; --i) - { - if ((firstValue & (1 << i)) != 0) - { - binary[accPos] = true; - } - accPos++; - } - - for (int i = 1; i < pairs.Count; ++i) - { - ExpandedPair currentPair = pairs[i]; - - int leftValue = currentPair.LeftChar.Value; - for (int j = 11; j >= 0; --j) - { - if ((leftValue & (1 << j)) != 0) - { - binary[accPos] = true; - } - accPos++; - } - - if (currentPair.RightChar != null) - { - int rightValue = currentPair.RightChar.Value; - for (int j = 11; j >= 0; --j) - { - if ((rightValue & (1 << j)) != 0) - { - binary[accPos] = true; - } - accPos++; - } - } - } - return binary; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/ExpandedPair.cs b/zxing.core/xx/oned/rss/expanded/ExpandedPair.cs deleted file mode 100644 index 6082230..0000000 --- a/zxing.core/xx/oned/rss/expanded/ExpandedPair.cs +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; - -namespace ZXing.OneD.RSS.Expanded -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - internal sealed class ExpandedPair - { - internal bool MayBeLast { get; private set; } - internal DataCharacter LeftChar { get; private set; } - internal DataCharacter RightChar { get; private set; } - internal FinderPattern FinderPattern { get; private set; } - - internal ExpandedPair(DataCharacter leftChar, - DataCharacter rightChar, - FinderPattern finderPattern, - bool mayBeLast) - { - LeftChar = leftChar; - RightChar = rightChar; - FinderPattern = finderPattern; - MayBeLast = mayBeLast; - } - - public bool MustBeLast - { - get { return RightChar == null; } - } - - override public String ToString() - { - return - "[ " + LeftChar + " , " + RightChar + " : " + - (FinderPattern == null ? "null" : FinderPattern.Value.ToString()) + " ]"; - } - - override public bool Equals(Object o) - { - if (!(o is ExpandedPair)) - { - return false; - } - ExpandedPair that = (ExpandedPair)o; - return - EqualsOrNull(LeftChar, that.LeftChar) && - EqualsOrNull(RightChar, that.RightChar) && - EqualsOrNull(FinderPattern, that.FinderPattern); - } - - private static bool EqualsOrNull(Object o1, Object o2) - { - return o1 == null ? o2 == null : o1.Equals(o2); - } - - override public int GetHashCode() - { - return hashNotNull(LeftChar) ^ hashNotNull(RightChar) ^ hashNotNull(FinderPattern); - } - - private static int hashNotNull(Object o) - { - return o == null ? 0 : o.GetHashCode(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/ExpandedRow.cs b/zxing.core/xx/oned/rss/expanded/ExpandedRow.cs deleted file mode 100644 index 9843af1..0000000 --- a/zxing.core/xx/oned/rss/expanded/ExpandedRow.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -namespace ZXing.OneD.RSS.Expanded -{ - /// - /// One row of an RSS Expanded Stacked symbol, consisting of 1+ expanded pairs. - /// - internal sealed class ExpandedRow - { - internal ExpandedRow(List pairs, int rowNumber, bool wasReversed) - { - Pairs = new List(pairs); - RowNumber = rowNumber; - IsReversed = wasReversed; - } - - internal List Pairs { get; private set; } - - internal int RowNumber { get; private set; } - - /// - /// Did this row of the image have to be reversed (mirrored) to recognize the pairs? - /// - internal bool IsReversed { get; private set; } - - internal bool IsEquivalent(List otherPairs) - { - return Pairs.Equals(otherPairs); - } - - override public String ToString() - { - return "{ " + Pairs + " }"; - } - - /// - /// Two rows are equal if they contain the same pairs in the same order. - /// - override public bool Equals(Object o) - { - if (!(o is ExpandedRow)) - { - return false; - } - ExpandedRow that = (ExpandedRow)o; - return Pairs.Equals(that.Pairs) && IsReversed == that.IsReversed; - } - - override public int GetHashCode() - { - return Pairs.GetHashCode() ^ IsReversed.GetHashCode(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/RSSExpandedReader.cs b/zxing.core/xx/oned/rss/expanded/RSSExpandedReader.cs deleted file mode 100644 index 02507ca..0000000 --- a/zxing.core/xx/oned/rss/expanded/RSSExpandedReader.cs +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; -using ZXing.OneD.RSS.Expanded.Decoders; - -namespace ZXing.OneD.RSS.Expanded -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - public sealed class RSSExpandedReader : AbstractRSSReader - { - private static readonly int[] SYMBOL_WIDEST = { 7, 5, 4, 3, 1 }; - private static readonly int[] EVEN_TOTAL_SUBSET = { 4, 20, 52, 104, 204 }; - private static readonly int[] GSUM = { 0, 348, 1388, 2948, 3988 }; - - private static readonly int[][] FINDER_PATTERNS = { - new[] {1, 8, 4, 1}, // A - new[] {3, 6, 4, 1}, // B - new[] {3, 4, 6, 1}, // C - new[] {3, 2, 8, 1}, // D - new[] {2, 6, 5, 1}, // E - new[] {2, 2, 9, 1} // F - }; - - private static readonly int[][] WEIGHTS = { - new[] {1, 3, 9, 27, 81, 32, 96, 77}, - new[] {20, 60, 180, 118, 143, 7, 21, 63}, - new[] {189, 145, 13, 39, 117, 140, 209, 205}, - new[] {193, 157, 49, 147, 19, 57, 171, 91}, - new[] {62, 186, 136, 197, 169, 85, 44, 132}, - new[] {185, 133, 188, 142, 4, 12, 36, 108}, - new[] {113, 128, 173, 97, 80, 29, 87, 50}, - new[] {150, 28, 84, 41, 123, 158, 52, 156}, - new[] {46, 138, 203, 187, 139, 206, 196, 166}, - new[] {76, 17, 51, 153, 37, 111, 122, 155}, - new[] {43, 129, 176, 106, 107, 110, 119, 146}, - new[] {16, 48, 144, 10, 30, 90, 59, 177}, - new[] {109, 116, 137, 200, 178, 112, 125, 164}, - new[] {70, 210, 208, 202, 184, 130, 179, 115}, - new[] {134, 191, 151, 31, 93, 68, 204, 190}, - new[] {148, 22, 66, 198, 172, 94, 71, 2}, - new[] {6, 18, 54, 162, 64, 192, 154, 40}, - new[] {120, 149, 25, 75, 14, 42, 126, 167}, - new[] {79, 26, 78, 23, 69, 207, 199, 175}, - new[] {103, 98, 83, 38, 114, 131, 182, 124}, - new[] {161, 61, 183, 127, 170, 88, 53, 159}, - new[] {55, 165, 73, 8, 24, 72, 5, 15}, - new[] {45, 135, 194, 160, 58, 174, 100, 89} - }; - private const int FINDER_PAT_A = 0; - private const int FINDER_PAT_B = 1; - private const int FINDER_PAT_C = 2; - private const int FINDER_PAT_D = 3; - private const int FINDER_PAT_E = 4; - private const int FINDER_PAT_F = 5; - - private static readonly int[][] FINDER_PATTERN_SEQUENCES = { - new[] { FINDER_PAT_A, FINDER_PAT_A }, - new[] { FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B }, - new[] { FINDER_PAT_A, FINDER_PAT_C, FINDER_PAT_B, FINDER_PAT_D }, - new[] { FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_C }, - new[] { FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_F }, - new[] { FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F }, - new[] { FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D }, - new[] { FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E }, - new[] { FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F }, - new[] { FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F }, - }; - - // private static readonly int LONGEST_SEQUENCE_SIZE = FINDER_PATTERN_SEQUENCES[FINDER_PATTERN_SEQUENCES.Length - 1].Length; - - private const int MAX_PAIRS = 11; - - private readonly List pairs = new List(MAX_PAIRS); - private readonly List rows = new List(); - private readonly int[] startEnd = new int[2]; - //private readonly int[] currentSequence = new int[LONGEST_SEQUENCE_SIZE]; - private bool startFromEven = false; - - internal List Pairs { get { return pairs; } } - - /// - ///

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 or null, if an error occurs or barcode cannot be found - /// - override public Result decodeRow(int rowNumber, - BitArray row, - IDictionary hints) - { - // Rows can start with even pattern in case in prev rows there where odd number of patters. - // So lets try twice - pairs.Clear(); - startFromEven = false; - if (decodeRow2pairs(rowNumber, row)) - return constructResult(pairs); - - pairs.Clear(); - startFromEven = true; - if (decodeRow2pairs(rowNumber, row)) - return constructResult(pairs); - return null; - } - - /// - /// Resets this instance. - /// - public override void reset() - { - pairs.Clear(); - rows.Clear(); - } - - // Not private for testing - internal bool decodeRow2pairs(int rowNumber, BitArray row) - { - while (true) - { - ExpandedPair nextPair = retrieveNextPair(row, this.pairs, rowNumber); - if (nextPair == null) - break; - pairs.Add(nextPair); - //System.out.println(this.pairs.size()+" pairs found so far on row "+rowNumber+": "+this.pairs); - // exit this loop when retrieveNextPair() fails and throws - } - if (pairs.Count == 0) - { - return false; - } - - // TODO: verify sequence of finder patterns as in checkPairSequence() - if (checkChecksum()) - { - return true; - } - - bool tryStackedDecode = rows.Count != 0; - bool wasReversed = false; // TODO: deal with reversed rows - storeRow(rowNumber, wasReversed); - if (tryStackedDecode) - { - // When the image is 180-rotated, then rows are sorted in wrong dirrection. - // Try twice with both the directions. - List ps = checkRows(false); - if (ps != null) - { - return true; - } - ps = checkRows(true); - if (ps != null) - { - return true; - } - } - - return false; - } - - private List checkRows(bool reverse) - { - // Limit number of rows we are checking - // We use recursive algorithm with pure complexity and don't want it to take forever - // Stacked barcode can have up to 11 rows, so 25 seems resonable enough - if (rows.Count > 25) - { - rows.Clear(); // We will never have a chance to get result, so clear it - return null; - } - - pairs.Clear(); - if (reverse) - { - rows.Reverse(); - } - - List ps = checkRows(new List(), 0); - - if (reverse) - { - rows.Reverse(); - } - - return ps; - } - - // Try to construct a valid rows sequence - // Recursion is used to implement backtracking - private List checkRows(List collectedRows, int currentRow) - { - for (int i = currentRow; i < rows.Count; i++) - { - ExpandedRow row = rows[i]; - pairs.Clear(); - int size = collectedRows.Count; - for (int j = 0; j < size; j++) - { - pairs.AddRange(collectedRows[j].Pairs); - } - pairs.AddRange(row.Pairs); - - if (!isValidSequence(pairs)) - { - continue; - } - - if (checkChecksum()) - { - return this.pairs; - } - - List rs = new List(); - rs.AddRange(collectedRows); - rs.Add(row); - // Recursion: try to add more rows - var result = checkRows(rs, i + 1); - if (result == null) - // We failed, try the next candidate - continue; - return result; - } - - return null; - } - - // Whether the pairs form a valid find pattern seqience, - // either complete or a prefix - private static bool isValidSequence(List pairs) - { - foreach (int[] sequence in FINDER_PATTERN_SEQUENCES) - { - if (pairs.Count > sequence.Length) - { - continue; - } - - bool stop = true; - for (int j = 0; j < pairs.Count; j++) - { - if (pairs[j].FinderPattern.Value != sequence[j]) - { - stop = false; - break; - } - } - - if (stop) - { - return true; - } - } - - return false; - } - - private void storeRow(int rowNumber, bool wasReversed) - { - // Discard if duplicate above or below; otherwise insert in order by row number. - int insertPos = 0; - bool prevIsSame = false; - bool nextIsSame = false; - while (insertPos < rows.Count) - { - ExpandedRow erow = rows[insertPos]; - if (erow.RowNumber > rowNumber) - { - nextIsSame = erow.IsEquivalent(pairs); - break; - } - prevIsSame = erow.IsEquivalent(pairs); - insertPos++; - } - if (nextIsSame || prevIsSame) - { - return; - } - - // When the row was partially decoded (e.g. 2 pairs found instead of 3), - // it will prevent us from detecting the barcode. - // Try to merge partial rows - - // Check whether the row is part of an allready detected row - if (isPartialRow(pairs, rows)) - { - return; - } - - rows.Insert(insertPos, new ExpandedRow(pairs, rowNumber, wasReversed)); - - removePartialRows(pairs, rows); - } - - // Remove all the rows that contains only specified pairs - private static void removePartialRows(List pairs, List rows) - { - for (var index = 0; index < rows.Count; index++) - { - var r = rows[index]; - if (r.Pairs.Count == pairs.Count) - { - continue; - } - bool allFound = true; - foreach (ExpandedPair p in r.Pairs) - { - bool found = false; - foreach (ExpandedPair pp in pairs) - { - if (p.Equals(pp)) - { - found = true; - break; - } - } - if (!found) - { - allFound = false; - break; - } - } - if (allFound) - { - // 'pairs' contains all the pairs from the row 'r' - rows.RemoveAt(index); - } - } - } - - // Returns true when one of the rows already contains all the pairs - private static bool isPartialRow(IEnumerable pairs, IEnumerable rows) - { - foreach (ExpandedRow r in rows) - { - var allFound = true; - foreach (ExpandedPair p in pairs) - { - bool found = false; - foreach (ExpandedPair pp in r.Pairs) - { - if (p.Equals(pp)) - { - found = true; - break; - } - } - if (!found) - { - allFound = false; - break; - } - } - if (allFound) - { - // the row 'r' contain all the pairs from 'pairs' - return true; - } - } - return false; - } - - // Only used for unit testing - internal List Rows - { - get { return this.rows; } - } - - internal static Result constructResult(List pairs) - { - BitArray binary = BitArrayBuilder.buildBitArray(pairs); - - AbstractExpandedDecoder decoder = AbstractExpandedDecoder.createDecoder(binary); - String resultingString = decoder.parseInformation(); - if (resultingString == null) - return null; - - ResultPoint[] firstPoints = pairs[0].FinderPattern.ResultPoints; - ResultPoint[] lastPoints = pairs[pairs.Count - 1].FinderPattern.ResultPoints; - - return new Result( - resultingString, - null, - new ResultPoint[] { firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1] }, - BarcodeFormat.RSS_EXPANDED - ); - } - - private bool checkChecksum() - { - ExpandedPair firstPair = pairs[0]; - DataCharacter checkCharacter = firstPair.LeftChar; - DataCharacter firstCharacter = firstPair.RightChar; - - if (firstCharacter == null) - { - return false; - } - - int checksum = firstCharacter.ChecksumPortion; - int s = 2; - - for (int i = 1; i < pairs.Count; ++i) - { - ExpandedPair currentPair = pairs[i]; - checksum += currentPair.LeftChar.ChecksumPortion; - s++; - DataCharacter currentRightChar = currentPair.RightChar; - if (currentRightChar != null) - { - checksum += currentRightChar.ChecksumPortion; - s++; - } - } - - checksum %= 211; - - int checkCharacterValue = 211 * (s - 4) + checksum; - - return checkCharacterValue == checkCharacter.Value; - } - - private static int getNextSecondBar(BitArray row, int initialPos) - { - int currentPos; - if (row[initialPos]) - { - currentPos = row.getNextUnset(initialPos); - currentPos = row.getNextSet(currentPos); - } - else - { - currentPos = row.getNextSet(initialPos); - currentPos = row.getNextUnset(currentPos); - } - return currentPos; - } - - // not private for testing - internal ExpandedPair retrieveNextPair(BitArray row, List previousPairs, int rowNumber) - { - bool isOddPattern = previousPairs.Count % 2 == 0; - if (startFromEven) - { - isOddPattern = !isOddPattern; - } - - FinderPattern pattern; - - bool keepFinding = true; - int forcedOffset = -1; - do - { - if (!findNextPair(row, previousPairs, forcedOffset)) - return null; - pattern = parseFoundFinderPattern(row, rowNumber, isOddPattern); - if (pattern == null) - { - forcedOffset = getNextSecondBar(row, startEnd[0]); - } - else - { - keepFinding = false; - } - } while (keepFinding); - - // When stacked symbol is split over multiple rows, there's no way to guess if this pair can be last or not. - // bool mayBeLast; - // if (!checkPairSequence(previousPairs, pattern, out mayBeLast)) - // return null; - - DataCharacter leftChar = decodeDataCharacter(row, pattern, isOddPattern, true); - if (leftChar == null) - return null; - - if (previousPairs.Count != 0 && - previousPairs[previousPairs.Count - 1].MustBeLast) - { - return null; - } - - DataCharacter rightChar = decodeDataCharacter(row, pattern, isOddPattern, false); - - return new ExpandedPair(leftChar, rightChar, pattern, true); - } - - private bool findNextPair(BitArray row, List previousPairs, int forcedOffset) - { - int[] counters = getDecodeFinderCounters(); - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - - int width = row.Size; - - int rowOffset; - if (forcedOffset >= 0) - { - rowOffset = forcedOffset; - } - else if (previousPairs.Count == 0) - { - rowOffset = 0; - } - else - { - ExpandedPair lastPair = previousPairs[previousPairs.Count - 1]; - rowOffset = lastPair.FinderPattern.StartEnd[1]; - } - bool searchingEvenPair = previousPairs.Count % 2 != 0; - if (startFromEven) - { - searchingEvenPair = !searchingEvenPair; - } - - bool isWhite = false; - while (rowOffset < width) - { - isWhite = !row[rowOffset]; - if (!isWhite) - { - break; - } - rowOffset++; - } - - int counterPosition = 0; - int patternStart = rowOffset; - for (int x = rowOffset; x < width; x++) - { - if (row[x] ^ isWhite) - { - counters[counterPosition]++; - } - else - { - if (counterPosition == 3) - { - if (searchingEvenPair) - { - reverseCounters(counters); - } - - if (isFinderPattern(counters)) - { - startEnd[0] = patternStart; - startEnd[1] = x; - return true; - } - - if (searchingEvenPair) - { - reverseCounters(counters); - } - - patternStart += counters[0] + counters[1]; - counters[0] = counters[2]; - counters[1] = counters[3]; - counters[2] = 0; - counters[3] = 0; - counterPosition--; - } - else - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - return false; - } - - private static void reverseCounters(int[] counters) - { - int length = counters.Length; - for (int i = 0; i < length / 2; ++i) - { - int tmp = counters[i]; - counters[i] = counters[length - i - 1]; - counters[length - i - 1] = tmp; - } - } - - private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, bool oddPattern) - { - // Actually we found elements 2-5. - int firstCounter; - int start; - int end; - - if (oddPattern) - { - // If pattern number is odd, we need to locate element 1 *before* the current block. - - int firstElementStart = startEnd[0] - 1; - // Locate element 1 - while (firstElementStart >= 0 && !row[firstElementStart]) - { - firstElementStart--; - } - - firstElementStart++; - firstCounter = startEnd[0] - firstElementStart; - start = firstElementStart; - end = startEnd[1]; - - } - else - { - // If pattern number is even, the pattern is reversed, so we need to locate element 1 *after* the current block. - start = startEnd[0]; - end = row.getNextUnset(startEnd[1] + 1); - firstCounter = end - startEnd[1]; - } - - // Make 'counters' hold 1-4 - int[] counters = getDecodeFinderCounters(); - Array.Copy(counters, 0, counters, 1, counters.Length - 1); - - counters[0] = firstCounter; - int value; - if (!parseFinderValue(counters, FINDER_PATTERNS, out value)) - return null; - - return new FinderPattern(value, new int[] { start, end }, start, end, rowNumber); - } - - internal DataCharacter decodeDataCharacter(BitArray row, - FinderPattern pattern, - bool isOddPattern, - bool leftChar) - { - int[] counters = getDataCharacterCounters(); - counters[0] = 0; - counters[1] = 0; - counters[2] = 0; - counters[3] = 0; - counters[4] = 0; - counters[5] = 0; - counters[6] = 0; - counters[7] = 0; - - if (leftChar) - { - if (!recordPatternInReverse(row, pattern.StartEnd[0], counters)) - return null; - } - else - { - if (!recordPattern(row, pattern.StartEnd[1], counters)) - return null; - // reverse it - for (int i = 0, j = counters.Length - 1; i < j; i++, j--) - { - int temp = counters[i]; - counters[i] = counters[j]; - counters[j] = temp; - } - }//counters[] has the pixels of the module - - const int numModules = 17; //left and right data characters have all the same length - float elementWidth = (float)count(counters) / (float)numModules; - - // Sanity check: element width for pattern and the character should match - float expectedElementWidth = (pattern.StartEnd[1] - pattern.StartEnd[0]) / 15.0f; - if (Math.Abs(elementWidth - expectedElementWidth) / expectedElementWidth > 0.3f) - { - return null; - } - - int[] oddCounts = getOddCounts(); - int[] evenCounts = getEvenCounts(); - float[] oddRoundingErrors = getOddRoundingErrors(); - float[] evenRoundingErrors = getEvenRoundingErrors(); - - for (int i = 0; i < counters.Length; i++) - { - float divided = 1.0f * counters[i] / elementWidth; - int rounded = (int)(divided + 0.5f); // Round - if (rounded < 1) - { - if (divided < 0.3f) - { - return null; - } - rounded = 1; - } - else if (rounded > 8) - { - if (divided > 8.7f) - { - return null; - } - rounded = 8; - } - int offset = i >> 1; - if ((i & 0x01) == 0) - { - oddCounts[offset] = rounded; - oddRoundingErrors[offset] = divided - rounded; - } - else - { - evenCounts[offset] = rounded; - evenRoundingErrors[offset] = divided - rounded; - } - } - - if (!adjustOddEvenCounts(numModules)) - return null; - - int weightRowNumber = 4 * pattern.Value + (isOddPattern ? 0 : 2) + (leftChar ? 0 : 1) - 1; - - int oddSum = 0; - int oddChecksumPortion = 0; - for (int i = oddCounts.Length - 1; i >= 0; i--) - { - if (isNotA1left(pattern, isOddPattern, leftChar)) - { - int weight = WEIGHTS[weightRowNumber][2 * i]; - oddChecksumPortion += oddCounts[i] * weight; - } - oddSum += oddCounts[i]; - } - int evenChecksumPortion = 0; - //int evenSum = 0; - for (int i = evenCounts.Length - 1; i >= 0; i--) - { - if (isNotA1left(pattern, isOddPattern, leftChar)) - { - int weight = WEIGHTS[weightRowNumber][2 * i + 1]; - evenChecksumPortion += evenCounts[i] * weight; - } - //evenSum += evenCounts[i]; - } - int checksumPortion = oddChecksumPortion + evenChecksumPortion; - - if ((oddSum & 0x01) != 0 || oddSum > 13 || oddSum < 4) - { - return null; - } - - int group = (13 - oddSum) / 2; - int oddWidest = SYMBOL_WIDEST[group]; - int evenWidest = 9 - oddWidest; - int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); - int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); - int tEven = EVEN_TOTAL_SUBSET[group]; - int gSum = GSUM[group]; - int value = vOdd * tEven + vEven + gSum; - - return new DataCharacter(value, checksumPortion); - } - - private static bool isNotA1left(FinderPattern pattern, bool isOddPattern, bool leftChar) - { - // A1: pattern.getValue is 0 (A), and it's an oddPattern, and it is a left char - return !(pattern.Value == 0 && isOddPattern && leftChar); - } - - private bool adjustOddEvenCounts(int numModules) - { - int oddSum = count(getOddCounts()); - int evenSum = count(getEvenCounts()); - int mismatch = oddSum + evenSum - numModules; - bool oddParityBad = (oddSum & 0x01) == 1; - bool evenParityBad = (evenSum & 0x01) == 0; - - bool incrementOdd = false; - bool decrementOdd = false; - - if (oddSum > 13) - { - decrementOdd = true; - } - else if (oddSum < 4) - { - incrementOdd = true; - } - bool incrementEven = false; - bool decrementEven = false; - if (evenSum > 13) - { - decrementEven = true; - } - else if (evenSum < 4) - { - incrementEven = true; - } - - if (mismatch == 1) - { - if (oddParityBad) - { - if (evenParityBad) - { - return false; - } - decrementOdd = true; - } - else - { - if (!evenParityBad) - { - return false; - } - decrementEven = true; - } - } - else if (mismatch == -1) - { - if (oddParityBad) - { - if (evenParityBad) - { - return false; - } - incrementOdd = true; - } - else - { - if (!evenParityBad) - { - return false; - } - incrementEven = true; - } - } - else if (mismatch == 0) - { - if (oddParityBad) - { - if (!evenParityBad) - { - return false; - } - // Both bad - if (oddSum < evenSum) - { - incrementOdd = true; - decrementEven = true; - } - else - { - decrementOdd = true; - incrementEven = true; - } - } - else - { - if (evenParityBad) - { - return false; - } - // Nothing to do! - } - } - else - { - return false; - } - - if (incrementOdd) - { - if (decrementOdd) - { - return false; - } - increment(getOddCounts(), getOddRoundingErrors()); - } - if (decrementOdd) - { - decrement(getOddCounts(), getOddRoundingErrors()); - } - if (incrementEven) - { - if (decrementEven) - { - return false; - } - increment(getEvenCounts(), getOddRoundingErrors()); - } - if (decrementEven) - { - decrement(getEvenCounts(), getEvenRoundingErrors()); - } - - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI013103decoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI013103decoder.cs deleted file mode 100644 index 3f436f3..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI013103decoder.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - internal sealed class AI013103decoder : AI013x0xDecoder - { - internal AI013103decoder(BitArray information) - : base(information) - { - } - - override protected void addWeightCode(StringBuilder buf, int weight) - { - buf.Append("(3103)"); - } - - override protected int checkWeight(int weight) - { - return weight; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01320xDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01320xDecoder.cs deleted file mode 100644 index 0d180f9..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01320xDecoder.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - sealed class AI01320xDecoder : AI013x0xDecoder - { - internal AI01320xDecoder(BitArray information) - : base(information) - { - } - - override protected void addWeightCode(StringBuilder buf, int weight) - { - if (weight < 10000) - { - buf.Append("(3202)"); - } - else - { - buf.Append("(3203)"); - } - } - - override protected int checkWeight(int weight) - { - if (weight < 10000) - { - return weight; - } - return weight - 10000; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01392xDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01392xDecoder.cs deleted file mode 100644 index 4f09794..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01392xDecoder.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - internal sealed class AI01392xDecoder : AI01decoder - { - private const int HEADER_SIZE = 5 + 1 + 2; - private const int LAST_DIGIT_SIZE = 2; - - internal AI01392xDecoder(BitArray information) - : base(information) - { - } - - override public String parseInformation() - { - if (this.getInformation().Size < HEADER_SIZE + GTIN_SIZE) - { - return null; - } - - StringBuilder buf = new StringBuilder(); - - encodeCompressedGtin(buf, HEADER_SIZE); - - int lastAIdigit = - this.getGeneralDecoder().extractNumericValueFromBitArray(HEADER_SIZE + GTIN_SIZE, LAST_DIGIT_SIZE); - buf.Append("(392"); - buf.Append(lastAIdigit); - buf.Append(')'); - - DecodedInformation decodedInformation = - this.getGeneralDecoder().decodeGeneralPurposeField(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE, null); - buf.Append(decodedInformation.getNewString()); - - return buf.ToString(); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01393xDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01393xDecoder.cs deleted file mode 100644 index 82571fa..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01393xDecoder.cs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ -using System; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - sealed class AI01393xDecoder : AI01decoder - { - private static int HEADER_SIZE = 5 + 1 + 2; - private static int LAST_DIGIT_SIZE = 2; - private static int FIRST_THREE_DIGITS_SIZE = 10; - - internal AI01393xDecoder(BitArray information) - : base(information) - { - } - - override public String parseInformation() - { - if (this.getInformation().Size < HEADER_SIZE + GTIN_SIZE) - { - return null; - } - - StringBuilder buf = new StringBuilder(); - - encodeCompressedGtin(buf, HEADER_SIZE); - - int lastAIdigit = - this.getGeneralDecoder().extractNumericValueFromBitArray(HEADER_SIZE + GTIN_SIZE, LAST_DIGIT_SIZE); - - buf.Append("(393"); - buf.Append(lastAIdigit); - buf.Append(')'); - - int firstThreeDigits = - this.getGeneralDecoder().extractNumericValueFromBitArray(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE, FIRST_THREE_DIGITS_SIZE); - if (firstThreeDigits / 100 == 0) - { - buf.Append('0'); - } - if (firstThreeDigits / 10 == 0) - { - buf.Append('0'); - } - buf.Append(firstThreeDigits); - - DecodedInformation generalInformation = - this.getGeneralDecoder().decodeGeneralPurposeField(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE + FIRST_THREE_DIGITS_SIZE, null); - buf.Append(generalInformation.getNewString()); - - return buf.ToString(); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI013x0x1xDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI013x0x1xDecoder.cs deleted file mode 100644 index 347a5c5..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI013x0x1xDecoder.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - sealed class AI013x0x1xDecoder : AI01weightDecoder - { - private static int HEADER_SIZE = 7 + 1; - private static int WEIGHT_SIZE = 20; - private static int DATE_SIZE = 16; - - private String dateCode; - private String firstAIdigits; - - internal AI013x0x1xDecoder(BitArray information, String firstAIdigits, String dateCode) - : base(information) - { - this.dateCode = dateCode; - this.firstAIdigits = firstAIdigits; - } - - override public String parseInformation() - { - if (this.getInformation().Size != HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE + DATE_SIZE) - { - return null; - } - - StringBuilder buf = new StringBuilder(); - - encodeCompressedGtin(buf, HEADER_SIZE); - encodeCompressedWeight(buf, HEADER_SIZE + GTIN_SIZE, WEIGHT_SIZE); - encodeCompressedDate(buf, HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE); - - return buf.ToString(); - } - - private void encodeCompressedDate(StringBuilder buf, int currentPos) - { - int numericDate = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos, DATE_SIZE); - if (numericDate == 38400) - { - return; - } - - buf.Append('('); - buf.Append(this.dateCode); - buf.Append(')'); - - int day = numericDate % 32; - numericDate /= 32; - int month = numericDate % 12 + 1; - numericDate /= 12; - int year = numericDate; - - if (year / 10 == 0) - { - buf.Append('0'); - } - buf.Append(year); - if (month / 10 == 0) - { - buf.Append('0'); - } - buf.Append(month); - if (day / 10 == 0) - { - buf.Append('0'); - } - buf.Append(day); - } - - override protected void addWeightCode(StringBuilder buf, int weight) - { - int lastAI = weight / 100000; - buf.Append('('); - buf.Append(this.firstAIdigits); - buf.Append(lastAI); - buf.Append(')'); - } - - override protected int checkWeight(int weight) - { - return weight % 100000; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI013x0xDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI013x0xDecoder.cs deleted file mode 100644 index 57e6510..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI013x0xDecoder.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - abstract class AI013x0xDecoder : AI01weightDecoder - { - private static int HEADER_SIZE = 4 + 1; - private static int WEIGHT_SIZE = 15; - - internal AI013x0xDecoder(BitArray information) - : base(information) - { - } - - override public String parseInformation() - { - if (this.getInformation().Size != HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE) - { - return null; - } - - StringBuilder buf = new StringBuilder(); - - encodeCompressedGtin(buf, HEADER_SIZE); - encodeCompressedWeight(buf, HEADER_SIZE + GTIN_SIZE, WEIGHT_SIZE); - - return buf.ToString(); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01AndOtherAIs.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01AndOtherAIs.cs deleted file mode 100644 index cafa67d..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01AndOtherAIs.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class AI01AndOtherAIs : AI01decoder - { - private static int HEADER_SIZE = 1 + 1 + 2; //first bit encodes the linkage flag, - //the second one is the encodation method, and the other two are for the variable length - - internal AI01AndOtherAIs(BitArray information) - : base(information) - { - } - - override public String parseInformation() - { - StringBuilder buff = new StringBuilder(); - - buff.Append("(01)"); - int initialGtinPosition = buff.Length; - int firstGtinDigit = this.getGeneralDecoder().extractNumericValueFromBitArray(HEADER_SIZE, 4); - buff.Append(firstGtinDigit); - - this.encodeCompressedGtinWithoutAI(buff, HEADER_SIZE + 4, initialGtinPosition); - - return this.getGeneralDecoder().decodeAllCodes(buff, HEADER_SIZE + 44); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01decoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01decoder.cs deleted file mode 100644 index 5df6366..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01decoder.cs +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - abstract class AI01decoder : AbstractExpandedDecoder - { - protected static int GTIN_SIZE = 40; - - internal AI01decoder(BitArray information) - : base(information) - { - } - - protected void encodeCompressedGtin(StringBuilder buf, int currentPos) - { - buf.Append("(01)"); - int initialPosition = buf.Length; - buf.Append('9'); - - encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition); - } - - protected void encodeCompressedGtinWithoutAI(StringBuilder buf, int currentPos, int initialBufferPosition) - { - for (int i = 0; i < 4; ++i) - { - int currentBlock = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos + 10 * i, 10); - if (currentBlock / 100 == 0) - { - buf.Append('0'); - } - if (currentBlock / 10 == 0) - { - buf.Append('0'); - } - buf.Append(currentBlock); - } - - appendCheckDigit(buf, initialBufferPosition); - } - - private static void appendCheckDigit(StringBuilder buf, int currentPos) - { - int checkDigit = 0; - for (int i = 0; i < 13; i++) - { - int digit = buf[i + currentPos] - '0'; - checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; - } - - checkDigit = 10 - (checkDigit % 10); - if (checkDigit == 10) - { - checkDigit = 0; - } - - buf.Append(checkDigit); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AI01weightDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AI01weightDecoder.cs deleted file mode 100644 index b9efcfe..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AI01weightDecoder.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - abstract class AI01weightDecoder : AI01decoder - { - internal AI01weightDecoder(BitArray information) - : base(information) - { - } - - protected void encodeCompressedWeight(StringBuilder buf, int currentPos, int weightSize) - { - int originalWeightNumeric = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos, weightSize); - addWeightCode(buf, originalWeightNumeric); - - int weightNumeric = checkWeight(originalWeightNumeric); - - int currentDivisor = 100000; - for (int i = 0; i < 5; ++i) - { - if (weightNumeric / currentDivisor == 0) - { - buf.Append('0'); - } - currentDivisor /= 10; - } - buf.Append(weightNumeric); - } - - protected abstract void addWeightCode(StringBuilder buf, int weight); - protected abstract int checkWeight(int weight); - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AbstractExpandedDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AbstractExpandedDecoder.cs deleted file mode 100644 index c70aed8..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AbstractExpandedDecoder.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - public abstract class AbstractExpandedDecoder - { - private readonly BitArray information; - private readonly GeneralAppIdDecoder generalDecoder; - - internal AbstractExpandedDecoder(BitArray information) - { - this.information = information; - this.generalDecoder = new GeneralAppIdDecoder(information); - } - - /// - /// Gets the information. - /// - /// - protected BitArray getInformation() - { - return information; - } - - internal GeneralAppIdDecoder getGeneralDecoder() - { - return generalDecoder; - } - - /// - /// Parses the information. - /// - /// - public abstract String parseInformation(); - - /// - /// Creates the decoder. - /// - /// The information. - /// - public static AbstractExpandedDecoder createDecoder(BitArray information) - { - if (information[1]) - { - return new AI01AndOtherAIs(information); - } - if (!information[2]) - { - return new AnyAIDecoder(information); - } - - int fourBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 4); - - switch (fourBitEncodationMethod) - { - case 4: return new AI013103decoder(information); - case 5: return new AI01320xDecoder(information); - } - - int fiveBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 5); - switch (fiveBitEncodationMethod) - { - case 12: return new AI01392xDecoder(information); - case 13: return new AI01393xDecoder(information); - } - - int sevenBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 7); - switch (sevenBitEncodationMethod) - { - case 56: return new AI013x0x1xDecoder(information, "310", "11"); - case 57: return new AI013x0x1xDecoder(information, "320", "11"); - case 58: return new AI013x0x1xDecoder(information, "310", "13"); - case 59: return new AI013x0x1xDecoder(information, "320", "13"); - case 60: return new AI013x0x1xDecoder(information, "310", "15"); - case 61: return new AI013x0x1xDecoder(information, "320", "15"); - case 62: return new AI013x0x1xDecoder(information, "310", "17"); - case 63: return new AI013x0x1xDecoder(information, "320", "17"); - } - - throw new InvalidOperationException("unknown decoder: " + information); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/AnyAIDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/AnyAIDecoder.cs deleted file mode 100644 index 9f6aab7..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/AnyAIDecoder.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; - -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class AnyAIDecoder : AbstractExpandedDecoder - { - private static int HEADER_SIZE = 2 + 1 + 2; - - internal AnyAIDecoder(BitArray information) - : base(information) - { - - } - - override public String parseInformation() - { - StringBuilder buf = new StringBuilder(); - return this.getGeneralDecoder().decodeAllCodes(buf, HEADER_SIZE); - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/BlockParsedResult.cs b/zxing.core/xx/oned/rss/expanded/decoders/BlockParsedResult.cs deleted file mode 100644 index bfd861c..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/BlockParsedResult.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class BlockParsedResult - { - private DecodedInformation decodedInformation; - private bool finished; - - internal BlockParsedResult(bool finished) - : this(null, finished) - { - } - - internal BlockParsedResult(DecodedInformation information, bool finished) - { - this.finished = finished; - this.decodedInformation = information; - } - - internal DecodedInformation getDecodedInformation() - { - return this.decodedInformation; - } - - internal bool isFinished() - { - return this.finished; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/CurrentParsingState.cs b/zxing.core/xx/oned/rss/expanded/decoders/CurrentParsingState.cs deleted file mode 100644 index eb8339d..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/CurrentParsingState.cs +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - internal sealed class CurrentParsingState - { - private int position; - private State encoding; - - private enum State - { - NUMERIC, - ALPHA, - ISO_IEC_646 - } - - internal CurrentParsingState() - { - this.position = 0; - this.encoding = State.NUMERIC; - } - - internal int getPosition() - { - return position; - } - - internal void setPosition(int position) - { - this.position = position; - } - - internal void incrementPosition(int delta) - { - position += delta; - } - - internal bool isAlpha() - { - return this.encoding == State.ALPHA; - } - - internal bool isNumeric() - { - return this.encoding == State.NUMERIC; - } - - internal bool isIsoIec646() - { - return this.encoding == State.ISO_IEC_646; - } - - internal void setNumeric() - { - this.encoding = State.NUMERIC; - } - - internal void setAlpha() - { - this.encoding = State.ALPHA; - } - - internal void setIsoIec646() - { - this.encoding = State.ISO_IEC_646; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/DecodedChar.cs b/zxing.core/xx/oned/rss/expanded/decoders/DecodedChar.cs deleted file mode 100644 index 6e238c9..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/DecodedChar.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class DecodedChar : DecodedObject - { - private char value; - - internal static char FNC1 = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset - - internal DecodedChar(int newPosition, char value) - : base(newPosition) - { - this.value = value; - } - - internal char getValue() - { - return this.value; - } - - internal bool isFNC1() - { - return this.value == FNC1; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/DecodedInformation.cs b/zxing.core/xx/oned/rss/expanded/decoders/DecodedInformation.cs deleted file mode 100644 index 41f804c..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/DecodedInformation.cs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class DecodedInformation : DecodedObject - { - private String newString; - private int remainingValue; - private bool remaining; - - internal DecodedInformation(int newPosition, String newString) - : base(newPosition) - { - this.newString = newString; - this.remaining = false; - this.remainingValue = 0; - } - - internal DecodedInformation(int newPosition, String newString, int remainingValue) - : base(newPosition) - { - this.remaining = true; - this.remainingValue = remainingValue; - this.newString = newString; - } - - internal String getNewString() - { - return this.newString; - } - - internal bool isRemaining() - { - return this.remaining; - } - - internal int getRemainingValue() - { - return this.remainingValue; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/DecodedNumeric.cs b/zxing.core/xx/oned/rss/expanded/decoders/DecodedNumeric.cs deleted file mode 100644 index 40ed5c2..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/DecodedNumeric.cs +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class DecodedNumeric : DecodedObject - { - private readonly int firstDigit; - private readonly int secondDigit; - - internal static int FNC1 = 10; - - internal DecodedNumeric(int newPosition, int firstDigit, int secondDigit) - : base(newPosition) - { - if (firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10) - { - throw FormatException.Instance; - } - - this.firstDigit = firstDigit; - this.secondDigit = secondDigit; - } - - internal int getFirstDigit() - { - return this.firstDigit; - } - - internal int getSecondDigit() - { - return this.secondDigit; - } - - internal int getValue() - { - return this.firstDigit * 10 + this.secondDigit; - } - - internal bool isFirstDigitFNC1() - { - return this.firstDigit == FNC1; - } - - internal bool isSecondDigitFNC1() - { - return this.secondDigit == FNC1; - } - - internal bool isAnyFNC1() - { - return this.firstDigit == FNC1 || this.secondDigit == FNC1; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/DecodedObject.cs b/zxing.core/xx/oned/rss/expanded/decoders/DecodedObject.cs deleted file mode 100644 index 624e5a8..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/DecodedObject.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// - internal abstract class DecodedObject - { - internal int NewPosition { get; private set; } - - internal DecodedObject(int newPosition) - { - NewPosition = newPosition; - } - } -} diff --git a/zxing.core/xx/oned/rss/expanded/decoders/FieldParser.cs b/zxing.core/xx/oned/rss/expanded/decoders/FieldParser.cs deleted file mode 100644 index 3966e27..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/FieldParser.cs +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Collections.Generic; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - static class FieldParser - { - private static readonly Object VARIABLE_LENGTH = new Object(); - - // "DIGITS", new Integer(LENGTH) - // or - // "DIGITS", VARIABLE_LENGTH, new Integer(MAX_SIZE) - private static readonly IDictionary TWO_DIGIT_DATA_LENGTH; - private static readonly IDictionary THREE_DIGIT_DATA_LENGTH; - private static readonly IDictionary THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH; - private static readonly IDictionary FOUR_DIGIT_DATA_LENGTH; - - static FieldParser() - { - TWO_DIGIT_DATA_LENGTH = new Dictionary - { - {"00", new object[] {18}}, - {"01", new object[] {14}}, - {"02", new object[] {14}}, - {"10", new object[] {VARIABLE_LENGTH, 20}}, - {"11", new object[] {6}}, - {"12", new object[] {6}}, - {"13", new object[] {6}}, - {"15", new object[] {6}}, - {"17", new object[] {6}}, - {"20", new object[] {2}}, - {"21", new object[] {VARIABLE_LENGTH, 20}}, - {"22", new object[] {VARIABLE_LENGTH, 29}}, - {"30", new object[] {VARIABLE_LENGTH, 8}}, - {"37", new object[] {VARIABLE_LENGTH, 8}}, - //internal company codes - {"90", new object[] {VARIABLE_LENGTH, 30}}, - {"91", new object[] {VARIABLE_LENGTH, 30}}, - {"92", new object[] {VARIABLE_LENGTH, 30}}, - {"93", new object[] {VARIABLE_LENGTH, 30}}, - {"94", new object[] {VARIABLE_LENGTH, 30}}, - {"95", new object[] {VARIABLE_LENGTH, 30}}, - {"96", new object[] {VARIABLE_LENGTH, 30}}, - {"97", new object[] {VARIABLE_LENGTH, 30}}, - {"98", new object[] {VARIABLE_LENGTH, 30}}, - {"99", new object[] {VARIABLE_LENGTH, 30}} - }; - THREE_DIGIT_DATA_LENGTH = new Dictionary - { - // Same format as above - - {"240", new object[] {VARIABLE_LENGTH, 30}}, - {"241", new object[] {VARIABLE_LENGTH, 30}}, - {"242", new object[] {VARIABLE_LENGTH, 6}}, - {"250", new object[] {VARIABLE_LENGTH, 30}}, - {"251", new object[] {VARIABLE_LENGTH, 30}}, - {"253", new object[] {VARIABLE_LENGTH, 17}}, - {"254", new object[] {VARIABLE_LENGTH, 20}}, - - {"400", new object[] {VARIABLE_LENGTH, 30}}, - {"401", new object[] {VARIABLE_LENGTH, 30}}, - {"402", new object[] {17}}, - {"403", new object[] {VARIABLE_LENGTH, 30}}, - {"410", new object[] {13}}, - {"411", new object[] {13}}, - {"412", new object[] {13}}, - {"413", new object[] {13}}, - {"414", new object[] {13}}, - {"420", new object[] {VARIABLE_LENGTH, 20}}, - {"421", new object[] {VARIABLE_LENGTH, 15}}, - {"422", new object[] {3}}, - {"423", new object[] {VARIABLE_LENGTH, 15}}, - {"424", new object[] {3}}, - {"425", new object[] {3}}, - {"426", new object[] {3}}, - }; - THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = new Dictionary - { - {"310", new object[] {6}}, - {"311", new object[] {6}}, - {"312", new object[] {6}}, - {"313", new object[] {6}}, - {"314", new object[] {6}}, - {"315", new object[] {6}}, - {"316", new object[] {6}}, - {"320", new object[] {6}}, - {"321", new object[] {6}}, - {"322", new object[] {6}}, - {"323", new object[] {6}}, - {"324", new object[] {6}}, - {"325", new object[] {6}}, - {"326", new object[] {6}}, - {"327", new object[] {6}}, - {"328", new object[] {6}}, - {"329", new object[] {6}}, - {"330", new object[] {6}}, - {"331", new object[] {6}}, - {"332", new object[] {6}}, - {"333", new object[] {6}}, - {"334", new object[] {6}}, - {"335", new object[] {6}}, - {"336", new object[] {6}}, - {"340", new object[] {6}}, - {"341", new object[] {6}}, - {"342", new object[] {6}}, - {"343", new object[] {6}}, - {"344", new object[] {6}}, - {"345", new object[] {6}}, - {"346", new object[] {6}}, - {"347", new object[] {6}}, - {"348", new object[] {6}}, - {"349", new object[] {6}}, - {"350", new object[] {6}}, - {"351", new object[] {6}}, - {"352", new object[] {6}}, - {"353", new object[] {6}}, - {"354", new object[] {6}}, - {"355", new object[] {6}}, - {"356", new object[] {6}}, - {"357", new object[] {6}}, - {"360", new object[] {6}}, - {"361", new object[] {6}}, - {"362", new object[] {6}}, - {"363", new object[] {6}}, - {"364", new object[] {6}}, - {"365", new object[] {6}}, - {"366", new object[] {6}}, - {"367", new object[] {6}}, - {"368", new object[] {6}}, - {"369", new object[] {6}}, - {"390", new object[] {VARIABLE_LENGTH, 15}}, - {"391", new object[] {VARIABLE_LENGTH, 18}}, - {"392", new object[] {VARIABLE_LENGTH, 15}}, - {"393", new object[] {VARIABLE_LENGTH, 18}}, - {"703", new object[] {VARIABLE_LENGTH, 30}} - - }; - FOUR_DIGIT_DATA_LENGTH = new Dictionary - { - {"7001", new object[] {13}}, - {"7002", new object[] {VARIABLE_LENGTH, 30}}, - {"7003", new object[] {10}}, - - {"8001", new object[] {14}}, - {"8002", new object[] {VARIABLE_LENGTH, 20}}, - {"8003", new object[] {VARIABLE_LENGTH, 30}}, - {"8004", new object[] {VARIABLE_LENGTH, 30}}, - {"8005", new object[] {6}}, - {"8006", new object[] {18}}, - {"8007", new object[] {VARIABLE_LENGTH, 30}}, - {"8008", new object[] {VARIABLE_LENGTH, 12}}, - {"8018", new object[] {18}}, - {"8020", new object[] {VARIABLE_LENGTH, 25}}, - {"8100", new object[] {6}}, - {"8101", new object[] {10}}, - {"8102", new object[] {2}}, - {"8110", new object[] {VARIABLE_LENGTH, 70}}, - {"8200", new object[] {VARIABLE_LENGTH, 70}}, - }; - } - - internal static String parseFieldsInGeneralPurpose(String rawInformation) - { - if (String.IsNullOrEmpty(rawInformation)) - { - return null; - } - - // Processing 2-digit AIs - - if (rawInformation.Length < 2) - { - return null; - } - - String firstTwoDigits = rawInformation.Substring(0, 2); - - if (TWO_DIGIT_DATA_LENGTH.ContainsKey(firstTwoDigits)) - { - var dataLength = TWO_DIGIT_DATA_LENGTH[firstTwoDigits]; - if (dataLength[0] == VARIABLE_LENGTH) - { - return processVariableAI(2, (int)dataLength[1], rawInformation); - } - return processFixedAI(2, (int)dataLength[0], rawInformation); - } - - if (rawInformation.Length < 3) - { - return null; - } - - String firstThreeDigits = rawInformation.Substring(0, 3); - - if (THREE_DIGIT_DATA_LENGTH.ContainsKey(firstThreeDigits)) - { - var dataLength = THREE_DIGIT_DATA_LENGTH[firstThreeDigits]; - if (dataLength[0] == VARIABLE_LENGTH) - { - return processVariableAI(3, (int)dataLength[1], rawInformation); - } - return processFixedAI(3, (int)dataLength[0], rawInformation); - } - - if (THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.ContainsKey(firstThreeDigits)) - { - var dataLength = THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[firstThreeDigits]; - if (dataLength[0] == VARIABLE_LENGTH) - { - return processVariableAI(4, (int)dataLength[1], rawInformation); - } - return processFixedAI(4, (int)dataLength[0], rawInformation); - } - - if (rawInformation.Length < 4) - { - return null; - } - - String firstFourDigits = rawInformation.Substring(0, 4); - - if (FOUR_DIGIT_DATA_LENGTH.ContainsKey(firstFourDigits)) - { - var dataLength = FOUR_DIGIT_DATA_LENGTH[firstFourDigits]; - if (dataLength[0] == VARIABLE_LENGTH) - { - return processVariableAI(4, (int)dataLength[1], rawInformation); - } - return processFixedAI(4, (int)dataLength[0], rawInformation); - } - - return null; - } - - private static String processFixedAI(int aiSize, int fieldSize, String rawInformation) - { - if (rawInformation.Length < aiSize) - { - return null; - } - - String ai = rawInformation.Substring(0, aiSize); - - if (rawInformation.Length < aiSize + fieldSize) - { - return null; - } - - String field = rawInformation.Substring(aiSize, fieldSize); - String remaining = rawInformation.Substring(aiSize + fieldSize); - String result = '(' + ai + ')' + field; - String parsedAI = parseFieldsInGeneralPurpose(remaining); - return parsedAI == null ? result : result + parsedAI; - } - - private static String processVariableAI(int aiSize, int variableFieldSize, String rawInformation) - { - String ai = rawInformation.Substring(0, aiSize); - int maxSize; - if (rawInformation.Length < aiSize + variableFieldSize) - { - maxSize = rawInformation.Length; - } - else - { - maxSize = aiSize + variableFieldSize; - } - String field = rawInformation.Substring(aiSize, maxSize - aiSize); - String remaining = rawInformation.Substring(maxSize); - String result = '(' + ai + ')' + field; - String parsedAI = parseFieldsInGeneralPurpose(remaining); - return parsedAI == null ? result : result + parsedAI; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/oned/rss/expanded/decoders/GeneralAppIdDecoder.cs b/zxing.core/xx/oned/rss/expanded/decoders/GeneralAppIdDecoder.cs deleted file mode 100644 index 30ad574..0000000 --- a/zxing.core/xx/oned/rss/expanded/decoders/GeneralAppIdDecoder.cs +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * These authors would like to acknowledge the Spanish Ministry of Industry, - * Tourism and Trade, for the support in the project TSI020301-2008-2 - * "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled - * Mobile Dynamic Environments", led by Treelogic - * ( http://www.treelogic.com/ ): - * - * http://www.piramidepse.com/ - */ - -using System; -using System.Collections.Generic; -using System.Text; -using ZXing.Common; - -namespace ZXing.OneD.RSS.Expanded.Decoders -{ - /// - /// Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) - /// Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) - /// - internal sealed class GeneralAppIdDecoder - { - private BitArray information; - private CurrentParsingState current = new CurrentParsingState(); - private StringBuilder buffer = new StringBuilder(); - - internal GeneralAppIdDecoder(BitArray information) - { - this.information = information; - } - - internal String decodeAllCodes(StringBuilder buff, int initialPosition) - { - int currentPosition = initialPosition; - String remaining = null; - do - { - DecodedInformation info = this.decodeGeneralPurposeField(currentPosition, remaining); - String parsedFields = FieldParser.parseFieldsInGeneralPurpose(info.getNewString()); - if (parsedFields != null) - { - buff.Append(parsedFields); - } - if (info.isRemaining()) - { - remaining = info.getRemainingValue().ToString(); - } - else - { - remaining = null; - } - - if (currentPosition == info.NewPosition) - {// No step forward! - break; - } - currentPosition = info.NewPosition; - } while (true); - - return buff.ToString(); - } - - private bool isStillNumeric(int pos) - { - // It's numeric if it still has 7 positions - // and one of the first 4 bits is "1". - if (pos + 7 > this.information.Size) - { - return pos + 4 <= this.information.Size; - } - - for (int i = pos; i < pos + 3; ++i) - { - if (this.information[i]) - { - return true; - } - } - - return this.information[pos + 3]; - } - - private DecodedNumeric decodeNumeric(int pos) - { - int numeric; - if (pos + 7 > this.information.Size) - { - numeric = extractNumericValueFromBitArray(pos, 4); - if (numeric == 0) - { - return new DecodedNumeric(this.information.Size, DecodedNumeric.FNC1, DecodedNumeric.FNC1); - } - return new DecodedNumeric(this.information.Size, numeric - 1, DecodedNumeric.FNC1); - } - numeric = extractNumericValueFromBitArray(pos, 7); - - int digit1 = (numeric - 8) / 11; - int digit2 = (numeric - 8) % 11; - - return new DecodedNumeric(pos + 7, digit1, digit2); - } - - internal int extractNumericValueFromBitArray(int pos, int bits) - { - return extractNumericValueFromBitArray(this.information, pos, bits); - } - - internal static int extractNumericValueFromBitArray(BitArray information, int pos, int bits) - { - int value = 0; - for (int i = 0; i < bits; ++i) - { - if (information[pos + i]) - { - value |= 1 << (bits - i - 1); - } - } - - return value; - } - - internal DecodedInformation decodeGeneralPurposeField(int pos, String remaining) - { - this.buffer.Length = 0; - - if (remaining != null) - { - this.buffer.Append(remaining); - } - - this.current.setPosition(pos); - - DecodedInformation lastDecoded = parseBlocks(); - if (lastDecoded != null && lastDecoded.isRemaining()) - { - return new DecodedInformation(this.current.getPosition(), this.buffer.ToString(), lastDecoded.getRemainingValue()); - } - return new DecodedInformation(this.current.getPosition(), this.buffer.ToString()); - } - - private DecodedInformation parseBlocks() - { - bool isFinished; - BlockParsedResult result; - do - { - int initialPosition = current.getPosition(); - - if (current.isAlpha()) - { - result = parseAlphaBlock(); - isFinished = result.isFinished(); - } - else if (current.isIsoIec646()) - { - result = parseIsoIec646Block(); - isFinished = result.isFinished(); - } - else - { // it must be numeric - result = parseNumericBlock(); - isFinished = result.isFinished(); - } - - bool positionChanged = initialPosition != current.getPosition(); - if (!positionChanged && !isFinished) - { - break; - } - } while (!isFinished); - - return result.getDecodedInformation(); - } - - private BlockParsedResult parseNumericBlock() - { - while (isStillNumeric(current.getPosition())) - { - DecodedNumeric numeric = decodeNumeric(current.getPosition()); - current.setPosition(numeric.NewPosition); - - if (numeric.isFirstDigitFNC1()) - { - DecodedInformation information; - if (numeric.isSecondDigitFNC1()) - { - information = new DecodedInformation(current.getPosition(), buffer.ToString()); - } - else - { - information = new DecodedInformation(current.getPosition(), buffer.ToString(), numeric.getSecondDigit()); - } - return new BlockParsedResult(information, true); - } - buffer.Append(numeric.getFirstDigit()); - - if (numeric.isSecondDigitFNC1()) - { - DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.ToString()); - return new BlockParsedResult(information, true); - } - buffer.Append(numeric.getSecondDigit()); - } - - if (isNumericToAlphaNumericLatch(current.getPosition())) - { - current.setAlpha(); - current.incrementPosition(4); - } - return new BlockParsedResult(false); - } - - private BlockParsedResult parseIsoIec646Block() - { - while (isStillIsoIec646(current.getPosition())) - { - DecodedChar iso = decodeIsoIec646(current.getPosition()); - current.setPosition(iso.NewPosition); - - if (iso.isFNC1()) - { - DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.ToString()); - return new BlockParsedResult(information, true); - } - buffer.Append(iso.getValue()); - } - - if (isAlphaOr646ToNumericLatch(current.getPosition())) - { - current.incrementPosition(3); - current.setNumeric(); - } - else if (isAlphaTo646ToAlphaLatch(current.getPosition())) - { - if (current.getPosition() + 5 < this.information.Size) - { - current.incrementPosition(5); - } - else - { - current.setPosition(this.information.Size); - } - - current.setAlpha(); - } - return new BlockParsedResult(false); - } - - private BlockParsedResult parseAlphaBlock() - { - while (isStillAlpha(current.getPosition())) - { - DecodedChar alpha = decodeAlphanumeric(current.getPosition()); - current.setPosition(alpha.NewPosition); - - if (alpha.isFNC1()) - { - DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.ToString()); - return new BlockParsedResult(information, true); //end of the char block - } - - buffer.Append(alpha.getValue()); - } - - if (isAlphaOr646ToNumericLatch(current.getPosition())) - { - current.incrementPosition(3); - current.setNumeric(); - } - else if (isAlphaTo646ToAlphaLatch(current.getPosition())) - { - if (current.getPosition() + 5 < this.information.Size) - { - current.incrementPosition(5); - } - else - { - current.setPosition(this.information.Size); - } - - current.setIsoIec646(); - } - return new BlockParsedResult(false); - } - - private bool isStillIsoIec646(int pos) - { - if (pos + 5 > this.information.Size) - { - return false; - } - - int fiveBitValue = extractNumericValueFromBitArray(pos, 5); - if (fiveBitValue >= 5 && fiveBitValue < 16) - { - return true; - } - - if (pos + 7 > this.information.Size) - { - return false; - } - - int sevenBitValue = extractNumericValueFromBitArray(pos, 7); - if (sevenBitValue >= 64 && sevenBitValue < 116) - { - return true; - } - - if (pos + 8 > this.information.Size) - { - return false; - } - - int eightBitValue = extractNumericValueFromBitArray(pos, 8); - return eightBitValue >= 232 && eightBitValue < 253; - - } - - private DecodedChar decodeIsoIec646(int pos) - { - int fiveBitValue = extractNumericValueFromBitArray(pos, 5); - if (fiveBitValue == 15) - { - return new DecodedChar(pos + 5, DecodedChar.FNC1); - } - - if (fiveBitValue >= 5 && fiveBitValue < 15) - { - return new DecodedChar(pos + 5, (char)('0' + fiveBitValue - 5)); - } - - int sevenBitValue = extractNumericValueFromBitArray(pos, 7); - - if (sevenBitValue >= 64 && sevenBitValue < 90) - { - return new DecodedChar(pos + 7, (char)(sevenBitValue + 1)); - } - - if (sevenBitValue >= 90 && sevenBitValue < 116) - { - return new DecodedChar(pos + 7, (char)(sevenBitValue + 7)); - } - - int eightBitValue = extractNumericValueFromBitArray(pos, 8); - char c; - switch (eightBitValue) - { - case 232: - c = '!'; - break; - case 233: - c = '"'; - break; - case 234: - c = '%'; - break; - case 235: - c = '&'; - break; - case 236: - c = '\''; - break; - case 237: - c = '('; - break; - case 238: - c = ')'; - break; - case 239: - c = '*'; - break; - case 240: - c = '+'; - break; - case 241: - c = ','; - break; - case 242: - c = '-'; - break; - case 243: - c = '.'; - break; - case 244: - c = '/'; - break; - case 245: - c = ':'; - break; - case 246: - c = ';'; - break; - case 247: - c = '<'; - break; - case 248: - c = '='; - break; - case 249: - c = '>'; - break; - case 250: - c = '?'; - break; - case 251: - c = '_'; - break; - case 252: - c = ' '; - break; - default: - throw new ArgumentException("Decoding invalid ISO/IEC 646 value: " + eightBitValue); - } - return new DecodedChar(pos + 8, c); - } - - private bool isStillAlpha(int pos) - { - if (pos + 5 > this.information.Size) - { - return false; - } - - // We now check if it's a valid 5-bit value (0..9 and FNC1) - int fiveBitValue = extractNumericValueFromBitArray(pos, 5); - if (fiveBitValue >= 5 && fiveBitValue < 16) - { - return true; - } - - if (pos + 6 > this.information.Size) - { - return false; - } - - int sixBitValue = extractNumericValueFromBitArray(pos, 6); - return sixBitValue >= 16 && sixBitValue < 63; // 63 not included - } - - private DecodedChar decodeAlphanumeric(int pos) - { - int fiveBitValue = extractNumericValueFromBitArray(pos, 5); - if (fiveBitValue == 15) - { - return new DecodedChar(pos + 5, DecodedChar.FNC1); - } - - if (fiveBitValue >= 5 && fiveBitValue < 15) - { - return new DecodedChar(pos + 5, (char)('0' + fiveBitValue - 5)); - } - - int sixBitValue = extractNumericValueFromBitArray(pos, 6); - - if (sixBitValue >= 32 && sixBitValue < 58) - { - return new DecodedChar(pos + 6, (char)(sixBitValue + 33)); - } - - char c; - switch (sixBitValue) - { - case 58: - c = '*'; - break; - case 59: - c = ','; - break; - case 60: - c = '-'; - break; - case 61: - c = '.'; - break; - case 62: - c = '/'; - break; - default: - throw new InvalidOperationException("Decoding invalid alphanumeric value: " + sixBitValue); - } - return new DecodedChar(pos + 6, c); - } - - private bool isAlphaTo646ToAlphaLatch(int pos) - { - if (pos + 1 > this.information.Size) - { - return false; - } - - for (int i = 0; i < 5 && i + pos < this.information.Size; ++i) - { - if (i == 2) - { - if (!this.information[pos + 2]) - { - return false; - } - } - else if (this.information[pos + i]) - { - return false; - } - } - - return true; - } - - private bool isAlphaOr646ToNumericLatch(int pos) - { - // Next is alphanumeric if there are 3 positions and they are all zeros - if (pos + 3 > this.information.Size) - { - return false; - } - - for (int i = pos; i < pos + 3; ++i) - { - if (this.information[i]) - { - return false; - } - } - return true; - } - - private bool isNumericToAlphaNumericLatch(int pos) - { - // Next is alphanumeric if there are 4 positions and they are all zeros, or - // if there is a subset of this just before the end of the symbol - if (pos + 1 > this.information.Size) - { - return false; - } - - for (int i = 0; i < 4 && i + pos < this.information.Size; ++i) - { - if (this.information[pos + i]) - { - return false; - } - } - return true; - } - } -} diff --git a/zxing.core/xx/pdf417/PDF417Common.cs b/zxing.core/xx/pdf417/PDF417Common.cs deleted file mode 100644 index 396c76f..0000000 --- a/zxing.core/xx/pdf417/PDF417Common.cs +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Collections.Generic; - -namespace ZXing.PDF417 -{ - /// - /// SITA Lab (kevin.osullivan@sita.aero) - /// Guenther Grau - /// - internal static class PDF417Common - { - public static readonly int INVALID_CODEWORD = -1; - - public static readonly int NUMBER_OF_CODEWORDS = 929; - - /// - /// Maximum Codewords (Data + Error). - /// - public static readonly int MAX_CODEWORDS_IN_BARCODE = NUMBER_OF_CODEWORDS - 1; - - public static readonly int MIN_ROWS_IN_BARCODE = 3; - public static readonly int MAX_ROWS_IN_BARCODE = 90; - - /* - /// - /// One left row indication column + max 30 data columns + one right row indicator column - /// - public static readonly int MAX_CODEWORDS_IN_ROW = 32; - */ - - public static readonly int MODULES_IN_CODEWORD = 17; - public static readonly int MODULES_IN_STOP_PATTERN = 18; - public static readonly int BARS_IN_MODULE = 8; - - private static readonly int[] EMPTY_INT_ARRAY = {}; - - /// - /// Gets the bit count sum. - /// - /// The bit count sum. - /// Module bit count. - public static int getBitCountSum(int[] moduleBitCount) - { - int bitCountSum = 0; - foreach (int count in moduleBitCount) - { - bitCountSum += count; - } - return bitCountSum; - } - - /// - /// Converts an ICollection to an int[] - /// Carry-over from Java. Will likely remove and replace with the Generic .ToArray() method. - /// - /// The int array. - /// List. - public static int[] toIntArray(ICollection list) - { - if (list == null || list.Count == 0) - { - return EMPTY_INT_ARRAY; - } - int[] result = new int[list.Count]; - int i = 0; - foreach (int integer in list) - { - result[i++] = integer; - } - return result; - } - - /// - /// Translate the symbol into a codeword - /// - /// the codeword corresponding to the symbol. - /// encoded symbol to translate to a codeword - public static int getCodeword(long symbol) - { - int i = System.Array.BinarySearch(SYMBOL_TABLE, (int)(symbol & 0x3FFFF)); - if (i < 0) - { - return -1; - } - return (CODEWORD_TABLE[i] - 1)%NUMBER_OF_CODEWORDS; - } - - /// - /// 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. - /// - public 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/zxing.core/xx/pdf417/PDF417Reader.cs b/zxing.core/xx/pdf417/PDF417Reader.cs deleted file mode 100644 index b851716..0000000 --- a/zxing.core/xx/pdf417/PDF417Reader.cs +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; -using ZXing.Multi; -using ZXing.PDF417.Internal; - -namespace ZXing.PDF417 -{ - /// - /// This implementation can detect and decode PDF417 codes in an image. - /// - /// SITA Lab (kevin.osullivan@sita.aero) - /// Guenther Grau - /// - public sealed class PDF417Reader : Reader, MultipleBarcodeReader - { - /// - /// Locates and decodes a PDF417 code in an image. - /// - /// a String representing the content encoded by the PDF417 code - /// if a PDF417 cannot be decoded - /// - public Result decode(BinaryBitmap image) - { - return decode(image, null); - } - - /// - /// 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. - /// **Note** this will return the FIRST barcode discovered if there are many. - /// - /// 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 - /// - public Result decode(BinaryBitmap image, - IDictionary hints) - { - Result[] results = decode(image, hints, false); - if (results.Length == 0) - { - return null; - } - else - { - return results[0]; // First barcode discovered. - } - } - - /// - /// Locates and decodes Multiple PDF417 codes in an image. - /// - /// an array of Strings representing the content encoded by the PDF417 codes - /// - public Result[] decodeMultiple(BinaryBitmap image) - { - return decodeMultiple(image, null); - } - - /// - /// Locates and decodes multiple barcodes 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 barcodes encode - /// - public Result[] decodeMultiple(BinaryBitmap image, - IDictionary hints) - { - return decode(image, hints, true); - } - - /// - /// Decode the specified image, with the hints and optionally multiple barcodes. - /// Based on Owen's Comments in , this method has been modified to continue silently - /// if a barcode was not decoded where it was detected instead of throwing a new exception object. - /// - /// Image. - /// Hints. - /// If set to true multiple. - private static Result[] decode(BinaryBitmap image, IDictionary hints, bool multiple) - { - var results = new List(); - var detectorResult = Detector.detect(image, hints, multiple); - if (detectorResult != null) - { - foreach (var points in detectorResult.Points) - { - var decoderResult = PDF417ScanningDecoder.decode(detectorResult.Bits, points[4], points[5], - points[6], points[7], getMinCodewordWidth(points), getMaxCodewordWidth(points)); - if (decoderResult == null) - { - continue; - } - var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.PDF_417); - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.ECLevel); - var pdf417ResultMetadata = (PDF417ResultMetadata) decoderResult.Other; - if (pdf417ResultMetadata != null) - { - result.putMetadata(ResultMetadataType.PDF417_EXTRA_METADATA, pdf417ResultMetadata); - } - results.Add(result); - } - } - return results.ToArray(); - } - - /// - /// Gets the maximum width of the barcode - /// - /// The max width. - /// P1. - /// P2. - private static int getMaxWidth(ResultPoint p1, ResultPoint p2) - { - if (p1 == null || p2 == null) - { - return 0; - } - return (int) Math.Abs(p1.X - p2.X); - } - - /// - /// Gets the minimum width of the barcode - /// - /// The minimum width. - /// P1. - /// P2. - private static int getMinWidth(ResultPoint p1, ResultPoint p2) - { - if (p1 == null || p2 == null) - { - return int.MaxValue; - } - return (int) Math.Abs(p1.X - p2.X); - } - - /// - /// Gets the maximum width of the codeword. - /// - /// The max codeword width. - /// P. - private static int getMaxCodewordWidth(ResultPoint[] p) - { - return Math.Max( - Math.Max(getMaxWidth(p[0], p[4]), getMaxWidth(p[6], p[2])*PDF417Common.MODULES_IN_CODEWORD/ - PDF417Common.MODULES_IN_STOP_PATTERN), - Math.Max(getMaxWidth(p[1], p[5]), getMaxWidth(p[7], p[3])*PDF417Common.MODULES_IN_CODEWORD/ - PDF417Common.MODULES_IN_STOP_PATTERN)); - } - - /// - /// Gets the minimum width of the codeword. - /// - /// The minimum codeword width. - /// P. - private static int getMinCodewordWidth(ResultPoint[] p) - { - return Math.Min( - Math.Min(getMinWidth(p[0], p[4]), getMinWidth(p[6], p[2])*PDF417Common.MODULES_IN_CODEWORD/ - PDF417Common.MODULES_IN_STOP_PATTERN), - Math.Min(getMinWidth(p[1], p[5]), getMinWidth(p[7], p[3])*PDF417Common.MODULES_IN_CODEWORD/ - PDF417Common.MODULES_IN_STOP_PATTERN)); - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - public void reset() - { - // do nothing - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/PDF417ResultMetadata.cs b/zxing.core/xx/pdf417/PDF417ResultMetadata.cs deleted file mode 100644 index a6779a1..0000000 --- a/zxing.core/xx/pdf417/PDF417ResultMetadata.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417 -{ - /// - /// PDF 417 result meta data. - /// Guenther Grau - /// - public sealed class PDF417ResultMetadata - { - public int SegmentIndex { get; set; } - public string FileId { get; set; } - public int[] OptionalData { get; set; } - public bool IsLastSegment { get; set; } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/PDF417Writer.cs b/zxing.core/xx/pdf417/PDF417Writer.cs deleted file mode 100644 index b2cb439..0000000 --- a/zxing.core/xx/pdf417/PDF417Writer.cs +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -using ZXing.Common; -using ZXing.PDF417.Internal; - -namespace ZXing.PDF417 -{ - /// - /// Jacob Haynes - /// qwandor@google.com (Andrew Walbran) - /// - public sealed class PDF417Writer : Writer - { - /// - /// default white space (margin) around the code - /// - private const int WHITE_SPACE = 30; - - /// - /// - /// 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) - /// - public BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (format != BarcodeFormat.PDF_417) - { - throw new ArgumentException("Can only encode PDF_417, but got " + format); - } - - var encoder = new Internal.PDF417(); - var margin = WHITE_SPACE; - var errorCorrectionLevel = 2; - - if (hints != null) - { - if (hints.ContainsKey(EncodeHintType.PDF417_COMPACT)) - { - encoder.setCompact((Boolean) hints[EncodeHintType.PDF417_COMPACT]); - } - if (hints.ContainsKey(EncodeHintType.PDF417_COMPACTION)) - { - encoder.setCompaction((Compaction) hints[EncodeHintType.PDF417_COMPACTION]); - } - if (hints.ContainsKey(EncodeHintType.PDF417_DIMENSIONS)) - { - var dimensions = (Dimensions) hints[EncodeHintType.PDF417_DIMENSIONS]; - encoder.setDimensions(dimensions.MaxCols, - dimensions.MinCols, - dimensions.MaxRows, - dimensions.MinRows); - } - if (hints.ContainsKey(EncodeHintType.MARGIN)) - { - margin = (int)(hints[EncodeHintType.MARGIN]); - } - if (hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) - { - var value = hints[EncodeHintType.ERROR_CORRECTION]; - if (value is PDF417ErrorCorrectionLevel || - value is int) - { - errorCorrectionLevel = (int)value; - } - } - if (hints.ContainsKey(EncodeHintType.CHARACTER_SET)) - { -#if !SILVERLIGHT || WINDOWS_PHONE - var encoding = (String)hints[EncodeHintType.CHARACTER_SET]; - if (encoding != null) - { - encoder.setEncoding(encoding); - } -#else - // Silverlight supports only UTF-8 and UTF-16 out-of-the-box - encoder.setEncoding("UTF-8"); -#endif - } - if (hints.ContainsKey(EncodeHintType.DISABLE_ECI)) - { - encoder.setDisableEci((bool)hints[EncodeHintType.DISABLE_ECI]); - } - } - - return bitMatrixFromEncoder(encoder, contents, width, height, margin, errorCorrectionLevel); - } - - /// - /// 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) - /// - public BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height) - { - return encode(contents, format, width, height, null); - } - - /// - /// Takes encoder, accounts for width/height, and retrieves bit matrix - /// - private static BitMatrix bitMatrixFromEncoder(Internal.PDF417 encoder, - String contents, - int width, - int height, - int margin, - int errorCorrectionLevel) - { - encoder.generateBarcodeLogic(contents, errorCorrectionLevel); - - const int lineThickness = 2; - const int aspectRatio = 4; - sbyte[][] originalScale = encoder.BarcodeMatrix.getScaledMatrix(lineThickness, aspectRatio*lineThickness); - bool rotated = false; - if ((height > width) ^ (originalScale[0].Length < originalScale.Length)) - { - originalScale = rotateArray(originalScale); - rotated = true; - } - - int scaleX = width/originalScale[0].Length; - int scaleY = height/originalScale.Length; - - int scale; - if (scaleX < scaleY) - { - scale = scaleX; - } - else - { - scale = scaleY; - } - - if (scale > 1) - { - sbyte[][] scaledMatrix = - encoder.BarcodeMatrix.getScaledMatrix(scale*lineThickness, scale*aspectRatio*lineThickness); - if (rotated) - { - scaledMatrix = rotateArray(scaledMatrix); - } - return bitMatrixFrombitArray(scaledMatrix, margin); - } - return bitMatrixFrombitArray(originalScale, margin); - } - - /// - /// This takes an array holding the values of the PDF 417 - /// - /// a byte array of information with 0 is black, and 1 is white - /// border around the barcode - /// BitMatrix of the input - private static BitMatrix bitMatrixFrombitArray(sbyte[][] input, int margin) - { - // Creates the bitmatrix with extra space for whitespace - var output = new BitMatrix(input[0].Length + 2 * margin, input.Length + 2 * margin); - var yOutput = output.Height - margin - 1; - for (int y = 0; y < input.Length; y++) - { - var currentInput = input[y]; - var currentInputLength = currentInput.Length; - for (int x = 0; x < currentInputLength; x++) - { - // Zero is white in the bytematrix - if (currentInput[x] == 1) - { - output[x + margin, yOutput] = true; - } - } - yOutput--; - } - return output; - } - - /// - /// Takes and rotates the it 90 degrees - /// - private static sbyte[][] rotateArray(sbyte[][] bitarray) - { - sbyte[][] temp = new sbyte[bitarray[0].Length][]; - for (int idx = 0; idx < bitarray[0].Length; idx++) - temp[idx] = new sbyte[bitarray.Length]; - for (int ii = 0; ii < bitarray.Length; ii++) - { - // This makes the direction consistent on screen when rotating the - // screen; - int inverseii = bitarray.Length - ii - 1; - for (int jj = 0; jj < bitarray[0].Length; jj++) - { - temp[jj][inverseii] = bitarray[ii][jj]; - } - } - return temp; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/BarcodeMetadata.cs b/zxing.core/xx/pdf417/decoder/BarcodeMetadata.cs deleted file mode 100644 index bfbf510..0000000 --- a/zxing.core/xx/pdf417/decoder/BarcodeMetadata.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal -{ - /// - /// Metadata about a PDF417 Barcode - /// - /// Guenther Grau - public sealed class BarcodeMetadata - { - public int ColumnCount { get; private set; } - public int ErrorCorrectionLevel { get; private set; } - public int RowCountUpper { get; private set; } - public int RowCountLower { get; private set; } - public int RowCount { get; private set; } - - public BarcodeMetadata(int columnCount, int rowCountUpperPart, int rowCountLowerPart, int errorCorrectionLevel) - { - this.ColumnCount = columnCount; - this.ErrorCorrectionLevel = errorCorrectionLevel; - this.RowCountUpper = rowCountUpperPart; - this.RowCountLower = rowCountLowerPart; - this.RowCount = rowCountLowerPart + rowCountUpperPart; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/BarcodeValue.cs b/zxing.core/xx/pdf417/decoder/BarcodeValue.cs deleted file mode 100644 index 97a92a8..0000000 --- a/zxing.core/xx/pdf417/decoder/BarcodeValue.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Collections.Generic; - -namespace ZXing.PDF417.Internal -{ - /// - /// A Barcode Value for the PDF417 barcode. - /// The scanner will iterate through the bitmatrix, - /// and given the different methods or iterations - /// will increment a given barcode value's confidence. - /// - /// When done, this will return the values of highest confidence. - /// - /// Guenther Grau - public sealed class BarcodeValue - { - private readonly IDictionary values = new Dictionary(); - - /// - /// Incremenets the Confidence for a given value. (Adds an occurance of a value) - /// - /// - /// Value. - public void setValue(int @value) - { - int confidence; - values.TryGetValue(@value, out confidence); - confidence++; - values[@value] = confidence; - } - - /// - /// Determines the maximum occurrence of a set value and returns all values which were set with this occurrence. - /// - /// an array of int, containing the values with the highest occurrence, or null, if no value was set. - public int[] getValue() - { - int maxConfidence = -1; - List result = new List(); - foreach (var entry in values) - { - if (entry.Value > maxConfidence) - { - maxConfidence = entry.Value; - result.Clear(); - result.Add(entry.Key); - } - else if (entry.Value == maxConfidence) - { - result.Add(entry.Key); - } - } - return result.ToArray(); - } - - /// - /// Returns the confience value for a given barcode value - /// - /// Barcode value. - public int getConfidence(int barcodeValue) - { - return values.ContainsKey(barcodeValue) ? values[barcodeValue] : 0; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/BoundingBox.cs b/zxing.core/xx/pdf417/decoder/BoundingBox.cs deleted file mode 100644 index 3441826..0000000 --- a/zxing.core/xx/pdf417/decoder/BoundingBox.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; - -namespace ZXing.PDF417.Internal -{ - /// - /// A Bounding Box helper class - /// - /// Guenther Grau - public sealed class BoundingBox - { - private readonly BitMatrix image; - - public ResultPoint TopLeft { get; private set; } - public ResultPoint TopRight { get; private set; } - public ResultPoint BottomLeft { get; private set; } - public ResultPoint BottomRight { get; private set; } - - public int MinX { get; private set; } - public int MaxX { get; private set; } - public int MinY { get; private set; } - public int MaxY { get; private set; } - - /// - /// Initializes a new instance of the class. - /// returns null if the corner points don't match up correctly - /// - /// The image. - /// The top left. - /// The bottom left. - /// The top right. - /// The bottom right. - /// - public static BoundingBox Create(BitMatrix image, - ResultPoint topLeft, - ResultPoint bottomLeft, - ResultPoint topRight, - ResultPoint bottomRight) - { - if ((topLeft == null && topRight == null) || - (bottomLeft == null && bottomRight == null) || - (topLeft != null && bottomLeft == null) || - (topRight != null && bottomRight == null)) - { - return null; - } - - return new BoundingBox(image, topLeft, bottomLeft,topRight, bottomRight); - } - - /// - /// Creates the specified box. - /// - /// The box. - /// - public static BoundingBox Create(BoundingBox box) - { - return new BoundingBox(box.image, box.TopLeft, box.BottomLeft, box.TopRight, box.BottomRight); - } - - /// - /// Initializes a new instance of the class. - /// Will throw an exception if the corner points don't match up correctly - /// - /// Image. - /// Top left. - /// Top right. - /// Bottom left. - /// Bottom right. - private BoundingBox(BitMatrix image, - ResultPoint topLeft, - ResultPoint bottomLeft, - ResultPoint topRight, - ResultPoint bottomRight) - { - this.image = image; - this.TopLeft = topLeft; - this.TopRight = topRight; - this.BottomLeft = bottomLeft; - this.BottomRight = bottomRight; - calculateMinMaxValues(); - } - - /// - /// Merge two Bounding Boxes, getting the left corners of left, and the right corners of right - /// (Images should be the same) - /// - /// Left. - /// Right. - internal static BoundingBox merge(BoundingBox leftBox, BoundingBox rightBox) - { - if (leftBox == null) - return rightBox; - if (rightBox == null) - return leftBox; - return new BoundingBox(leftBox.image, leftBox.TopLeft, leftBox.BottomLeft, rightBox.TopRight, rightBox.BottomRight); - } - - /// - /// Adds the missing rows. - /// - /// The missing rows. - /// Missing start rows. - /// Missing end rows. - /// If set to true is left. - public BoundingBox addMissingRows(int missingStartRows, int missingEndRows, bool isLeft) - { - ResultPoint newTopLeft = TopLeft; - ResultPoint newBottomLeft = BottomLeft; - ResultPoint newTopRight = TopRight; - ResultPoint newBottomRight = BottomRight; - - if (missingStartRows > 0) - { - ResultPoint top = isLeft ? TopLeft : TopRight; - int newMinY = (int) top.Y - missingStartRows; - if (newMinY < 0) - { - newMinY = 0; - } - // TODO use existing points to better interpolate the new x positions - ResultPoint newTop = new ResultPoint(top.X, newMinY); - if (isLeft) - { - newTopLeft = newTop; - } - else - { - newTopRight = newTop; - } - } - - if (missingEndRows > 0) - { - ResultPoint bottom = isLeft ? BottomLeft : BottomRight; - int newMaxY = (int) bottom.Y + missingEndRows; - if (newMaxY >= image.Height) - { - newMaxY = image.Height - 1; - } - // TODO use existing points to better interpolate the new x positions - ResultPoint newBottom = new ResultPoint(bottom.X, newMaxY); - if (isLeft) - { - newBottomLeft = newBottom; - } - else - { - newBottomRight = newBottom; - } - } - - calculateMinMaxValues(); - return new BoundingBox(image, newTopLeft, newBottomLeft, newTopRight, newBottomRight); - } - - /// - /// Calculates the minimum and maximum X & Y values based on the corner points. - /// - private void calculateMinMaxValues() - { - // Constructor ensures that either Left or Right is not null - if (TopLeft == null) - { - TopLeft = new ResultPoint(0, TopRight.Y); - BottomLeft = new ResultPoint(0, BottomRight.Y); - } - else if (TopRight == null) - { - TopRight = new ResultPoint(image.Width - 1, TopLeft.Y); - BottomRight = new ResultPoint(image.Width - 1, TopLeft.Y); - } - - MinX = (int) Math.Min(TopLeft.X, BottomLeft.X); - MaxX = (int) Math.Max(TopRight.X, BottomRight.X); - MinY = (int) Math.Min(TopLeft.Y, TopRight.Y); - MaxY = (int) Math.Max(BottomLeft.Y, BottomRight.Y); - - } - - /// - /// If we adjust the width, set a new right corner coordinate and recalculate - /// - /// Bottom right. - internal void SetBottomRight(ResultPoint bottomRight) - { - this.BottomRight = bottomRight; - calculateMinMaxValues(); - } - /* - /// - /// If we adjust the width, set a new right corner coordinate and recalculate - /// - /// Top right. - internal void SetTopRight(ResultPoint topRight) - { - this.TopRight = topRight; - calculateMinMaxValues(); - } - */ - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/Codeword.cs b/zxing.core/xx/pdf417/decoder/Codeword.cs deleted file mode 100644 index b60237e..0000000 --- a/zxing.core/xx/pdf417/decoder/Codeword.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal -{ - /// - /// A Codeword in the PDF417 barcode - /// - /// Guenther Grau - public sealed class Codeword - { - /// - /// Default value for the RowNumber (-1 being an invalid real number) - /// - private static readonly int BARCODE_ROW_UNKNOWN = -1; - - public int StartX { get; private set; } - public int EndX { get; private set; } - public int Bucket { get; private set; } - public int Value { get; private set; } - public int RowNumber { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// Start x. - /// End x. - /// Bucket. - /// Value. - public Codeword(int startX, int endX, int bucket, int value) - { - this.StartX = startX; - this.EndX = endX; - this.Bucket = bucket; - this.Value = value; - this.RowNumber = BARCODE_ROW_UNKNOWN; - } - - /// - /// Gets the width. - /// - /// The width. - public int Width - { - get { return EndX - StartX; } - } - - /// - /// Gets a value indicating whether this instance has valid row number. - /// - /// true if this instance has valid row number; otherwise, false. - public bool HasValidRowNumber - { - get { return IsValidRowNumber(RowNumber); } - } - - /// - /// Determines whether this instance is valid row number the specified rowNumber. - /// - /// true if this instance is valid row number the specified rowNumber; otherwise, false. - /// Row number. - public bool IsValidRowNumber(int rowNumber) - { - return rowNumber != BARCODE_ROW_UNKNOWN && Bucket == (rowNumber%3)*3; - } - - /// - /// Sets the row number as the row's indicator column. - /// - public void setRowNumberAsRowIndicatorColumn() - { - this.RowNumber = (Value/30)*3 + Bucket/3; - } - - /// - /// Returns a that represents the current . - /// - /// A that represents the current . - public override string ToString() - { - return RowNumber + "|" + Value; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/DecodedBitStreamParser.cs b/zxing.core/xx/pdf417/decoder/DecodedBitStreamParser.cs deleted file mode 100644 index 036b6ad..0000000 --- a/zxing.core/xx/pdf417/decoder/DecodedBitStreamParser.cs +++ /dev/null @@ -1,808 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Text; -using System.Numerics; - -using ZXing.Common; - -namespace ZXing.PDF417.Internal -{ - /// - ///

This class contains the methods for decoding the PDF417 codewords.

- /// - /// SITA Lab (kevin.osullivan@sita.aero) - ///
- internal static class 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 ECI_USER_DEFINED = 925; - private const int ECI_GENERAL_PURPOSE = 926; - private const int ECI_CHARSET = 927; - 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 BigInteger[] EXP900; - static DecodedBitStreamParser() - { - EXP900 = new BigInteger[16]; - EXP900[0] = BigInteger.One; - BigInteger nineHundred = new BigInteger(900); - EXP900[1] = nineHundred; - for (int i = 2; i < EXP900.Length; i++) - { - EXP900[i] = BigInteger.Multiply(EXP900[i - 1], nineHundred); - } - } - private const int NUMBER_OF_SEQUENCE_CODEWORDS = 2; - - internal static DecoderResult decode(int[] codewords, String ecLevel) - { - var result = new StringBuilder(codewords.Length * 2); - // Get compaction mode - int codeIndex = 1; - int code = codewords[codeIndex++]; - var resultMetadata = new PDF417ResultMetadata(); - Encoding encoding = null; - - while (codeIndex < codewords[0]) - { - switch (code) - { - case TEXT_COMPACTION_MODE_LATCH: - codeIndex = textCompaction(codewords, codeIndex, result); - break; - case BYTE_COMPACTION_MODE_LATCH: - case BYTE_COMPACTION_MODE_LATCH_6: - codeIndex = byteCompaction(code, codewords, encoding ?? (encoding = getEncoding(PDF417HighLevelEncoder.DEFAULT_ENCODING_NAME)), codeIndex, result); - break; - case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: - result.Append((char)codewords[codeIndex++]); - break; - case NUMERIC_COMPACTION_MODE_LATCH: - codeIndex = numericCompaction(codewords, codeIndex, result); - break; - case ECI_CHARSET: - var charsetECI = CharacterSetECI.getCharacterSetECIByValue(codewords[codeIndex++]); - encoding = getEncoding(charsetECI.EncodingName); - break; - case ECI_GENERAL_PURPOSE: - // Can't do anything with generic ECI; skip its 2 characters - codeIndex += 2; - break; - case ECI_USER_DEFINED: - // Can't do anything with user ECI; skip its 1 character - codeIndex++; - break; - case BEGIN_MACRO_PDF417_CONTROL_BLOCK: - codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata); - break; - case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: - case MACRO_PDF417_TERMINATOR: - // Should not see these outside a macro block - return null; - 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 < 0) - return null; - if (codeIndex < codewords.Length) - { - code = codewords[codeIndex++]; - } - else - { - return null; - } - } - - if (result.Length == 0) - { - return null; - } - - var decoderResult = new DecoderResult(null, result.ToString(), null, ecLevel); - decoderResult.Other = resultMetadata; - return decoderResult; - } - - private static Encoding getEncoding(string encodingName) - { - Encoding encoding = null; - - try - { - encoding = Encoding.GetEncoding(encodingName); - } -#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) - catch (ArgumentException) - { - try - { - // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 - encoding = Encoding.GetEncoding("UTF-8"); - } - catch (Exception) - { - } - } -#endif -#if WindowsCE - catch (PlatformNotSupportedException) - { - try - { - // WindowsCE doesn't support all encodings. But it is device depended. - // So we try here the some different ones - if (encodingName == "ISO-8859-1") - { - encoding = Encoding.GetEncoding(1252); - } - else - { - encoding = Encoding.GetEncoding("UTF-8"); - } - } - catch (Exception) - { - } - } -#endif - catch (Exception) - { - return null; - } - - return encoding; - } - - private static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata) - { - if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) - { - // we must have at least two bytes left for the segment index - return -1; - } - int[] segmentIndexArray = new int[NUMBER_OF_SEQUENCE_CODEWORDS]; - for (int i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) - { - segmentIndexArray[i] = codewords[codeIndex]; - } - String s = decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS); - if (s == null) - return -1; - resultMetadata.SegmentIndex = Int32.Parse(s); - - StringBuilder fileId = new StringBuilder(); - codeIndex = textCompaction(codewords, codeIndex, fileId); - resultMetadata.FileId = fileId.ToString(); - - if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) - { - codeIndex++; - int[] additionalOptionCodeWords = new int[codewords[0] - codeIndex]; - int additionalOptionCodeWordsIndex = 0; - - bool end = false; - while ((codeIndex < codewords[0]) && !end) - { - int code = codewords[codeIndex++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - additionalOptionCodeWords[additionalOptionCodeWordsIndex++] = code; - } - else - { - switch (code) - { - case MACRO_PDF417_TERMINATOR: - resultMetadata.IsLastSegment = true; - codeIndex++; - end = true; - break; - default: - return -1; - } - } - } - resultMetadata.OptionalData = new int[additionalOptionCodeWordsIndex]; - Array.Copy(additionalOptionCodeWords, resultMetadata.OptionalData, additionalOptionCodeWordsIndex); - } - else if (codewords[codeIndex] == MACRO_PDF417_TERMINATOR) - { - resultMetadata.IsLastSegment = true; - codeIndex++; - } - - return codeIndex; - } - - /// - /// 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] - codeIndex) << 1]; - // Used to hold the byte compaction value if there is a mode shift - int[] byteCompactionData = new int[(codewords[0] - codeIndex) << 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: - case BYTE_COMPACTION_MODE_LATCH_6: - case NUMERIC_COMPACTION_MODE_LATCH: - case BEGIN_MACRO_PDF417_CONTROL_BLOCK: - case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: - case MACRO_PDF417_TERMINATOR: - 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; - index++; - 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 = null; - switch (subMode) - { - case 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) - { - // TODO Does this need to use the current character encoding? See other occurrences below - result.Append((char)byteCompactionData[i]); - } - else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) - { - subMode = Mode.ALPHA; - } - } - break; - - case 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 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 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 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 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 != null) - { - // Append decoded character to result - result.Append(ch.Value); - } - 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) - /// Currently active character encoding - /// 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, Encoding encoding, int codeIndex, StringBuilder result) - { - var decodedBytes = new System.IO.MemoryStream(); - 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; - 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) - { - decodedBytes.WriteByte((byte)(value >> (8 * (5 - j)))); - } - value = 0; - 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++) - { - decodedBytes.WriteByte((byte)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++]; - if (code < TEXT_COMPACTION_MODE_LATCH) - { - count++; - // Base 900 - value = 900 * value + 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) - { - decodedBytes.WriteByte((byte)(value >> (8 * (5 - j)))); - } - value = 0; - count = 0; - } - } - } - var bytes = decodedBytes.ToArray(); - result.Append(encoding.GetString(bytes, 0, bytes.Length)); - 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. - /// - 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) - { - 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) - { - codeIndex--; - end = true; - } - } - 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. - if (count > 0) - { - String s = decodeBase900toBase10(numericCodewords, count); - if (s == null) - return -1; - result.Append(s); - count = 0; - } - } - } - return codeIndex; - } - - /// - /// Convert a list of Numeric Compacted codewords from Base 900 to Base 10. - /// 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 - /// The array of codewords - /// The number of codewords - /// The decoded string representing the Numeric data. - /// - private static String decodeBase900toBase10(int[] codewords, int count) - { - BigInteger result = BigInteger.Zero; - for (int i = 0; i < count; i++) - { - result = BigInteger.Add(result, BigInteger.Multiply(EXP900[count - i - 1], new BigInteger(codewords[i]))); - } - String resultString = result.ToString(); - if (resultString[0] != '1') - { - return null; - } - return resultString.Substring(1); - } - } -} diff --git a/zxing.core/xx/pdf417/decoder/DetectionResult.cs b/zxing.core/xx/pdf417/decoder/DetectionResult.cs deleted file mode 100644 index 207a316..0000000 --- a/zxing.core/xx/pdf417/decoder/DetectionResult.cs +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Globalization; -using System.Text; - -namespace ZXing.PDF417.Internal -{ - /// - /// - /// - /// Guenther Grau - public class DetectionResult - { - private const int ADJUST_ROW_NUMBER_SKIP = 2; - - public BarcodeMetadata Metadata { get; private set; } - public DetectionResultColumn[] DetectionResultColumns { get; set; } - public BoundingBox Box { get; set; } - public int ColumnCount { get; private set; } - - public int RowCount - { - get { return Metadata.RowCount; } - } - - public int ErrorCorrectionLevel - { - get { return Metadata.ErrorCorrectionLevel; } - } - - public DetectionResult(BarcodeMetadata metadata, BoundingBox box) - { - Metadata = metadata; - Box = box; - ColumnCount = metadata.ColumnCount; - DetectionResultColumns = new DetectionResultColumn[ColumnCount + 2]; - } - - /// - /// Returns the DetectionResult Columns. This does a fair bit of calculation, so call it sparingly. - /// - /// The detection result columns. - public DetectionResultColumn[] getDetectionResultColumns() - { - adjustIndicatorColumnRowNumbers(DetectionResultColumns[0]); - adjustIndicatorColumnRowNumbers(DetectionResultColumns[ColumnCount + 1]); - int unadjustedCodewordCount = PDF417Common.MAX_CODEWORDS_IN_BARCODE; - int previousUnadjustedCount; - do - { - previousUnadjustedCount = unadjustedCodewordCount; - unadjustedCodewordCount = adjustRowNumbers(); - } while (unadjustedCodewordCount > 0 && unadjustedCodewordCount < previousUnadjustedCount); - return DetectionResultColumns; - } - - /// - /// Adjusts the indicator column row numbers. - /// - /// Detection result column. - private void adjustIndicatorColumnRowNumbers(DetectionResultColumn detectionResultColumn) - { - if (detectionResultColumn != null) - { - ((DetectionResultRowIndicatorColumn) detectionResultColumn) - .adjustCompleteIndicatorColumnRowNumbers(Metadata); - } - } - - /// - /// return number of codewords which don't have a valid row number. Note that the count is not accurate as codewords . - /// will be counted several times. It just serves as an indicator to see when we can stop adjusting row numbers - /// - /// The row numbers. - private int adjustRowNumbers() - { - // TODO ensure that no detected codewords with unknown row number are left - // we should be able to estimate the row height and use it as a hint for the row number - // we should also fill the rows top to bottom and bottom to top - int unadjustedCount = adjustRowNumbersByRow(); - if (unadjustedCount == 0) - { - return 0; - } - for (int barcodeColumn = 1; barcodeColumn < ColumnCount + 1; barcodeColumn++) - { - Codeword[] codewords = DetectionResultColumns[barcodeColumn].Codewords; - for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++) - { - if (codewords[codewordsRow] == null) - { - continue; - } - if (!codewords[codewordsRow].HasValidRowNumber) - { - adjustRowNumbers(barcodeColumn, codewordsRow, codewords); - } - } - } - return unadjustedCount; - } - - /// - /// Adjusts the row numbers by row. - /// - /// The row numbers by row. - private int adjustRowNumbersByRow() - { - adjustRowNumbersFromBothRI(); // RI = RowIndicators - // TODO we should only do full row adjustments if row numbers of left and right row indicator column match. - // Maybe it's even better to calculated the height (in codeword rows) and divide it by the number of barcode - // rows. This, together with the LRI and RRI row numbers should allow us to get a good estimate where a row - // number starts and ends. - int unadjustedCount = adjustRowNumbersFromLRI(); - return unadjustedCount + adjustRowNumbersFromRRI(); - } - - /// - /// Adjusts the row numbers from both Row Indicators - /// - /// zero - private void adjustRowNumbersFromBothRI() - { - if (DetectionResultColumns[0] == null || DetectionResultColumns[ColumnCount + 1] == null) - { - return; - } - Codeword[] LRIcodewords = DetectionResultColumns[0].Codewords; - Codeword[] RRIcodewords = DetectionResultColumns[ColumnCount + 1].Codewords; - for (int codewordsRow = 0; codewordsRow < LRIcodewords.Length; codewordsRow++) - { - if (LRIcodewords[codewordsRow] != null && - RRIcodewords[codewordsRow] != null && - LRIcodewords[codewordsRow].RowNumber == RRIcodewords[codewordsRow].RowNumber) - { - for (int barcodeColumn = 1; barcodeColumn <= ColumnCount; barcodeColumn++) - { - Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; - if (codeword == null) - { - continue; - } - codeword.RowNumber = LRIcodewords[codewordsRow].RowNumber; - if (!codeword.HasValidRowNumber) - { - // LOG.info("Removing codeword with invalid row number, cw[" + codewordsRow + "][" + barcodeColumn + "]"); - DetectionResultColumns[barcodeColumn].Codewords[codewordsRow] = null; - } - } - } - } - } - - /// - /// Adjusts the row numbers from Right Row Indicator. - /// - /// The unadjusted row count. - private int adjustRowNumbersFromRRI() - { - if (DetectionResultColumns[ColumnCount + 1] == null) - { - return 0; - } - int unadjustedCount = 0; - Codeword[] codewords = DetectionResultColumns[ColumnCount + 1].Codewords; - for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++) - { - if (codewords[codewordsRow] == null) - { - continue; - } - int rowIndicatorRowNumber = codewords[codewordsRow].RowNumber; - int invalidRowCounts = 0; - for (int barcodeColumn = ColumnCount + 1; barcodeColumn > 0 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn--) - { - Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; - if (codeword != null) - { - invalidRowCounts = adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword); - if (!codeword.HasValidRowNumber) - { - unadjustedCount++; - } - } - } - } - return unadjustedCount; - } - - /// - /// Adjusts the row numbers from Left Row Indicator. - /// - /// Unadjusted row Count. - private int adjustRowNumbersFromLRI() - { - if (DetectionResultColumns[0] == null) - { - return 0; - } - int unadjustedCount = 0; - Codeword[] codewords = DetectionResultColumns[0].Codewords; - for (int codewordsRow = 0; codewordsRow < codewords.Length; codewordsRow++) - { - if (codewords[codewordsRow] == null) - { - continue; - } - int rowIndicatorRowNumber = codewords[codewordsRow].RowNumber; - int invalidRowCounts = 0; - for (int barcodeColumn = 1; barcodeColumn < ColumnCount + 1 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn++) - { - Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; - if (codeword != null) - { - invalidRowCounts = adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword); - if (!codeword.HasValidRowNumber) - { - unadjustedCount++; - } - } - } - } - return unadjustedCount; - } - - /// - /// Adjusts the row number if valid. - /// - /// The invalid rows - /// Row indicator row number. - /// Invalid row counts. - /// Codeword. - private static int adjustRowNumberIfValid(int rowIndicatorRowNumber, int invalidRowCounts, Codeword codeword) - { - - if (codeword == null) - { - return invalidRowCounts; - } - if (!codeword.HasValidRowNumber) - { - if (codeword.IsValidRowNumber(rowIndicatorRowNumber)) - { - codeword.RowNumber = rowIndicatorRowNumber; - invalidRowCounts = 0; - } - else - { - ++invalidRowCounts; - } - } - return invalidRowCounts; - } - - /// - /// Adjusts the row numbers. - /// - /// Barcode column. - /// Codewords row. - /// Codewords. - private void adjustRowNumbers(int barcodeColumn, int codewordsRow, Codeword[] codewords) - { - Codeword codeword = codewords[codewordsRow]; - Codeword[] previousColumnCodewords = DetectionResultColumns[barcodeColumn - 1].Codewords; - Codeword[] nextColumnCodewords = previousColumnCodewords; - if (DetectionResultColumns[barcodeColumn + 1] != null) - { - nextColumnCodewords = DetectionResultColumns[barcodeColumn + 1].Codewords; - } - - Codeword[] otherCodewords = new Codeword[14]; - - otherCodewords[2] = previousColumnCodewords[codewordsRow]; - otherCodewords[3] = nextColumnCodewords[codewordsRow]; - - if (codewordsRow > 0) - { - otherCodewords[0] = codewords[codewordsRow - 1]; - otherCodewords[4] = previousColumnCodewords[codewordsRow - 1]; - otherCodewords[5] = nextColumnCodewords[codewordsRow - 1]; - } - if (codewordsRow > 1) - { - otherCodewords[8] = codewords[codewordsRow - 2]; - otherCodewords[10] = previousColumnCodewords[codewordsRow - 2]; - otherCodewords[11] = nextColumnCodewords[codewordsRow - 2]; - } - if (codewordsRow < codewords.Length - 1) - { - otherCodewords[1] = codewords[codewordsRow + 1]; - otherCodewords[6] = previousColumnCodewords[codewordsRow + 1]; - otherCodewords[7] = nextColumnCodewords[codewordsRow + 1]; - } - if (codewordsRow < codewords.Length - 2) - { - otherCodewords[9] = codewords[codewordsRow + 2]; - otherCodewords[12] = previousColumnCodewords[codewordsRow + 2]; - otherCodewords[13] = nextColumnCodewords[codewordsRow + 2]; - } - foreach (Codeword otherCodeword in otherCodewords) - { - if (adjustRowNumber(codeword, otherCodeword)) - { - return; - } - } - } - - /// - /// Adjusts the row number. - /// - /// true, if row number was adjusted, false otherwise. - /// Codeword. - /// Other codeword. - private static bool adjustRowNumber(Codeword codeword, Codeword otherCodeword) - { - if (otherCodeword == null) - { - return false; - } - if (otherCodeword.HasValidRowNumber && otherCodeword.Bucket == codeword.Bucket) - { - codeword.RowNumber = otherCodeword.RowNumber; - return true; - } - return false; - } - - /// - /// Returns a that represents the current . - /// - /// A that represents the current . - public override string ToString() - { - StringBuilder formatter = new StringBuilder(); - DetectionResultColumn rowIndicatorColumn = DetectionResultColumns[0]; - if (rowIndicatorColumn == null) - { - rowIndicatorColumn = DetectionResultColumns[ColumnCount + 1]; - } - for (int codewordsRow = 0; codewordsRow < rowIndicatorColumn.Codewords.Length; codewordsRow++) - { - formatter.AppendFormat(CultureInfo.InvariantCulture, "CW {0,3}:", codewordsRow); - for (int barcodeColumn = 0; barcodeColumn < ColumnCount + 2; barcodeColumn++) - { - if (DetectionResultColumns[barcodeColumn] == null) - { - formatter.Append(" | "); - continue; - } - Codeword codeword = DetectionResultColumns[barcodeColumn].Codewords[codewordsRow]; - if (codeword == null) - { - formatter.Append(" | "); - continue; - } - formatter.AppendFormat(CultureInfo.InvariantCulture, " {0,3}|{1,3}", codeword.RowNumber, codeword.Value); - } - formatter.Append("\n"); - } - - return formatter.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/DetectionResultColumn.cs b/zxing.core/xx/pdf417/decoder/DetectionResultColumn.cs deleted file mode 100644 index 2afa897..0000000 --- a/zxing.core/xx/pdf417/decoder/DetectionResultColumn.cs +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Globalization; -using System.Text; - -namespace ZXing.PDF417.Internal -{ - /// - /// Represents a Column in the Detection Result - /// - /// Guenther Grau - public class DetectionResultColumn - { - /// - /// The maximum distance to search in the codeword array in both the positive and negative directions - /// - private const int MAX_NEARBY_DISTANCE = 5; - - /// - /// The Bounding Box around the column (in the BitMatrix) - /// - /// The box. - public BoundingBox Box { get; private set; } - - /// - /// The Codewords the Box encodes for, offset by the Box minY. - /// Remember to Access this ONLY through GetCodeword(imageRow) if you're accessing it in that manner. - /// - /// The codewords. - public Codeword[] Codewords { get; set; } - - // TODO convert this to a dictionary? Dictionary ?? - - /// - /// Initializes a new instance of the class. - /// - /// The Bounding Box around the column (in the BitMatrix) - public DetectionResultColumn(BoundingBox box) - { - this.Box = BoundingBox.Create(box); - this.Codewords = new Codeword[Box.MaxY - Box.MinY + 1]; - } - - /// - /// Converts the Image's Row to the index in the Codewords array - /// - /// The Codeword Index. - /// Image row. - public int IndexForRow(int imageRow) - { - return imageRow - Box.MinY; - } - - /// - /// Converts the Codeword array index into a Row in the Image (BitMatrix) - /// - /// The Image Row. - /// Codeword index. - public int RowForIndex(int codewordIndex) - { - return Box.MinY + codewordIndex; - } - - /// - /// Gets the codeword for a given row - /// - /// The codeword. - /// Image row. - public Codeword getCodeword(int imageRow) - { - return Codewords[imageRowToCodewordIndex(imageRow)]; - } - - /// - /// Gets the codeword closest to the specified row in the image - /// - /// Image row. - public Codeword getCodewordNearby(int imageRow) - { - Codeword codeword = getCodeword(imageRow); - if (codeword != null) - { - return codeword; - } - for (int i = 1; i < MAX_NEARBY_DISTANCE; i++) - { - int nearImageRow = imageRowToCodewordIndex(imageRow) - i; - if (nearImageRow >= 0) - { - codeword = Codewords[nearImageRow]; - if (codeword != null) - { - return codeword; - } - } - nearImageRow = imageRowToCodewordIndex(imageRow) + i; - if (nearImageRow < Codewords.Length) - { - codeword = Codewords[nearImageRow]; - if (codeword != null) - { - return codeword; - } - } - } - return null; - } - - internal int imageRowToCodewordIndex(int imageRow) - { - return imageRow - Box.MinY; - } - - /// - /// Sets the codeword for an image row - /// - /// Image row. - /// Codeword. - public void setCodeword(int imageRow, Codeword codeword) - { - Codewords[IndexForRow(imageRow)] = codeword; - } - - /// - /// Returns a that represents the current . - /// - /// A that represents the current . - public override string ToString() - { - StringBuilder builder = new StringBuilder(); - int row = 0; - foreach (var cw in Codewords) - { - if (cw == null) - { - builder.AppendFormat(CultureInfo.InvariantCulture, "{0,3}: | \n", row++); - } - else - { - builder.AppendFormat(CultureInfo.InvariantCulture, "{0,3}: {1,3}|{2,3}\n", row++, cw.RowNumber, cw.Value); - } - } - return builder.ToString(); - // return "Valid Codewords: " + (from cw in Codewords where cw != null select cw).Count().ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/DetectionResultRowIndicatorColumn.cs b/zxing.core/xx/pdf417/decoder/DetectionResultRowIndicatorColumn.cs deleted file mode 100644 index e710d1e..0000000 --- a/zxing.core/xx/pdf417/decoder/DetectionResultRowIndicatorColumn.cs +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal -{ - /// - /// Represents a Column in the Detection Result - /// - /// Guenther Grau - public sealed class DetectionResultRowIndicatorColumn : DetectionResultColumn - { - /// - /// Gets or sets a value indicating whether this instance is the left indicator - /// - /// true if this instance is left; otherwise, false. - public bool IsLeft { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// Box. - /// If set to true is left. - public DetectionResultRowIndicatorColumn(BoundingBox box, bool isLeft) - : base(box) - { - this.IsLeft = isLeft; - } - - /// - /// Sets the Row Numbers as Inidicator Columns - /// - public void setRowNumbers() - { - foreach (var cw in Codewords) - { - if (cw != null) - { - cw.setRowNumberAsRowIndicatorColumn(); - } - } - } - - - /// - /// TODO implement properly - /// TODO maybe we should add missing codewords to store the correct row number to make - /// finding row numbers for other columns easier - /// use row height count to make detection of invalid row numbers more reliable - /// - /// The indicator column row numbers. - /// Metadata. - public int adjustCompleteIndicatorColumnRowNumbers(BarcodeMetadata metadata) - { - var codewords = Codewords; - setRowNumbers(); // Assign this as an indicator column - removeIncorrectCodewords(codewords, metadata); - - ResultPoint top = IsLeft ? Box.TopLeft : Box.TopRight; - ResultPoint bottom = IsLeft ? Box.BottomLeft : Box.BottomRight; - - int firstRow = imageRowToCodewordIndex((int) top.Y); - int lastRow = imageRowToCodewordIndex((int) bottom.Y); - - // We need to be careful using the average row height. - // Barcode could be skewed so that we have smaller and taller rows - float averageRowHeight = (lastRow - firstRow)/(float) metadata.RowCount; - - // initialize loop - int barcodeRow = -1; - int maxRowHeight = 1; - int currentRowHeight = 0; - - for (int codewordRow = firstRow; codewordRow < lastRow; codewordRow++) - { - var codeword = codewords[codewordRow]; - if (codeword == null) - { - continue; - } - - // float expectedRowNumber = (codewordsRow - firstRow) / averageRowHeight; - // if (Math.abs(codeword.getRowNumber() - expectedRowNumber) > 2) { - // SimpleLog.log(LEVEL.WARNING, - // "Removing codeword, rowNumberSkew too high, codeword[" + codewordsRow + "]: Expected Row: " + - // expectedRowNumber + ", RealRow: " + codeword.getRowNumber() + ", value: " + codeword.getValue()); - // codewords[codewordsRow] = null; - // } - - int rowDifference = codeword.RowNumber - barcodeRow; - - // TODO improve handling with case where first row indicator doesn't start with 0 - - if (rowDifference == 0) - { - currentRowHeight++; - } - else if (rowDifference == 1) - { - maxRowHeight = Math.Max(maxRowHeight, currentRowHeight); - currentRowHeight = 1; - barcodeRow = codeword.RowNumber; - } - else if (rowDifference < 0 || - codeword.RowNumber >= metadata.RowCount || - rowDifference > codewordRow) - { - codewords[codewordRow] = null; - } - else - { - int checkedRows; - if (maxRowHeight > 2) - { - checkedRows = (maxRowHeight - 2)*rowDifference; - } - else - { - checkedRows = rowDifference; - } - bool closePreviousCodewordFound = checkedRows > codewordRow; - for (int i = 1; i <= checkedRows && !closePreviousCodewordFound; i++) - { - // there must be (height * rowDifference) number of codewords missing. For now we assume height = 1. - // This should hopefully get rid of most problems already. - closePreviousCodewordFound = codewords[codewordRow - i] != null; - } - if (closePreviousCodewordFound) - { - codewords[codewordRow] = null; - } - else - { - barcodeRow = codeword.RowNumber; - currentRowHeight = 1; - } - } - - } - return (int) (averageRowHeight + 0.5); - } - - /// - /// Gets the row heights. - /// - /// The row heights. - public int[] getRowHeights() - { - BarcodeMetadata barcodeMetadata = getBarcodeMetadata(); - if (barcodeMetadata == null) - { - return null; - } - adjustIncompleteIndicatorColumnRowNumbers(barcodeMetadata); - int[] result = new int[barcodeMetadata.RowCount]; - foreach (var codeword in Codewords) - { - if (codeword != null) - { - int rowNumber = codeword.RowNumber; - if (rowNumber >= result.Length) - { - return null; - } - result[rowNumber]++; - } // else throw exception? (or return null) - } - return result; - } - - /// - /// Adjusts the in omplete indicator column row numbers. - /// - /// Metadata. - public int adjustIncompleteIndicatorColumnRowNumbers(BarcodeMetadata metadata) - { - // TODO maybe we should add missing codewords to store the correct row number to make - // finding row numbers for other columns easier - // use row height count to make detection of invalid row numbers more reliable - - ResultPoint top = IsLeft ? Box.TopLeft : Box.TopRight; - ResultPoint bottom = IsLeft ? Box.BottomLeft : Box.BottomRight; - - int firstRow = imageRowToCodewordIndex((int) top.Y); - int lastRow = imageRowToCodewordIndex((int) bottom.Y); - - // We need to be careful using the average row height. - // Barcode could be skewed so that we have smaller and taller rows - float averageRowHeight = (lastRow - firstRow)/(float) metadata.RowCount; - var codewords = Codewords; - - // initialize loop - int barcodeRow = -1; - int maxRowHeight = 1; - int currentRowHeight = 0; - - for (int codewordRow = firstRow; codewordRow < lastRow; codewordRow++) - { - var codeword = codewords[codewordRow]; - if (codeword == null) - { - continue; - } - - codeword.setRowNumberAsRowIndicatorColumn(); - - int rowDifference = codeword.RowNumber - barcodeRow; - - // TODO improve handling with case where first row indicator doesn't start with 0 - - if (rowDifference == 0) - { - currentRowHeight++; - } - else if (rowDifference == 1) - { - maxRowHeight = Math.Max(maxRowHeight, currentRowHeight); - currentRowHeight = 1; - barcodeRow = codeword.RowNumber; - } - else if (codeword.RowNumber > metadata.RowCount) - { - Codewords[codewordRow] = null; - } - else - { - barcodeRow = codeword.RowNumber; - currentRowHeight = 1; - } - - } - return (int) (averageRowHeight + 0.5); - } - - /// - /// Gets the barcode metadata. - /// - /// The barcode metadata. - public BarcodeMetadata getBarcodeMetadata() - { - var codewords = Codewords; - BarcodeValue barcodeColumnCount = new BarcodeValue(); - BarcodeValue barcodeRowCountUpperPart = new BarcodeValue(); - BarcodeValue barcodeRowCountLowerPart = new BarcodeValue(); - BarcodeValue barcodeECLevel = new BarcodeValue(); - foreach (Codeword codeword in codewords) - { - if (codeword == null) - { - continue; - } - codeword.setRowNumberAsRowIndicatorColumn(); - int rowIndicatorValue = codeword.Value%30; - int codewordRowNumber = codeword.RowNumber; - if (!IsLeft) - { - codewordRowNumber += 2; - } - switch (codewordRowNumber%3) - { - case 0: - barcodeRowCountUpperPart.setValue(rowIndicatorValue*3 + 1); - break; - case 1: - barcodeECLevel.setValue(rowIndicatorValue/3); - barcodeRowCountLowerPart.setValue(rowIndicatorValue%3); - break; - case 2: - barcodeColumnCount.setValue(rowIndicatorValue + 1); - break; - } - } - // Maybe we should check if we have ambiguous values? - var barcodeColumnCountValues = barcodeColumnCount.getValue(); - var barcodeRowCountUpperPartValues = barcodeRowCountUpperPart.getValue(); - var barcodeRowCountLowerPartValues = barcodeRowCountLowerPart.getValue(); - var barcodeECLevelValues = barcodeECLevel.getValue(); - if ((barcodeColumnCountValues.Length == 0) || - (barcodeRowCountUpperPartValues.Length == 0) || - (barcodeRowCountLowerPartValues.Length == 0) || - (barcodeECLevelValues.Length == 0) || - barcodeColumnCountValues[0] < 1 || - barcodeRowCountUpperPartValues[0] + barcodeRowCountLowerPartValues[0] < PDF417Common.MIN_ROWS_IN_BARCODE || - barcodeRowCountUpperPartValues[0] + barcodeRowCountLowerPartValues[0] > PDF417Common.MAX_ROWS_IN_BARCODE) - { - return null; - } - var barcodeMetadata = new BarcodeMetadata(barcodeColumnCountValues[0], - barcodeRowCountUpperPartValues[0], - barcodeRowCountLowerPartValues[0], - barcodeECLevelValues[0]); - removeIncorrectCodewords(codewords, barcodeMetadata); - return barcodeMetadata; - } - - /// - /// Prune the codewords which do not match the metadata - /// TODO Maybe we should keep the incorrect codewords for the start and end positions? - /// - /// Codewords. - /// Metadata. - private void removeIncorrectCodewords(Codeword[] codewords, BarcodeMetadata metadata) - { - for (int row = 0; row < codewords.Length; row++) - { - var codeword = codewords[row]; - if (codeword == null) - continue; - - int indicatorValue = codeword.Value%30; - int rowNumber = codeword.RowNumber; - - // Row does not exist in the metadata - if (rowNumber >= metadata.RowCount) // different to java rowNumber > metadata.RowCount - { - codewords[row] = null; // remove this. - continue; - } - - if (!IsLeft) - { - rowNumber += 2; - } - - switch (rowNumber%3) - { - default: - case 0: - if (indicatorValue*3 + 1 != metadata.RowCountUpper) - { - codewords[row] = null; - } - break; - - case 1: - if (indicatorValue%3 != metadata.RowCountLower || - indicatorValue/3 != metadata.ErrorCorrectionLevel) - { - codewords[row] = null; - } - break; - - case 2: - if (indicatorValue + 1 != metadata.ColumnCount) - { - codewords[row] = null; - } - break; - } - - } - } - - /// - /// Returns a that represents the current . - /// - /// A that represents the current . - public override string ToString() - { - return "Is Left: " + IsLeft + " \n" + base.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/PDF417CodewordDecoder.cs b/zxing.core/xx/pdf417/decoder/PDF417CodewordDecoder.cs deleted file mode 100644 index b43cad3..0000000 --- a/zxing.core/xx/pdf417/decoder/PDF417CodewordDecoder.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal -{ - /// - /// - /// - /// Guenther Grau - /// creatale GmbH (christoph.schulz@creatale.de) - public static class PDF417CodewordDecoder - { - /// - /// The ratios table - /// - private static readonly float[][] RATIOS_TABLE; // = new float[PDF417Common.SYMBOL_TABLE.Length][PDF417Common.BARS_IN_MODULE]; - - /// - /// Initializes the class & Pre-computes the symbol ratio table. - /// - static PDF417CodewordDecoder() - { - // Jagged arrays in Java assign the memory automatically, but C# has no equivalent. (Jon Skeet says so!) - // http://stackoverflow.com/a/5313879/266252 - RATIOS_TABLE = new float[PDF417Common.SYMBOL_TABLE.Length][]; - for (int s = 0; s < RATIOS_TABLE.Length; s++) - { - RATIOS_TABLE[s] = new float[PDF417Common.BARS_IN_MODULE]; - } - - // Pre-computes the symbol ratio table. - for (int i = 0; i < PDF417Common.SYMBOL_TABLE.Length; i++) - { - int currentSymbol = PDF417Common.SYMBOL_TABLE[i]; - int currentBit = currentSymbol & 0x1; - for (int j = 0; j < PDF417Common.BARS_IN_MODULE; j++) - { - float size = 0.0f; - while ((currentSymbol & 0x1) == currentBit) - { - size += 1.0f; - currentSymbol >>= 1; - } - currentBit = currentSymbol & 0x1; - RATIOS_TABLE[i][PDF417Common.BARS_IN_MODULE - j - 1] = size/PDF417Common.MODULES_IN_CODEWORD; - } - } - } - - /// - /// Gets the decoded value. - /// - /// The decoded value. - /// Module bit count. - public static int getDecodedValue(int[] moduleBitCount) - { - int decodedValue = getDecodedCodewordValue(sampleBitCounts(moduleBitCount)); - if (decodedValue != PDF417Common.INVALID_CODEWORD) - { - return decodedValue; - } - return getClosestDecodedValue(moduleBitCount); - } - - /// - /// Samples the bit counts. - /// - /// The bit counts. - /// Module bit count. - private static int[] sampleBitCounts(int[] moduleBitCount) - { - float bitCountSum = PDF417Common.getBitCountSum(moduleBitCount); - int[] result = new int[PDF417Common.BARS_IN_MODULE]; - int bitCountIndex = 0; - int sumPreviousBits = 0; - for (int i = 0; i < PDF417Common.MODULES_IN_CODEWORD; i++) - { - float sampleIndex = - bitCountSum/(2*PDF417Common.MODULES_IN_CODEWORD) + - (i*bitCountSum)/PDF417Common.MODULES_IN_CODEWORD; - if (sumPreviousBits + moduleBitCount[bitCountIndex] <= sampleIndex) - { - sumPreviousBits += moduleBitCount[bitCountIndex]; - bitCountIndex++; - } - result[bitCountIndex]++; - } - return result; - } - - /// - /// Gets the decoded codeword value. - /// - /// The decoded codeword value. - /// Module bit count. - private static int getDecodedCodewordValue(int[] moduleBitCount) - { - int decodedValue = getBitValue(moduleBitCount); - return PDF417Common.getCodeword(decodedValue) == PDF417Common.INVALID_CODEWORD ? PDF417Common.INVALID_CODEWORD : decodedValue; - } - - /// - /// Gets the bit value. - /// - /// The bit value. - /// Module bit count. - private static int getBitValue(int[] moduleBitCount) - { - ulong result = 0; - for (ulong i = 0; i < (ulong) moduleBitCount.Length; i++) - { - for (int bit = 0; bit < moduleBitCount[i]; bit++) - { - result = (result << 1) | (i%2ul == 0ul ? 1ul : 0ul); // C# was warning about using the bit-wise 'OR' here with a mix of int/longs. - } - } - return (int) result; - } - - /// - /// Gets the closest decoded value. - /// - /// The closest decoded value. - /// Module bit count. - private static int getClosestDecodedValue(int[] moduleBitCount) - { - int bitCountSum = PDF417Common.getBitCountSum(moduleBitCount); - float[] bitCountRatios = new float[PDF417Common.BARS_IN_MODULE]; - for (int i = 0; i < bitCountRatios.Length; i++) - { - bitCountRatios[i] = moduleBitCount[i]/(float) bitCountSum; - } - float bestMatchError = float.MaxValue; - int bestMatch = PDF417Common.INVALID_CODEWORD; - for (int j = 0; j < RATIOS_TABLE.Length; j++) - { - float error = 0.0f; - float[] ratioTableRow = RATIOS_TABLE[j]; - for (int k = 0; k < PDF417Common.BARS_IN_MODULE; k++) - { - float diff = ratioTableRow[k] - bitCountRatios[k]; - error += diff*diff; - if (error >= bestMatchError) - { - break; - } - } - if (error < bestMatchError) - { - bestMatchError = error; - bestMatch = PDF417Common.SYMBOL_TABLE[j]; - } - } - return bestMatch; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/PDF417ScanningDecoder.cs b/zxing.core/xx/pdf417/decoder/PDF417ScanningDecoder.cs deleted file mode 100644 index 63db71f..0000000 --- a/zxing.core/xx/pdf417/decoder/PDF417ScanningDecoder.cs +++ /dev/null @@ -1,916 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; -using System.Globalization; -using System.Text; - -using ZXing.Common; -using ZXing.PDF417.Internal.EC; - -namespace ZXing.PDF417.Internal -{ - /// - /// - /// - /// Guenther Grau - public static class PDF417ScanningDecoder - { - private const int CODEWORD_SKEW_SIZE = 2; - - private const int MAX_ERRORS = 3; - private const int MAX_EC_CODEWORDS = 512; - private static readonly ErrorCorrection errorCorrection = new ErrorCorrection(); - - /// - /// Decode the specified image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, minCodewordWidth - /// and maxCodewordWidth. - /// TODO: don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern - /// columns. That way width can be deducted from the pattern column. - /// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider - /// than it should be. This can happen if the scanner used a bad blackpoint. - /// - /// Image. - /// Image top left. - /// Image bottom left. - /// Image top right. - /// Image bottom right. - /// Minimum codeword width. - /// Max codeword width. - public static DecoderResult decode(BitMatrix image, - ResultPoint imageTopLeft, - ResultPoint imageBottomLeft, - ResultPoint imageTopRight, - ResultPoint imageBottomRight, - int minCodewordWidth, - int maxCodewordWidth) - { - BoundingBox boundingBox = BoundingBox.Create(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight); - if (boundingBox == null) - return null; - - DetectionResultRowIndicatorColumn leftRowIndicatorColumn = null; - DetectionResultRowIndicatorColumn rightRowIndicatorColumn = null; - DetectionResult detectionResult = null; - for (int i = 0; i < 2; i++) - { - if (imageTopLeft != null) - { - leftRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopLeft, true, minCodewordWidth, maxCodewordWidth); - } - if (imageTopRight != null) - { - rightRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth); - } - detectionResult = merge(leftRowIndicatorColumn, rightRowIndicatorColumn); - if (detectionResult == null) - { - // TODO Based on Owen's Comments in , this method has been modified to continue silently - // if a barcode was not decoded where it was detected instead of throwing a new exception object. - return null; - } - if (i == 0 && detectionResult.Box != null && - (detectionResult.Box.MinY < boundingBox.MinY || detectionResult.Box.MaxY > boundingBox.MaxY)) - { - boundingBox = detectionResult.Box; - } - else - { - detectionResult.Box = boundingBox; - break; - } - } - int maxBarcodeColumn = detectionResult.ColumnCount + 1; - detectionResult.DetectionResultColumns[0] = leftRowIndicatorColumn; - - detectionResult.DetectionResultColumns[maxBarcodeColumn] = rightRowIndicatorColumn; - - bool leftToRight = leftRowIndicatorColumn != null; - for (int barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) - { - int barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount; - if (detectionResult.DetectionResultColumns[barcodeColumn] != null) - { - // This will be the case for the opposite row indicator column, which doesn't need to be decoded again. - continue; - } - DetectionResultColumn detectionResultColumn; - if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) - { - detectionResultColumn = new DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn == 0); - } - else - { - detectionResultColumn = new DetectionResultColumn(boundingBox); - } - detectionResult.DetectionResultColumns[barcodeColumn] = detectionResultColumn; - int startColumn = -1; - int previousStartColumn = startColumn; - // TODO start at a row for which we know the start position, then detect upwards and downwards from there. - for (int imageRow = boundingBox.MinY; imageRow <= boundingBox.MaxY; imageRow++) - { - startColumn = getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight); - if (startColumn < 0 || startColumn > boundingBox.MaxX) - { - if (previousStartColumn == -1) - { - continue; - } - startColumn = previousStartColumn; - } - Codeword codeword = detectCodeword(image, boundingBox.MinX, boundingBox.MaxX, leftToRight, - startColumn, imageRow, minCodewordWidth, maxCodewordWidth); - if (codeword != null) - { - detectionResultColumn.setCodeword(imageRow, codeword); - previousStartColumn = startColumn; - minCodewordWidth = Math.Min(minCodewordWidth, codeword.Width); - maxCodewordWidth = Math.Max(maxCodewordWidth, codeword.Width); - } - } - } - return createDecoderResult(detectionResult); - } - - /// - /// Merge the specified leftRowIndicatorColumn and rightRowIndicatorColumn. - /// - /// Left row indicator column. - /// Right row indicator column. - private static DetectionResult merge(DetectionResultRowIndicatorColumn leftRowIndicatorColumn, - DetectionResultRowIndicatorColumn rightRowIndicatorColumn) - { - if (leftRowIndicatorColumn == null && rightRowIndicatorColumn == null) - { - return null; - } - BarcodeMetadata barcodeMetadata = getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn); - if (barcodeMetadata == null) - { - return null; - } - BoundingBox boundingBox = BoundingBox.merge(adjustBoundingBox(leftRowIndicatorColumn), - adjustBoundingBox(rightRowIndicatorColumn)); - - return new DetectionResult(barcodeMetadata, boundingBox); - } - - /// - /// Adjusts the bounding box. - /// - /// The bounding box. - /// Row indicator column. - private static BoundingBox adjustBoundingBox(DetectionResultRowIndicatorColumn rowIndicatorColumn) - { - if (rowIndicatorColumn == null) - { - return null; - } - int[] rowHeights = rowIndicatorColumn.getRowHeights(); - if (rowHeights == null) - { - return null; - } - int maxRowHeight = getMax(rowHeights); - int missingStartRows = 0; - foreach (int rowHeight in rowHeights) - { - missingStartRows += maxRowHeight - rowHeight; - if (rowHeight > 0) - { - break; - } - } - Codeword[] codewords = rowIndicatorColumn.Codewords; - for (int row = 0; missingStartRows > 0 && codewords[row] == null; row++) - { - missingStartRows--; - } - int missingEndRows = 0; - for (int row = rowHeights.Length - 1; row >= 0; row--) - { - missingEndRows += maxRowHeight - rowHeights[row]; - if (rowHeights[row] > 0) - { - break; - } - } - for (int row = codewords.Length - 1; missingEndRows > 0 && codewords[row] == null; row--) - { - missingEndRows--; - } - return rowIndicatorColumn.Box.addMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn.IsLeft); - } - - private static int getMax(int[] values) - { - int maxValue = -1; - for (var index = values.Length - 1; index >= 0; index--) - { - maxValue = Math.Max(maxValue, values[index]); - } - return maxValue; - } - - /// - /// Gets the barcode metadata. - /// - /// The barcode metadata. - /// Left row indicator column. - /// Right row indicator column. - private static BarcodeMetadata getBarcodeMetadata(DetectionResultRowIndicatorColumn leftRowIndicatorColumn, - DetectionResultRowIndicatorColumn rightRowIndicatorColumn) - { - - BarcodeMetadata leftBarcodeMetadata; - if (leftRowIndicatorColumn == null || - (leftBarcodeMetadata = leftRowIndicatorColumn.getBarcodeMetadata()) == null) - { - return rightRowIndicatorColumn == null ? null : rightRowIndicatorColumn.getBarcodeMetadata(); - } - BarcodeMetadata rightBarcodeMetadata; - if (rightRowIndicatorColumn == null || - (rightBarcodeMetadata = rightRowIndicatorColumn.getBarcodeMetadata()) == null) - { - return leftBarcodeMetadata; - } - - if (leftBarcodeMetadata.ColumnCount != rightBarcodeMetadata.ColumnCount && - leftBarcodeMetadata.ErrorCorrectionLevel != rightBarcodeMetadata.ErrorCorrectionLevel && - leftBarcodeMetadata.RowCount != rightBarcodeMetadata.RowCount) - { - return null; - } - return leftBarcodeMetadata; - } - - /// - /// Gets the row indicator column. - /// - /// The row indicator column. - /// Image. - /// Bounding box. - /// Start point. - /// If set to true left to right. - /// Minimum codeword width. - /// Max codeword width. - private static DetectionResultRowIndicatorColumn getRowIndicatorColumn(BitMatrix image, - BoundingBox boundingBox, - ResultPoint startPoint, - bool leftToRight, - int minCodewordWidth, - int maxCodewordWidth) - { - DetectionResultRowIndicatorColumn rowIndicatorColumn = new DetectionResultRowIndicatorColumn(boundingBox, leftToRight); - for (int i = 0; i < 2; i++) - { - int increment = i == 0 ? 1 : -1; - int startColumn = (int) startPoint.X; - for (int imageRow = (int) startPoint.Y; imageRow <= boundingBox.MaxY && - imageRow >= boundingBox.MinY; imageRow += increment) - { - Codeword codeword = detectCodeword(image, 0, image.Width, leftToRight, startColumn, imageRow, - minCodewordWidth, maxCodewordWidth); - if (codeword != null) - { - rowIndicatorColumn.setCodeword(imageRow, codeword); - if (leftToRight) - { - startColumn = codeword.StartX; - } - else - { - startColumn = codeword.EndX; - } - } - } - } - return rowIndicatorColumn; - } - - /// - /// Adjusts the codeword count. - /// - /// Detection result. - /// Barcode matrix. - private static bool adjustCodewordCount(DetectionResult detectionResult, BarcodeValue[][] barcodeMatrix) - { - int[] numberOfCodewords = barcodeMatrix[0][1].getValue(); - int calculatedNumberOfCodewords = detectionResult.ColumnCount* - detectionResult.RowCount - - getNumberOfECCodeWords(detectionResult.ErrorCorrectionLevel); - if (numberOfCodewords.Length == 0) - { - if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > PDF417Common.MAX_CODEWORDS_IN_BARCODE) - { - return false; - } - barcodeMatrix[0][1].setValue(calculatedNumberOfCodewords); - } - else if (numberOfCodewords[0] != calculatedNumberOfCodewords) - { - // The calculated one is more reliable as it is derived from the row indicator columns - barcodeMatrix[0][1].setValue(calculatedNumberOfCodewords); - } - - return true; - } - - /// - /// Creates the decoder result. - /// - /// The decoder result. - /// Detection result. - private static DecoderResult createDecoderResult(DetectionResult detectionResult) - { - BarcodeValue[][] barcodeMatrix = createBarcodeMatrix(detectionResult); - if (barcodeMatrix == null) - return null; - - if (!adjustCodewordCount(detectionResult, barcodeMatrix)) - { - return null; - } - List erasures = new List(); - int[] codewords = new int[detectionResult.RowCount*detectionResult.ColumnCount]; - List ambiguousIndexValuesList = new List(); - List ambiguousIndexesList = new List(); - for (int row = 0; row < detectionResult.RowCount; row++) - { - for (int column = 0; column < detectionResult.ColumnCount; column++) - { - int[] values = barcodeMatrix[row][column + 1].getValue(); - int codewordIndex = row*detectionResult.ColumnCount + column; - if (values.Length == 0) - { - erasures.Add(codewordIndex); - } - else if (values.Length == 1) - { - codewords[codewordIndex] = values[0]; - } - else - { - ambiguousIndexesList.Add(codewordIndex); - ambiguousIndexValuesList.Add(values); - } - } - } - int[][] ambiguousIndexValues = new int[ambiguousIndexValuesList.Count][]; - for (int i = 0; i < ambiguousIndexValues.Length; i++) - { - ambiguousIndexValues[i] = ambiguousIndexValuesList[i]; - } - return createDecoderResultFromAmbiguousValues(detectionResult.ErrorCorrectionLevel, codewords, - erasures.ToArray(), ambiguousIndexesList.ToArray(), ambiguousIndexValues); - } - - /// - /// This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The - /// current error correction implementation doesn't deal with erasures very well, so it's better to provide a value - /// for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of - /// the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the - /// ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes, - /// so decoding the normal barcodes is not affected by this. - /// - /// The decoder result from ambiguous values. - /// Ec level. - /// Codewords. - /// contains the indexes of erasures. - /// array with the indexes that have more than one most likely value. - /// two dimensional array that contains the ambiguous values. The first dimension must - /// be the same Length as the ambiguousIndexes array. - private static DecoderResult createDecoderResultFromAmbiguousValues(int ecLevel, - int[] codewords, - int[] erasureArray, - int[] ambiguousIndexes, - int[][] ambiguousIndexValues) - { - int[] ambiguousIndexCount = new int[ambiguousIndexes.Length]; - - int tries = 100; - while (tries-- > 0) - { - for (int i = 0; i < ambiguousIndexCount.Length; i++) - { - codewords[ambiguousIndexes[i]] = ambiguousIndexValues[i][ambiguousIndexCount[i]]; - } - try - { - var result = decodeCodewords(codewords, ecLevel, erasureArray); - if (result != null) - return result; - } - catch (ReaderException) - { - // ignored, should not happen - } - if (ambiguousIndexCount.Length == 0) - { - return null; - } - for (int i = 0; i < ambiguousIndexCount.Length; i++) - { - if (ambiguousIndexCount[i] < ambiguousIndexValues[i].Length - 1) - { - ambiguousIndexCount[i]++; - break; - } - else - { - ambiguousIndexCount[i] = 0; - if (i == ambiguousIndexCount.Length - 1) - { - return null; - } - } - } - } - return null; - } - - /// - /// Creates the barcode matrix. - /// - /// The barcode matrix. - /// Detection result. - private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult) - { - // Manually setup Jagged Array in C# - var barcodeMatrix = new BarcodeValue[detectionResult.RowCount][]; - for (int row = 0; row < barcodeMatrix.Length; row++) - { - barcodeMatrix[row] = new BarcodeValue[detectionResult.ColumnCount + 2]; - for (int col = 0; col < barcodeMatrix[row].Length; col++) - { - barcodeMatrix[row][col] = new BarcodeValue(); - } - } - - int column = 0; - foreach (DetectionResultColumn detectionResultColumn in detectionResult.getDetectionResultColumns()) - { - if (detectionResultColumn != null) - { - foreach (Codeword codeword in detectionResultColumn.Codewords) - { - if (codeword != null) - { - int rowNumber = codeword.RowNumber; - if (rowNumber >= 0) - { - if (rowNumber >= barcodeMatrix.Length) - { - return null; - } - barcodeMatrix[rowNumber][column].setValue(codeword.Value); - } - } - } - } - column++; - } - - return barcodeMatrix; - } - - /// - /// Tests to see if the Barcode Column is Valid - /// - /// true, if barcode column is valid, false otherwise. - /// Detection result. - /// Barcode column. - private static bool isValidBarcodeColumn(DetectionResult detectionResult, int barcodeColumn) - { - return (barcodeColumn >= 0) && (barcodeColumn < detectionResult.DetectionResultColumns.Length); - } - - /// - /// Gets the start column. - /// - /// The start column. - /// Detection result. - /// Barcode column. - /// Image row. - /// If set to true left to right. - private static int getStartColumn(DetectionResult detectionResult, - int barcodeColumn, - int imageRow, - bool leftToRight) - { - int offset = leftToRight ? 1 : -1; - Codeword codeword = null; - if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) - { - codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].getCodeword(imageRow); - } - if (codeword != null) - { - return leftToRight ? codeword.EndX : codeword.StartX; - } - codeword = detectionResult.DetectionResultColumns[barcodeColumn].getCodewordNearby(imageRow); - if (codeword != null) - { - return leftToRight ? codeword.StartX : codeword.EndX; - } - if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) - { - codeword = detectionResult.DetectionResultColumns[barcodeColumn - offset].getCodewordNearby(imageRow); - } - if (codeword != null) - { - return leftToRight ? codeword.EndX : codeword.StartX; - } - int skippedColumns = 0; - - while (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) - { - barcodeColumn -= offset; - foreach (Codeword previousRowCodeword in detectionResult.DetectionResultColumns[barcodeColumn].Codewords) - { - if (previousRowCodeword != null) - { - return (leftToRight ? previousRowCodeword.EndX : previousRowCodeword.StartX) + - offset* - skippedColumns* - (previousRowCodeword.EndX - previousRowCodeword.StartX); - } - } - skippedColumns++; - } - return leftToRight ? detectionResult.Box.MinX : detectionResult.Box.MaxX; - } - - /// - /// Detects the codeword. - /// - /// The codeword. - /// Image. - /// Minimum column. - /// Max column. - /// If set to true left to right. - /// Start column. - /// Image row. - /// Minimum codeword width. - /// Max codeword width. - private static Codeword detectCodeword(BitMatrix image, - int minColumn, - int maxColumn, - bool leftToRight, - int startColumn, - int imageRow, - int minCodewordWidth, - int maxCodewordWidth) - { - startColumn = adjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); - // we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected length - // and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels. - // min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate - // for the current position - int[] moduleBitCount = getModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); - if (moduleBitCount == null) - { - return null; - } - int endColumn; - int codewordBitCount = PDF417Common.getBitCountSum(moduleBitCount); - if (leftToRight) - { - endColumn = startColumn + codewordBitCount; - } - else - { - for (int i = 0; i < (moduleBitCount.Length >> 1); i++) - { - int tmpCount = moduleBitCount[i]; - moduleBitCount[i] = moduleBitCount[moduleBitCount.Length - 1 - i]; - moduleBitCount[moduleBitCount.Length - 1 - i] = tmpCount; - } - endColumn = startColumn; - startColumn = endColumn - codewordBitCount; - } - // TODO implement check for width and correction of black and white bars - // use start (and maybe stop pattern) to determine if blackbars are wider than white bars. If so, adjust. - // should probably done only for codewords with a lot more than 17 bits. - // The following fixes 10-1.png, which has wide black bars and small white bars - // for (int i = 0; i < moduleBitCount.Length; i++) { - // if (i % 2 == 0) { - // moduleBitCount[i]--; - // } else { - // moduleBitCount[i]++; - // } - // } - - // We could also use the width of surrounding codewords for more accurate results, but this seems - // sufficient for now - if (!checkCodewordSkew(codewordBitCount, minCodewordWidth, maxCodewordWidth)) - { - // We could try to use the startX and endX position of the codeword in the same column in the previous row, - // create the bit count from it and normalize it to 8. This would help with single pixel errors. - return null; - } - - int decodedValue = PDF417CodewordDecoder.getDecodedValue(moduleBitCount); - int codeword = PDF417Common.getCodeword(decodedValue); - if (codeword == -1) - { - return null; - } - return new Codeword(startColumn, endColumn, getCodewordBucketNumber(decodedValue), codeword); - } - - /// - /// Gets the module bit count. - /// - /// The module bit count. - /// Image. - /// Minimum column. - /// Max column. - /// If set to true left to right. - /// Start column. - /// Image row. - private static int[] getModuleBitCount(BitMatrix image, - int minColumn, - int maxColumn, - bool leftToRight, - int startColumn, - int imageRow) - { - int imageColumn = startColumn; - int[] moduleBitCount = new int[8]; - int moduleNumber = 0; - int increment = leftToRight ? 1 : -1; - bool previousPixelValue = leftToRight; - while (((leftToRight && imageColumn < maxColumn) || (!leftToRight && imageColumn >= minColumn)) && - moduleNumber < moduleBitCount.Length) - { - if (image[imageColumn, imageRow] == previousPixelValue) - { - moduleBitCount[moduleNumber]++; - imageColumn += increment; - } - else - { - moduleNumber++; - previousPixelValue = !previousPixelValue; - } - } - if (moduleNumber == moduleBitCount.Length || - (((leftToRight && imageColumn == maxColumn) || (!leftToRight && imageColumn == minColumn)) && moduleNumber == moduleBitCount.Length - 1)) - { - return moduleBitCount; - } - return null; - } - - /// - /// Gets the number of EC code words. - /// - /// The number of EC code words. - /// Barcode EC level. - private static int getNumberOfECCodeWords(int barcodeECLevel) - { - return 2 << barcodeECLevel; - } - - /// - /// Adjusts the codeword start column. - /// - /// The codeword start column. - /// Image. - /// Minimum column. - /// Max column. - /// If set to true left to right. - /// Codeword start column. - /// Image row. - private static int adjustCodewordStartColumn(BitMatrix image, - int minColumn, - int maxColumn, - bool leftToRight, - int codewordStartColumn, - int imageRow) - { - int correctedStartColumn = codewordStartColumn; - int increment = leftToRight ? -1 : 1; - // there should be no black pixels before the start column. If there are, then we need to start earlier. - for (int i = 0; i < 2; i++) - { - while (((leftToRight && correctedStartColumn >= minColumn) || (!leftToRight && correctedStartColumn < maxColumn)) && - leftToRight == image[correctedStartColumn, imageRow]) - { - if (Math.Abs(codewordStartColumn - correctedStartColumn) > CODEWORD_SKEW_SIZE) - { - return codewordStartColumn; - } - correctedStartColumn += increment; - } - increment = -increment; - leftToRight = !leftToRight; - } - return correctedStartColumn; - } - - /// - /// Checks the codeword for any skew. - /// - /// true, if codeword is within the skew, false otherwise. - /// Codeword size. - /// Minimum codeword width. - /// Max codeword width. - private static bool checkCodewordSkew(int codewordSize, int minCodewordWidth, int maxCodewordWidth) - { - return minCodewordWidth - CODEWORD_SKEW_SIZE <= codewordSize && - codewordSize <= maxCodewordWidth + CODEWORD_SKEW_SIZE; - } - - /// - /// Decodes the codewords. - /// - /// The codewords. - /// Codewords. - /// Ec level. - /// Erasures. - private static DecoderResult decodeCodewords(int[] codewords, int ecLevel, int[] erasures) - { - if (codewords.Length == 0) - { - return null; - } - - int numECCodewords = 1 << (ecLevel + 1); - - int correctedErrorsCount = correctErrors(codewords, erasures, numECCodewords); - if (correctedErrorsCount < 0) - { - return null; - } - if (!verifyCodewordCount(codewords, numECCodewords)) - { - return null; - } - - // Decode the codewords - DecoderResult decoderResult = DecodedBitStreamParser.decode(codewords, ecLevel.ToString()); - if (decoderResult != null) - { - decoderResult.ErrorsCorrected = correctedErrorsCount; - decoderResult.Erasures = erasures.Length; - } - return decoderResult; - } - - /// - /// Given data and error-correction codewords received, possibly corrupted by errors, attempts to - /// correct the errors in-place. - /// - /// The errors. - /// data and error correction codewords. - /// positions of any known erasures. - /// number of error correction codewords that are available in codewords. - private static int correctErrors(int[] codewords, int[] erasures, int numECCodewords) - { - if (erasures != null && - erasures.Length > numECCodewords/2 + MAX_ERRORS || - numECCodewords < 0 || - numECCodewords > MAX_EC_CODEWORDS) - { - // Too many errors or EC Codewords is corrupted - return -1; - - } - int errorCount; - if (!errorCorrection.decode(codewords, numECCodewords, erasures, out errorCount)) - { - return -1; - } - return errorCount; - } - - /// - /// Verifies that all is well with the the codeword array. - /// - /// Codewords. - /// Number EC codewords. - private static bool verifyCodewordCount(int[] codewords, int numECCodewords) - { - 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 - return false; - } - // 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) - { - return false; - } - 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 - { - return false; - } - } - - return true; - } - - /// - /// Gets the bit count for codeword. - /// - /// The bit count for codeword. - /// Codeword. - private static int[] getBitCountForCodeword(int codeword) - { - int[] result = new int[8]; - int previousValue = 0; - int i = result.Length - 1; - while (true) - { - if ((codeword & 0x1) != previousValue) - { - previousValue = codeword & 0x1; - i--; - if (i < 0) - { - break; - } - } - result[i]++; - codeword >>= 1; - } - return result; - } - - /// - /// Gets the codeword bucket number. - /// - /// The codeword bucket number. - /// Codeword. - private static int getCodewordBucketNumber(int codeword) - { - return getCodewordBucketNumber(getBitCountForCodeword(codeword)); - } - - /// - /// Gets the codeword bucket number. - /// - /// The codeword bucket number. - /// Module bit count. - private static int getCodewordBucketNumber(int[] moduleBitCount) - { - return (moduleBitCount[0] - moduleBitCount[2] + moduleBitCount[4] - moduleBitCount[6] + 9)%9; - } - - /// - /// Returns a that represents the jagged array. - /// - /// A that represents the jagged array. - /// Barcode matrix as a jagged array. - public static String ToString(BarcodeValue[][] barcodeMatrix) - { - StringBuilder formatter = new StringBuilder(); - for (int row = 0; row < barcodeMatrix.Length; row++) - { - formatter.AppendFormat(CultureInfo.InvariantCulture, "Row {0,2}: ", row); - for (int column = 0; column < barcodeMatrix[row].Length; column++) - { - BarcodeValue barcodeValue = barcodeMatrix[row][column]; - int[] values = barcodeValue.getValue(); - if (values.Length == 0) - { - formatter.Append(" "); - } - else - { - formatter.AppendFormat(CultureInfo.InvariantCulture, "{0,4}({1,2})", values[0], barcodeValue.getConfidence(values[0])); - } - } - formatter.Append("\n"); - } - return formatter.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/ec/ErrorCorrection.cs b/zxing.core/xx/pdf417/decoder/ec/ErrorCorrection.cs deleted file mode 100644 index d0a72b9..0000000 --- a/zxing.core/xx/pdf417/decoder/ec/ErrorCorrection.cs +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal.EC -{ - /// - ///

PDF417 error correction implementation.

- ///

This example - /// is quite useful in understanding the algorithm.

- /// Sean Owen - /// - ///
- public sealed class ErrorCorrection - { - private readonly ModulusGF field; - - /// - /// Initializes a new instance of the class. - /// - public ErrorCorrection() - { - this.field = ModulusGF.PDF417_GF; - } - - /// - /// Decodes the specified received. - /// - /// received codewords - /// number of those codewords used for EC - /// location of erasures - /// The error locations count. - /// - public bool decode(int[] received, int numECCodewords, int[] erasures, out int errorLocationsCount) - { - ModulusPoly poly = new ModulusPoly(field, received); - int[] S = new int[numECCodewords]; - bool error = false; - errorLocationsCount = 0; - for (int i = numECCodewords; i > 0; i--) - { - int eval = poly.evaluateAt(field.exp(i)); - S[numECCodewords - i] = eval; - if (eval != 0) - { - error = true; - } - } - - if (!error) - { - return true; - } - - ModulusPoly knownErrors = field.One; - if (erasures != null) - { - foreach (int erasure in erasures) - { - int b = field.exp(received.Length - 1 - erasure); - // Add (1 - bx) term: - ModulusPoly term = new ModulusPoly(field, new int[] {field.subtract(0, b), 1}); - knownErrors = knownErrors.multiply(term); - } - } - - ModulusPoly syndrome = new ModulusPoly(field, S); - //syndrome = syndrome.multiply(knownErrors); - - ModulusPoly[] sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(numECCodewords, 1), syndrome, numECCodewords); - - if (sigmaOmega == null) - { - return false; - } - - ModulusPoly sigma = sigmaOmega[0]; - ModulusPoly omega = sigmaOmega[1]; - - if (sigma == null || omega == null) - { - return false; - } - - //sigma = sigma.multiply(knownErrors); - - int[] errorLocations = findErrorLocations(sigma); - - if (errorLocations == null) - { - return false; - } - - int[] errorMagnitudes = findErrorMagnitudes(omega, sigma, errorLocations); - - for (int i = 0; i < errorLocations.Length; i++) - { - int position = received.Length - 1 - field.log(errorLocations[i]); - if (position < 0) - { - return false; - - } - received[position] = field.subtract(received[position], errorMagnitudes[i]); - } - errorLocationsCount = errorLocations.Length; - return true; - } - - /// - /// Runs the euclidean algorithm (Greatest Common Divisor) until r's degree is less than R/2 - /// - /// The euclidean algorithm. - private ModulusPoly[] runEuclideanAlgorithm(ModulusPoly a, ModulusPoly b, int R) - { - // Assume a's degree is >= b's - if (a.Degree < b.Degree) - { - ModulusPoly temp = a; - a = b; - b = temp; - } - - ModulusPoly rLast = a; - ModulusPoly r = b; - ModulusPoly tLast = field.Zero; - ModulusPoly t = field.One; - - // Run Euclidean algorithm until r's degree is less than R/2 - while (r.Degree >= R / 2) - { - ModulusPoly rLastLast = rLast; - ModulusPoly tLastLast = tLast; - rLast = r; - tLast = t; - - // Divide rLastLast by rLast, with quotient in q and remainder in r - if (rLast.isZero) - { - // Oops, Euclidean algorithm already terminated? - return null; - } - r = rLastLast; - ModulusPoly q = field.Zero; - int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); - int dltInverse = field.inverse(denominatorLeadingTerm); - while (r.Degree >= rLast.Degree && !r.isZero) - { - int degreeDiff = r.Degree - rLast.Degree; - int scale = field.multiply(r.getCoefficient(r.Degree), dltInverse); - q = q.add(field.buildMonomial(degreeDiff, scale)); - r = r.subtract(rLast.multiplyByMonomial(degreeDiff, scale)); - } - - t = q.multiply(tLast).subtract(tLastLast).getNegative(); - } - - int sigmaTildeAtZero = t.getCoefficient(0); - if (sigmaTildeAtZero == 0) - { - return null; - } - - int inverse = field.inverse(sigmaTildeAtZero); - ModulusPoly sigma = t.multiply(inverse); - ModulusPoly omega = r.multiply(inverse); - return new ModulusPoly[] { sigma, omega }; - } - - /// - /// Finds the error locations as a direct application of Chien's search - /// - /// The error locations. - /// Error locator. - private int[] findErrorLocations(ModulusPoly errorLocator) - { - // This is a direct application of Chien's search - int numErrors = errorLocator.Degree; - 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) - { - return null; - } - return result; - } - - /// - /// Finds the error magnitudes by directly applying Forney's Formula - /// - /// The error magnitudes. - /// Error evaluator. - /// Error locator. - /// Error locations. - private int[] findErrorMagnitudes(ModulusPoly errorEvaluator, - ModulusPoly errorLocator, - int[] errorLocations) - { - int errorLocatorDegree = errorLocator.Degree; - int[] formalDerivativeCoefficients = new int[errorLocatorDegree]; - for (int i = 1; i <= errorLocatorDegree; i++) - { - formalDerivativeCoefficients[errorLocatorDegree - i] = - field.multiply(i, errorLocator.getCoefficient(i)); - } - ModulusPoly formalDerivative = new ModulusPoly(field, formalDerivativeCoefficients); - - // 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 numerator = field.subtract(0, errorEvaluator.evaluateAt(xiInverse)); - int denominator = field.inverse(formalDerivative.evaluateAt(xiInverse)); - result[i] = field.multiply(numerator, denominator); - } - return result; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/ec/ModulusGF.cs b/zxing.core/xx/pdf417/decoder/ec/ModulusGF.cs deleted file mode 100644 index ad97319..0000000 --- a/zxing.core/xx/pdf417/decoder/ec/ModulusGF.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal.EC -{ - /// - ///

A field based on powers of a generator integer, modulo some modulus.

- /// @see com.google.zxing.common.reedsolomon.GenericGF - ///
- /// Sean Owen - internal sealed class ModulusGF - { - public static ModulusGF PDF417_GF = new ModulusGF(PDF417Common.NUMBER_OF_CODEWORDS, 3); - - private readonly int[] expTable; - private readonly int[] logTable; - public ModulusPoly Zero { get; private set; } - public ModulusPoly One { get; private set; } - private readonly int modulus; - - public ModulusGF(int modulus, int generator) - { - this.modulus = modulus; - expTable = new int[modulus]; - logTable = new int[modulus]; - int x = 1; - for (int i = 0; i < modulus; i++) - { - expTable[i] = x; - x = (x * generator) % modulus; - } - for (int i = 0; i < modulus - 1; i++) - { - logTable[expTable[i]] = i; - } - // logTable[0] == 0 but this should never be used - Zero = new ModulusPoly(this, new int[] {0}); - One = new ModulusPoly(this, new int[] {1}); - } - - internal ModulusPoly buildMonomial(int degree, int coefficient) - { - if (degree < 0) - { - throw new ArgumentException(); - } - if (coefficient == 0) - { - return Zero; - } - int[] coefficients = new int[degree + 1]; - coefficients[0] = coefficient; - return new ModulusPoly(this, coefficients); - } - - internal int add(int a, int b) - { - return (a + b)%modulus; - } - - internal int subtract(int a, int b) - { - return (modulus + a - b)%modulus; - } - - internal int exp(int a) - { - return expTable[a]; - } - - internal int log(int a) - { - if (a == 0) - { - throw new ArgumentException(); - } - return logTable[a]; - } - - internal int inverse(int a) - { - if (a == 0) - { - throw new ArithmeticException(); - } - return expTable[modulus - logTable[a] - 1]; - } - - internal int multiply(int a, int b) - { - if (a == 0 || b == 0) - { - return 0; - } - return expTable[(logTable[a] + logTable[b]) % (modulus - 1)]; - } - - internal int Size - { - get - { - return modulus; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/decoder/ec/ModulusPoly.cs b/zxing.core/xx/pdf417/decoder/ec/ModulusPoly.cs deleted file mode 100644 index 3e5d8ed..0000000 --- a/zxing.core/xx/pdf417/decoder/ec/ModulusPoly.cs +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -namespace ZXing.PDF417.Internal.EC -{ - /// - /// - /// - /// Sean Owen - internal sealed class ModulusPoly - { - private readonly ModulusGF field; - private readonly int[] coefficients; - - public ModulusPoly(ModulusGF field, int[] coefficients) - { - if (coefficients.Length == 0) - { - throw new ArgumentException(); - } - this.field = field; - int coefficientsLength = coefficients.Length; - if (coefficientsLength > 1 && coefficients[0] == 0) - { - // Leading term must be non-zero for anything except the constant polynomial "0" - int firstNonZero = 1; - while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) - { - firstNonZero++; - } - if (firstNonZero == coefficientsLength) - { - this.coefficients = new int[]{0}; - } - else - { - this.coefficients = new int[coefficientsLength - firstNonZero]; - Array.Copy(coefficients, - firstNonZero, - this.coefficients, - 0, - this.coefficients.Length); - } - } - else - { - this.coefficients = coefficients; - } - } - - /// - /// Gets the coefficients. - /// - /// The coefficients. - internal int[] Coefficients - { - get { return coefficients; } - } - - /// - /// degree of this polynomial - /// - internal int Degree - { - get - { - return coefficients.Length - 1; - } - } - - /// - /// Gets a value indicating whether this instance is zero. - /// - /// true if this polynomial is the monomial "0" - /// - internal bool isZero - { - get { return coefficients[0] == 0; } - } - - /// - /// coefficient of x^degree term in this polynomial - /// - /// The degree. - /// coefficient of x^degree term in this polynomial - internal int getCoefficient(int degree) - { - return coefficients[coefficients.Length - 1 - degree]; - } - - /// - /// evaluation of this polynomial at a given point - /// - /// A. - /// evaluation of this polynomial at a given point - internal int evaluateAt(int a) - { - if (a == 0) - { - // Just return the x^0 coefficient - return getCoefficient(0); - } - int size = coefficients.Length; - int result = 0; - if (a == 1) - { - // Just the sum of the coefficients - foreach (var coefficient in coefficients) - { - result = field.add(result, coefficient); - } - return result; - } - result = coefficients[0]; - for (int i = 1; i < size; i++) - { - result = field.add(field.multiply(a, result), coefficients[i]); - } - return result; - } - - /// - /// Adds another Modulus - /// - /// Other. - internal ModulusPoly add(ModulusPoly other) - { - if (!field.Equals(other.field)) - { - throw new ArgumentException("ModulusPolys do not have same ModulusGF field"); - } - if (isZero) - { - return other; - } - if (other.isZero) - { - return this; - } - - int[] smallerCoefficients = this.coefficients; - int[] largerCoefficients = other.coefficients; - if (smallerCoefficients.Length > largerCoefficients.Length) - { - int[] temp = smallerCoefficients; - smallerCoefficients = largerCoefficients; - largerCoefficients = temp; - } - int[] sumDiff = new int[largerCoefficients.Length]; - int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length; - // Copy high-order terms only found in higher-degree polynomial's coefficients - Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); - - for (int i = lengthDiff; i < largerCoefficients.Length; i++) - { - sumDiff[i] = field.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); - } - - return new ModulusPoly(field, sumDiff); - } - - /// - /// Subtract another Modulus - /// - /// Other. - internal ModulusPoly subtract(ModulusPoly other) - { - if (!field.Equals(other.field)) - { - throw new ArgumentException("ModulusPolys do not have same ModulusGF field"); - } - if (other.isZero) - { - return this; - } - return add(other.getNegative()); - } - - /// - /// Multiply by another Modulus - /// - /// Other. - internal ModulusPoly multiply(ModulusPoly other) - { - if (!field.Equals(other.field)) - { - throw new ArgumentException("ModulusPolys do not have same ModulusGF field"); - } - if (isZero || other.isZero) - { - return field.Zero; - } - int[] aCoefficients = this.coefficients; - int aLength = aCoefficients.Length; - int[] bCoefficients = other.coefficients; - int bLength = bCoefficients.Length; - int[] product = new int[aLength + bLength - 1]; - for (int i = 0; i < aLength; i++) - { - int aCoeff = aCoefficients[i]; - for (int j = 0; j < bLength; j++) - { - product[i + j] = field.add(product[i + j], field.multiply(aCoeff, bCoefficients[j])); - } - } - return new ModulusPoly(field, product); - } - - /// - /// Returns a Negative version of this instance - /// - internal ModulusPoly getNegative() - { - int size = coefficients.Length; - int[] negativeCoefficients = new int[size]; - for (int i = 0; i < size; i++) - { - negativeCoefficients[i] = field.subtract(0, coefficients[i]); - } - return new ModulusPoly(field, negativeCoefficients); - } - - /// - /// Multiply by a Scalar. - /// - /// Scalar. - internal ModulusPoly multiply(int scalar) - { - if (scalar == 0) - { - return field.Zero; - } - if (scalar == 1) - { - return this; - } - int size = coefficients.Length; - int[] product = new int[size]; - for (int i = 0; i < size; i++) - { - product[i] = field.multiply(coefficients[i], scalar); - } - return new ModulusPoly(field, product); - } - - /// - /// Multiplies by a Monomial - /// - /// The by monomial. - /// Degree. - /// Coefficient. - internal ModulusPoly multiplyByMonomial(int degree, int coefficient) - { - if (degree < 0) - { - throw new ArgumentException(); - } - if (coefficient == 0) - { - return field.Zero; - } - int size = coefficients.Length; - int[] product = new int[size + degree]; - for (int i = 0; i < size; i++) - { - product[i] = field.multiply(coefficients[i], coefficient); - } - return new ModulusPoly(field, product); - } - - /// - /// Divide by another modulus - /// - /// Other. - internal ModulusPoly[] divide(ModulusPoly other) - { - if (!field.Equals(other.field)) - { - throw new ArgumentException("ModulusPolys do not have same ModulusGF field"); - } - if (other.isZero) - { - throw new DivideByZeroException(); - } - - ModulusPoly quotient = field.Zero; - ModulusPoly remainder = this; - - int denominatorLeadingTerm = other.getCoefficient(other.Degree); - int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm); - - while (remainder.Degree >= other.Degree && !remainder.isZero) - { - int degreeDifference = remainder.Degree - other.Degree; - int scale = field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm); - ModulusPoly term = other.multiplyByMonomial(degreeDifference, scale); - ModulusPoly iterationQuotient = field.buildMonomial(degreeDifference, scale); - quotient = quotient.add(iterationQuotient); - remainder = remainder.subtract(term); - } - - return new ModulusPoly[] { quotient, remainder }; - } - - /// - /// Returns a that represents the current . - /// - /// A that represents the current . - public override String ToString() - { - var result = new StringBuilder(8 * Degree); - for (int degree = Degree; degree >= 0; degree--) - { - int coefficient = getCoefficient(degree); - if (coefficient != 0) - { - if (coefficient < 0) - { - result.Append(" - "); - coefficient = -coefficient; - } - else - { - if (result.Length > 0) - { - result.Append(" + "); - } - } - if (degree == 0 || coefficient != 1) - { - result.Append(coefficient); - } - if (degree != 0) - { - if (degree == 1) - { - result.Append('x'); - } - else - { - result.Append("x^"); - result.Append(degree); - } - } - } - } - return result.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/detector/Detector.cs b/zxing.core/xx/pdf417/detector/Detector.cs deleted file mode 100644 index 91f6d60..0000000 --- a/zxing.core/xx/pdf417/detector/Detector.cs +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright 2009 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; - -namespace ZXing.PDF417.Internal -{ - /// - ///

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

- /// - /// SITA Lab (kevin.osullivan@sita.aero) - /// dswitkin@google.com (Daniel Switkin) - /// Guenther Grau - ///
- public sealed class Detector - { - private static readonly int[] INDEXES_START_PATTERN = {0, 4, 1, 5}; - private static readonly int[] INDEXES_STOP_PATTERN = {6, 2, 7, 3}; - private const int INTEGER_MATH_SHIFT = 8; - private const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; - private const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR*0.42f); - private const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR*0.8f); - - - /// - /// 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}; - - /// - /// 1111111 0 1 000 1 0 1 00 1 - /// - private static readonly int[] STOP_PATTERN = {7, 1, 1, 3, 1, 1, 1, 2, 1}; - - private const int MAX_PIXEL_DRIFT = 3; - private const int MAX_PATTERN_DRIFT = 5; - - /// - /// if we set the value too low, then we don't detect the correct height of the bar if the start patterns are damaged. - /// if we set the value too high, then we might detect the start pattern from a neighbor barcode. - /// - private const int SKIPPED_ROW_COUNT_MAX = 25; - - /// - /// A PDF471 barcode should have at least 3 rows, with each row being >= 3 times the module width. Therefore it should be at least - /// 9 pixels tall. To be conservative, we use about half the size to ensure we don't miss it. - /// - private const int ROW_STEP = 5; - - private const int BARCODE_MIN_HEIGHT = 10; - - /// - ///

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

- ///
- /// barcode image to decode - /// optional hints to detector - /// if true, then the image is searched for multiple codes. If false, then at most one code will be found and returned - /// - /// encapsulating results of detecting a PDF417 code - /// - public static PDF417DetectorResult detect(BinaryBitmap image, IDictionary hints, bool multiple) - { - // TODO detection improvement, tryHarder could try several different luminance thresholds/blackpoints or even - // different binarizers (SF: or different Skipped Row Counts/Steps?) - //boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); - - BitMatrix bitMatrix = image.BlackMatrix; - if (bitMatrix == null) - return null; - - List barcodeCoordinates = detect(multiple, bitMatrix); - if (barcodeCoordinates == null || - barcodeCoordinates.Count == 0) - { - bitMatrix = (BitMatrix) bitMatrix.Clone(); - bitMatrix.rotate180(); - barcodeCoordinates = detect(multiple, bitMatrix); - } - return new PDF417DetectorResult(bitMatrix, barcodeCoordinates); - } - - /// - /// Detects PDF417 codes in an image. Only checks 0 degree rotation (so rotate the matrix and check again outside of this method) - /// - /// multiple if true, then the image is searched for multiple codes. If false, then at most one code will be found and returned. - /// bit matrix to detect barcodes in. - /// List of ResultPoint arrays containing the coordinates of found barcodes - private static List detect(bool multiple, BitMatrix bitMatrix) - { - List barcodeCoordinates = new List(); - int row = 0; - int column = 0; - bool foundBarcodeInRow = false; - while (row < bitMatrix.Height) - { - ResultPoint[] vertices = findVertices(bitMatrix, row, column); - - if (vertices[0] == null && vertices[3] == null) - { - if (!foundBarcodeInRow) - { - // we didn't find any barcode so that's the end of searching - break; - } - // we didn't find a barcode starting at the given column and row. Try again from the first column and slightly - // below the lowest barcode we found so far. - foundBarcodeInRow = false; - column = 0; - foreach (ResultPoint[] barcodeCoordinate in barcodeCoordinates) - { - if (barcodeCoordinate[1] != null) - { - row = (int) Math.Max(row, barcodeCoordinate[1].Y); - } - if (barcodeCoordinate[3] != null) - { - row = Math.Max(row, (int) barcodeCoordinate[3].Y); - } - } - row += ROW_STEP; - continue; - } - foundBarcodeInRow = true; - barcodeCoordinates.Add(vertices); - if (!multiple) - { - break; - } - // if we didn't find a right row indicator column, then continue the search for the next barcode after the - // start pattern of the barcode just found. - if (vertices[2] != null) - { - column = (int) vertices[2].X; - row = (int) vertices[2].Y; - } - else - { - column = (int) vertices[4].X; - row = (int) vertices[4].Y; - } - } - return barcodeCoordinates; - } - - /// - /// Locate the vertices and the codewords area of a black blob using the Start and Stop patterns as locators. - /// - /// Matrix. - /// Start row. - /// Start column. - /// 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, int startRow, int startColumn) - { - int height = matrix.Height; - int width = matrix.Width; - - ResultPoint[] result = new ResultPoint[8]; - copyToResult(result, findRowsWithPattern(matrix, height, width, startRow, startColumn, START_PATTERN), - INDEXES_START_PATTERN); - - if (result[4] != null) - { - startColumn = (int) result[4].X; - startRow = (int) result[4].Y; - } - copyToResult(result, findRowsWithPattern(matrix, height, width, startRow, startColumn, STOP_PATTERN), - INDEXES_STOP_PATTERN); - return result; - } - - /// - /// Copies the temp data to the final result - /// - /// Result. - /// Temp result. - /// Destination indexes. - private static void copyToResult(ResultPoint[] result, ResultPoint[] tmpResult, int[] destinationIndexes) - { - for (int i = 0; i < destinationIndexes.Length; i++) - { - result[destinationIndexes[i]] = tmpResult[i]; - } - } - - /// - /// Finds the rows with the given pattern. - /// - /// The rows with pattern. - /// Matrix. - /// Height. - /// Width. - /// Start row. - /// Start column. - /// Pattern. - private static ResultPoint[] findRowsWithPattern( - BitMatrix matrix, - int height, - int width, - int startRow, - int startColumn, - int[] pattern) - { - ResultPoint[] result = new ResultPoint[4]; - bool found = false; - int[] counters = new int[pattern.Length]; - for (; startRow < height; startRow += ROW_STEP) - { - int[] loc = findGuardPattern(matrix, startColumn, startRow, width, false, pattern, counters); - if (loc != null) - { - while (startRow > 0) - { - int[] previousRowLoc = findGuardPattern(matrix, startColumn, --startRow, width, false, pattern, counters); - if (previousRowLoc != null) - { - loc = previousRowLoc; - } - else - { - startRow++; - break; - } - } - result[0] = new ResultPoint(loc[0], startRow); - result[1] = new ResultPoint(loc[1], startRow); - found = true; - break; - } - } - int stopRow = startRow + 1; - // Last row of the current symbol that contains pattern - if (found) - { - int skippedRowCount = 0; - int[] previousRowLoc = {(int) result[0].X, (int) result[1].X}; - for (; stopRow < height; stopRow++) - { - int[] loc = findGuardPattern(matrix, previousRowLoc[0], stopRow, width, false, pattern, counters); - // a found pattern is only considered to belong to the same barcode if the start and end positions - // don't differ too much. Pattern drift should be not bigger than two for consecutive rows. With - // a higher number of skipped rows drift could be larger. To keep it simple for now, we allow a slightly - // larger drift and don't check for skipped rows. - if (loc != null && - Math.Abs(previousRowLoc[0] - loc[0]) < MAX_PATTERN_DRIFT && - Math.Abs(previousRowLoc[1] - loc[1]) < MAX_PATTERN_DRIFT) - { - previousRowLoc = loc; - skippedRowCount = 0; - } - else - { - if (skippedRowCount > SKIPPED_ROW_COUNT_MAX) - { - break; - } - else - { - skippedRowCount++; - } - } - } - stopRow -= skippedRowCount + 1; - result[2] = new ResultPoint(previousRowLoc[0], stopRow); - result[3] = new ResultPoint(previousRowLoc[1], stopRow); - } - if (stopRow - startRow < BARCODE_MIN_HEIGHT) - { - for (int i = 0; i < result.Length; i++) - { - result[i] = null; - } - } - return result; - } - - /// - /// Finds the guard pattern. Uses System.Linq.Enumerable.Repeat to fill in counters. This might be a performance issue? - /// - /// start/end horizontal offset of guard pattern, as an array of two ints. - /// matrix row of black/white values to search - /// column x position to start search. - /// row y position to start search. - /// width the number of pixels to search on this row. - /// If set to true search the white patterns first. - /// pattern of counts of number of black and white pixels that are being searched for as a pattern. - /// counters array of counters, as long as pattern, to re-use . - private static int[] findGuardPattern( - BitMatrix matrix, - int column, - int row, - int width, - bool whiteFirst, - int[] pattern, - int[] counters) - { - SupportClass.Fill(counters, 0); - int patternLength = pattern.Length; - bool isWhite = whiteFirst; - int patternStart = column; - int pixelDrift = 0; - - // if there are black pixels left of the current pixel shift to the left, but only for MAX_PIXEL_DRIFT pixels - while (matrix[patternStart, row] && patternStart > 0 && pixelDrift++ < MAX_PIXEL_DRIFT) - { - patternStart--; - } - int x = patternStart; - int counterPosition = 0; - for (; x < width; x++) - { - bool pixel = matrix[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 - { - counterPosition++; - } - counters[counterPosition] = 1; - isWhite = !isWhite; - } - } - if (counterPosition == patternLength - 1) - { - if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) - { - return new int[] {patternStart, x - 1}; - } - } - 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. - /// - /// - /// 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 - /// - /// observed counters. - /// expected pattern. - /// The most any counter can differ before we give up. - 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 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; - - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/detector/PDF417DetectorResult.cs b/zxing.core/xx/pdf417/detector/PDF417DetectorResult.cs deleted file mode 100644 index 53121dc..0000000 --- a/zxing.core/xx/pdf417/detector/PDF417DetectorResult.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Collections.Generic; - -using ZXing.Common; - -namespace ZXing.PDF417.Internal -{ - /// - /// PDF 417 Detector Result class. Skipped private backing stores. - /// Guenther Grau - /// - public sealed class PDF417DetectorResult - { - public BitMatrix Bits { get; private set; } - public List Points { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// Bits. - /// Points. - public PDF417DetectorResult(BitMatrix bits, List points) - { - Bits = bits; - Points = points; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/BarcodeMatrix.cs b/zxing.core/xx/pdf417/encoder/BarcodeMatrix.cs deleted file mode 100644 index 98250f0..0000000 --- a/zxing.core/xx/pdf417/encoder/BarcodeMatrix.cs +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ - -namespace ZXing.PDF417.Internal -{ - /// - /// Holds all of the information for a barcode in a format where it can be easily accessable - /// - /// Jacob Haynes - /// - internal sealed class BarcodeMatrix - { - private readonly BarcodeRow[] matrix; - private int currentRow; - private readonly int height; - private readonly int width; - - /// - /// the height of the matrix (Rows) - /// the width of the matrix (Cols) - /// - internal BarcodeMatrix(int height, int width) - { - matrix = new BarcodeRow[height]; - //Initializes the array to the correct width - for (int i = 0, matrixLength = matrix.Length; i < matrixLength; i++) - { - matrix[i] = new BarcodeRow((width + 4)*17 + 1); - } - this.width = width*17; - this.height = height; - this.currentRow = -1; - } - - internal void set(int x, int y, sbyte value) - { - matrix[y][x] = value; - } - - /* - internal void setMatrix(int x, int y, bool black) - { - set(x, y, (sbyte) (black ? 1 : 0)); - } - */ - - internal void startRow() - { - ++currentRow; - } - - internal BarcodeRow getCurrentRow() - { - return matrix[currentRow]; - } - - internal sbyte[][] getMatrix() - { - return getScaledMatrix(1, 1); - } - - /* - internal sbyte[][] getScaledMatrix(int Scale) - { - return getScaledMatrix(Scale, Scale); - } - */ - - internal sbyte[][] getScaledMatrix(int xScale, int yScale) - { - sbyte[][] matrixOut = new sbyte[height*yScale][]; - for (int idx = 0; idx < height*yScale; idx++) - matrixOut[idx] = new sbyte[width*xScale]; - int yMax = height*yScale; - for (int ii = 0; ii < yMax; ii++) - { - matrixOut[yMax - ii - 1] = matrix[ii/yScale].getScaledRow(xScale); - } - return matrixOut; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/BarcodeRow.cs b/zxing.core/xx/pdf417/encoder/BarcodeRow.cs deleted file mode 100644 index 2719eab..0000000 --- a/zxing.core/xx/pdf417/encoder/BarcodeRow.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - */ - -namespace ZXing.PDF417.Internal -{ - /// - /// Jacob Haynes - /// - internal sealed class BarcodeRow - { - private readonly sbyte[] row; - //A tacker for position in the bar - private int currentLocation; - - /// - /// Creates a Barcode row of the width - /// - /// The width. - internal BarcodeRow(int width) - { - row = new sbyte[width]; - currentLocation = 0; - } - - /// - /// Sets a specific location in the bar - /// - /// The location in the bar - /// Black if true, white if false; - /// - internal sbyte this[int x] - { - get { return row[x]; } - set { row[x] = value; } - } - - /// - /// Sets a specific location in the bar - /// - /// The location in the bar - /// Black if true, white if false; - /// - internal void set(int x, bool black) - { - row[x] = (sbyte) (black ? 1 : 0); - } - - /// - /// A boolean which is true if the bar black false if it is white - /// How many spots wide the bar is. - /// - internal void addBar(bool black, int width) - { - for (int ii = 0; ii < width; ii++) - { - set(currentLocation++, black); - } - } - - /* - internal sbyte[] Row - { - get { return row; } - } - */ - - /// - /// This function scales the row - /// - /// How much you want the image to be scaled, must be greater than or equal to 1. - /// the scaled row - /// - internal sbyte[] getScaledRow(int scale) - { - var output = new sbyte[row.Length*scale]; - for (int i = 0; i < output.Length; i++) - { - output[i] = row[i/scale]; - } - return output; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/Compaction.cs b/zxing.core/xx/pdf417/encoder/Compaction.cs deleted file mode 100644 index c5f30e7..0000000 --- a/zxing.core/xx/pdf417/encoder/Compaction.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -namespace ZXing.PDF417.Internal -{ - /// - /// PDF417 compaction mode - /// - public enum Compaction - { - /// - /// - /// - AUTO, - - /// - /// - /// - TEXT, - - /// - /// - /// - BYTE, - - /// - /// - /// - NUMERIC - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/Dimensions.cs b/zxing.core/xx/pdf417/encoder/Dimensions.cs deleted file mode 100644 index e9c4bfa..0000000 --- a/zxing.core/xx/pdf417/encoder/Dimensions.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.PDF417.Internal -{ - /// - /// Data object to specify the minimum and maximum number of rows and columns for a PDF417 barcode. - /// @author qwandor@google.com (Andrew Walbran) - /// - public sealed class Dimensions - { - private readonly int minCols; - private readonly int maxCols; - private readonly int minRows; - private readonly int maxRows; - - /// - /// Initializes a new instance of the class. - /// - /// The min cols. - /// The max cols. - /// The min rows. - /// The max rows. - public Dimensions(int minCols, int maxCols, int minRows, int maxRows) - { - this.minCols = minCols; - this.maxCols = maxCols; - this.minRows = minRows; - this.maxRows = maxRows; - } - - /// - /// Gets the min cols. - /// - public int MinCols - { - get { return minCols; } - } - - /// - /// Gets the max cols. - /// - public int MaxCols - { - get { return maxCols; } - } - - /// - /// Gets the min rows. - /// - public int MinRows - { - get { return minRows; } - } - - /// - /// Gets the max rows. - /// - public int MaxRows - { - get { return maxRows; } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/PDF417.cs b/zxing.core/xx/pdf417/encoder/PDF417.cs deleted file mode 100644 index ba65a7c..0000000 --- a/zxing.core/xx/pdf417/encoder/PDF417.cs +++ /dev/null @@ -1,840 +0,0 @@ -/* - * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This file has been modified from its original form in Barcode4J. - */ - -using System; -using System.Text; - -namespace ZXing.PDF417.Internal -{ - /// - /// Top-level class for the logic part of the PDF417 implementation. - /// - internal sealed class PDF417 - { - /// - /// The start pattern (17 bits) - /// - private const int START_PATTERN = 0x1fea8; - - /// - /// The stop pattern (18 bits) - /// - private const int STOP_PATTERN = 0x3fa29; - - /// - /// The codeword table from the Annex A of ISO/IEC 15438:2001(E). - /// - private static readonly int[][] CODEWORD_TABLE = - { - new[] - { - 0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, - 0x1a8c0, 0x1d470, 0x1a860, 0x15040, 0x1a830, 0x15020, - 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, 0x1d678, 0x1eb3e, - 0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, - 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, - 0x1af7c, 0x15e78, 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, - 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, 0x1e93c, 0x1a460, - 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, - 0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, - 0x1d33c, 0x14c60, 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, - 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, 0x1a73c, 0x14e38, - 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0, - 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, - 0x1a230, 0x1d11c, 0x14420, 0x1a218, 0x14410, 0x14408, - 0x146c0, 0x1a370, 0x1d1bc, 0x14660, 0x1a338, 0x1d19e, - 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, - 0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8, - 0x1e85e, 0x14240, 0x1a130, 0x1d09c, 0x14220, 0x1a118, - 0x1d08e, 0x14210, 0x1a10c, 0x14208, 0x1a106, 0x14360, - 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, - 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, - 0x1d05c, 0x14120, 0x1a098, 0x1d04e, 0x14110, 0x1a08c, - 0x14108, 0x1a086, 0x14104, 0x141b0, 0x14198, 0x1418c, - 0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0, - 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, - 0x1ca38, 0x1e51e, 0x12840, 0x19430, 0x12820, 0x196e0, - 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, 0x1cb3c, 0x12c60, - 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, - 0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be, - 0x12f3c, 0x12fbe, 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, - 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, 0x1ed1c, 0x1b420, - 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970, - 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, - 0x1db38, 0x1ed9e, 0x16c40, 0x12420, 0x19218, 0x1c90e, - 0x16c20, 0x1b618, 0x16c10, 0x126c0, 0x19370, 0x1c9bc, - 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, - 0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc, - 0x16f70, 0x12738, 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, - 0x127bc, 0x16fbc, 0x1279e, 0x16f9e, 0x1d960, 0x1ecb8, - 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, - 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, - 0x1c8b8, 0x1e45e, 0x1b360, 0x19130, 0x1c89c, 0x16640, - 0x12220, 0x1d99c, 0x1c88e, 0x16620, 0x12210, 0x1910c, - 0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8, - 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, - 0x1918e, 0x16718, 0x1230c, 0x12306, 0x123b8, 0x191de, - 0x167b8, 0x1239c, 0x1679c, 0x1238e, 0x1678e, 0x167de, - 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, - 0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102, - 0x12140, 0x190b0, 0x1c85c, 0x16340, 0x12120, 0x19098, - 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, 0x16310, 0x12108, - 0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc, - 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, - 0x12186, 0x16386, 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, - 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, 0x1d846, 0x1b084, - 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, - 0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084, - 0x16184, 0x12082, 0x120d8, 0x161d8, 0x161cc, 0x161c6, - 0x1d82c, 0x1d826, 0x1b042, 0x1902c, 0x12048, 0x160c8, - 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, - 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, - 0x11410, 0x11408, 0x116c0, 0x18b70, 0x1c5bc, 0x11660, - 0x18b38, 0x1c59e, 0x11630, 0x18b1c, 0x11618, 0x1160c, - 0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc, - 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, - 0x1e69c, 0x19a20, 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, - 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, 0x1e25e, 0x19b60, - 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, - 0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608, - 0x11360, 0x189b8, 0x1c4de, 0x13760, 0x11330, 0x1cdde, - 0x13730, 0x19b9c, 0x1898e, 0x13718, 0x1130c, 0x1370c, - 0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e, - 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, - 0x1ee98, 0x1f74e, 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, - 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, 0x1bb40, 0x19920, - 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, - 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140, - 0x188b0, 0x1c45c, 0x13340, 0x11120, 0x18898, 0x1c44e, - 0x17740, 0x13320, 0x19998, 0x1ccce, 0x17720, 0x1bb98, - 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, - 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, - 0x177b0, 0x13398, 0x199ce, 0x17798, 0x1bbce, 0x11186, - 0x13386, 0x111dc, 0x133dc, 0x111ce, 0x177dc, 0x133ce, - 0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, - 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, - 0x1b9a0, 0x19890, 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, - 0x1b988, 0x19884, 0x1b984, 0x19882, 0x1b982, 0x110a0, - 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, - 0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084, - 0x17388, 0x13184, 0x11082, 0x13182, 0x110d8, 0x1886e, - 0x131d8, 0x110cc, 0x173d8, 0x131cc, 0x110c6, 0x173cc, - 0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48, - 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, - 0x19848, 0x1cc26, 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, - 0x1b8c2, 0x11050, 0x1882c, 0x130d0, 0x11048, 0x18826, - 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, - 0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6, - 0x1ee16, 0x1dc22, 0x1cc16, 0x19824, 0x19822, 0x11028, - 0x13068, 0x170e8, 0x11022, 0x13062, 0x18560, 0x10a40, - 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, - 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, - 0x1859c, 0x10b18, 0x1858e, 0x10b0c, 0x10b06, 0x10bb8, - 0x185de, 0x10b9c, 0x10b8e, 0x10bde, 0x18d40, 0x1c6b0, - 0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08, - 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, - 0x10920, 0x1c6dc, 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, - 0x11b10, 0x10908, 0x18486, 0x11b08, 0x18d86, 0x10902, - 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, - 0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce, - 0x11bce, 0x1cea0, 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, - 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, 0x18ca0, 0x1c658, - 0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646, - 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, - 0x18458, 0x119a0, 0x10890, 0x1c66e, 0x13ba0, 0x11990, - 0x18ccc, 0x18446, 0x13b90, 0x19dcc, 0x10884, 0x13b88, - 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, - 0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6, - 0x108ee, 0x119ee, 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, - 0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, 0x1e72c, 0x1ded0, - 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, - 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, - 0x1bdd0, 0x19cc8, 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42, - 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, 0x1842c, 0x118d0, - 0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0, - 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, - 0x17bc4, 0x1086c, 0x118ec, 0x10866, 0x139ec, 0x118e6, - 0x17bec, 0x139e6, 0x17be6, 0x1ef28, 0x1f796, 0x1ef24, - 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, - 0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24, - 0x1bce8, 0x19c64, 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, - 0x10828, 0x18416, 0x11868, 0x18c36, 0x138e8, 0x11864, - 0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2, - 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, - 0x19c34, 0x1bc74, 0x1bc72, 0x11834, 0x13874, 0x178f4, - 0x178f2, 0x10540, 0x10520, 0x18298, 0x10510, 0x10508, - 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, - 0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346, - 0x18684, 0x18682, 0x104a0, 0x18258, 0x10da0, 0x186d8, - 0x1824c, 0x10d90, 0x186cc, 0x10d88, 0x186c6, 0x10d84, - 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, - 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, - 0x1c748, 0x1c744, 0x1c742, 0x18650, 0x18ed0, 0x1c76c, - 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, 0x18642, 0x18ec2, - 0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8, - 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, - 0x1046c, 0x10cec, 0x10466, 0x11dec, 0x10ce6, 0x11de6, - 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, 0x1cf68, 0x1e7b6, - 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, - 0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62, - 0x19ee2, 0x10428, 0x18216, 0x10c68, 0x18636, 0x11ce8, - 0x10c64, 0x10422, 0x13de8, 0x11ce4, 0x10c62, 0x13de4, - 0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4, - 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, - 0x1cf34, 0x1c712, 0x1df74, 0x1cf32, 0x1df72, 0x18614, - 0x18e34, 0x18612, 0x19e74, 0x18e32, 0x1bef4 - }, - new[] - { - 0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, - 0x1f518, 0x1fa8e, 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506, - 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, 0x1d640, 0x1eb30, - 0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, - 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, - 0x1ae40, 0x1d730, 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, - 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, 0x1ae04, 0x1af60, - 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, - 0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06, - 0x15f60, 0x1afb8, 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, - 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, 0x15f9c, 0x15f8e, - 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e, - 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, - 0x1d340, 0x1e9b0, 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, - 0x1d310, 0x1e98c, 0x1d308, 0x1e986, 0x1d304, 0x1d302, - 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, - 0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702, - 0x14f40, 0x1a7b0, 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, - 0x14f10, 0x1a78c, 0x14f08, 0x1a786, 0x14f04, 0x14fb0, - 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, - 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, - 0x1e888, 0x1f446, 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8, - 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, 0x1e8c6, 0x1d184, - 0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, - 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, - 0x1d1ee, 0x14790, 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, - 0x14782, 0x147d8, 0x1a3ee, 0x147cc, 0x147c6, 0x147ee, - 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, - 0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, - 0x1a1d0, 0x1d0ec, 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, - 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, 0x143c4, 0x143c2, - 0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822, - 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, - 0x1a0e4, 0x1a0e2, 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, - 0x1e814, 0x1e812, 0x1d034, 0x1d032, 0x1a074, 0x1a072, - 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, - 0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502, - 0x1cb40, 0x1e5b0, 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, - 0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, 0x1cb04, 0x1cb02, - 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, - 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, - 0x12f40, 0x197b0, 0x1cbdc, 0x12f20, 0x19798, 0x1cbce, - 0x12f10, 0x1978c, 0x12f08, 0x19786, 0x12f04, 0x12fb0, - 0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, - 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, - 0x169f8, 0x1f688, 0x1fb46, 0x168fc, 0x1f684, 0x1f682, - 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, 0x1e490, 0x1fb6e, - 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, - 0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, - 0x1c990, 0x1e4cc, 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, - 0x1c984, 0x1db84, 0x1c982, 0x1db82, 0x193a0, 0x1c9d8, - 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc, - 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, - 0x127a0, 0x193d8, 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, - 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, 0x12784, 0x16f84, - 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, - 0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8, - 0x1f648, 0x1fb26, 0x164fc, 0x1f644, 0x1647e, 0x1f642, - 0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, 0x1f226, 0x1ecc8, - 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, - 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, - 0x1c8c2, 0x1d9c2, 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8, - 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, 0x191c2, 0x1b3c2, - 0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8, - 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, - 0x123e6, 0x167e6, 0x1f628, 0x1fb16, 0x162fc, 0x1f624, - 0x1627e, 0x1f622, 0x1e428, 0x1f216, 0x1ec68, 0x1f636, - 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, - 0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, - 0x1b1e8, 0x1d8f6, 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, - 0x190f6, 0x163e8, 0x121e4, 0x163e4, 0x121e2, 0x163e2, - 0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414, - 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, - 0x1d872, 0x19074, 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, - 0x161f4, 0x120f2, 0x161f2, 0x1f60a, 0x1e40a, 0x1ec1a, - 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, - 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284, - 0x1e282, 0x1c5a0, 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, - 0x1c588, 0x1e2c6, 0x1c584, 0x1c582, 0x18ba0, 0x1c5d8, - 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, - 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, - 0x11788, 0x18bc6, 0x11784, 0x11782, 0x117d8, 0x18bee, - 0x117cc, 0x117c6, 0x117ee, 0x1f350, 0x1f9ac, 0x135f8, - 0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342, - 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, - 0x1f366, 0x1e6c4, 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, - 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, 0x1e6e6, 0x1cdc4, - 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, - 0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, - 0x113d0, 0x189ec, 0x137d0, 0x113c8, 0x189e6, 0x137c8, - 0x19be6, 0x137c4, 0x113c2, 0x137c2, 0x113ec, 0x137ec, - 0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4, - 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, - 0x1f996, 0x132fc, 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, - 0x1f764, 0x1f322, 0x1767e, 0x1f762, 0x1e228, 0x1f116, - 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, - 0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464, - 0x1dde8, 0x1cce4, 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, - 0x188e8, 0x1c476, 0x199e8, 0x188e4, 0x1bbe8, 0x199e4, - 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, - 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, - 0x133e2, 0x177e2, 0x111f6, 0x133f6, 0x1fb94, 0x172f8, - 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, 0x1f314, 0x1317e, - 0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634, - 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, - 0x1c432, 0x1dcf4, 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, - 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, 0x110f4, 0x131f4, - 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, - 0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, - 0x1c41a, 0x1cc3a, 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, - 0x1107a, 0x130fa, 0x171fa, 0x170be, 0x1e150, 0x1f0ac, - 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c, - 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, - 0x185c8, 0x1c2e6, 0x185c4, 0x185c2, 0x10bd0, 0x185ec, - 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, 0x10bec, 0x10be6, - 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, - 0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122, - 0x1e362, 0x1c268, 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, - 0x1c262, 0x1c6e2, 0x184e8, 0x1c276, 0x18de8, 0x184e4, - 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, - 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, - 0x1f9d4, 0x13af8, 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e, - 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, 0x13b7e, 0x1f3b2, - 0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772, - 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, - 0x18474, 0x18cf4, 0x18472, 0x19df4, 0x18cf2, 0x19df2, - 0x108f4, 0x119f4, 0x108f2, 0x13bf4, 0x119f2, 0x13bf2, - 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, - 0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, - 0x1f18a, 0x1f39a, 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, - 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, 0x1defa, 0x1843a, - 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa, - 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, - 0x178bc, 0x1789e, 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, - 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, 0x182e8, 0x1c176, - 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, - 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4, - 0x1e092, 0x1e1b2, 0x1c134, 0x1c374, 0x1c132, 0x1c372, - 0x18274, 0x186f4, 0x18272, 0x186f2, 0x104f4, 0x10df4, - 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, - 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, - 0x1c77a, 0x1823a, 0x1867a, 0x18efa, 0x1047a, 0x10cfa, - 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, 0x13d1e, 0x11cbe, - 0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, - 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, - 0x1be5e, 0x17c9c, 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, - 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, 0x18174, 0x18172, - 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, - 0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, - 0x13eb8, 0x19f5e, 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, - 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, 0x17e8c, 0x17e86, - 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e, - 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, - 0x10f5e, 0x11f5c, 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, - 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, 0x13f26 - }, - new[] - { - 0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, - 0x1a8f8, 0x1d47e, 0x150f0, 0x1a87c, 0x15078, 0x1fad0, - 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, 0x1acfc, 0x1fac4, - 0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, - 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, - 0x1f5c2, 0x1ebd0, 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, - 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, 0x1ebe6, 0x1d7c4, - 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, - 0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, - 0x148f0, 0x1a47c, 0x14878, 0x1a43e, 0x1483c, 0x1fa68, - 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, 0x1a67e, 0x1fa62, - 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4, - 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, - 0x1d3e8, 0x1e9f6, 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, - 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, 0x1d17e, 0x144f0, - 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, - 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474, - 0x1477e, 0x1f472, 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, - 0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, 0x14278, 0x1a13e, - 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, - 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, - 0x141be, 0x140bc, 0x1409e, 0x12bc0, 0x195f0, 0x1cafc, - 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, 0x1947c, 0x12878, - 0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964, - 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, - 0x1f976, 0x12efc, 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, - 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, 0x1e5f6, 0x1cbe4, - 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, - 0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, - 0x1b478, 0x1da3e, 0x16870, 0x1b43c, 0x16838, 0x1b41e, - 0x1681c, 0x125e0, 0x192f8, 0x1c97e, 0x16de0, 0x124f0, - 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c, - 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, - 0x1fb74, 0x1f932, 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, - 0x1263e, 0x16e3e, 0x1f274, 0x1277e, 0x1f6f4, 0x1f272, - 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, - 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2, - 0x165c0, 0x1b2f0, 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, - 0x16470, 0x1b23c, 0x16438, 0x1b21e, 0x1641c, 0x1640e, - 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, - 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, - 0x1fb3a, 0x1677c, 0x1233e, 0x1673e, 0x1f23a, 0x1f67a, - 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, 0x191fa, 0x162e0, - 0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e, - 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, - 0x1633c, 0x1211e, 0x1631e, 0x121be, 0x163be, 0x16170, - 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, 0x1610e, 0x120bc, - 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, - 0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0, - 0x18af8, 0x1c57e, 0x114f0, 0x18a7c, 0x11478, 0x18a3e, - 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, 0x18b7e, 0x1f8b2, - 0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4, - 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, - 0x19af0, 0x1cd7c, 0x134e0, 0x19a78, 0x1cd3e, 0x13470, - 0x19a3c, 0x13438, 0x19a1e, 0x1341c, 0x1340e, 0x112f0, - 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, - 0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba, - 0x1377c, 0x1133e, 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, - 0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, 0x1bae0, 0x1dd78, - 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, - 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, - 0x132e0, 0x19978, 0x1ccbe, 0x176e0, 0x13270, 0x1993c, - 0x17670, 0x1bb3c, 0x1991e, 0x17638, 0x1321c, 0x1761c, - 0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c, - 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, - 0x111be, 0x133be, 0x177be, 0x172c0, 0x1b970, 0x1dcbc, - 0x17260, 0x1b938, 0x1dc9e, 0x17230, 0x1b91c, 0x17218, - 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, - 0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e, - 0x1730e, 0x110bc, 0x131bc, 0x1109e, 0x173bc, 0x1319e, - 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, 0x17130, 0x1b89c, - 0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e, - 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, - 0x130de, 0x171de, 0x170b0, 0x1b85c, 0x17098, 0x1b84e, - 0x1708c, 0x17086, 0x1305c, 0x170dc, 0x1304e, 0x170ce, - 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, - 0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e, - 0x10a3c, 0x10a1e, 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, - 0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, 0x1c6be, 0x11a70, - 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, - 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, - 0x109be, 0x11bbe, 0x13ac0, 0x19d70, 0x1cebc, 0x13a60, - 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, 0x13a18, 0x19d0e, - 0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938, - 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, - 0x108bc, 0x119bc, 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, - 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, 0x1bd30, 0x1de9c, - 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, - 0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, - 0x13930, 0x19c9c, 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, - 0x1390c, 0x17b0c, 0x13906, 0x17b06, 0x118b8, 0x18c5e, - 0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c, - 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, - 0x17940, 0x1bcb0, 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, - 0x17910, 0x1bc8c, 0x17908, 0x1bc86, 0x17904, 0x17902, - 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, - 0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc, - 0x1184e, 0x179dc, 0x138ce, 0x179ce, 0x178a0, 0x1bc58, - 0x1de2e, 0x17890, 0x1bc4c, 0x17888, 0x1bc46, 0x17884, - 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, - 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, - 0x1bc2c, 0x17848, 0x1bc26, 0x17844, 0x17842, 0x1382c, - 0x1786c, 0x13826, 0x17866, 0x17828, 0x1bc16, 0x17824, - 0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c, - 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, - 0x10d1c, 0x10d0e, 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, - 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, 0x18e9c, 0x11d18, - 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, - 0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, - 0x11dde, 0x13d40, 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, - 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, 0x19e86, 0x13d04, - 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e, - 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, - 0x11cdc, 0x10c4e, 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, - 0x1df58, 0x1efae, 0x1be90, 0x1df4c, 0x1be88, 0x1df46, - 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, - 0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88, - 0x13c84, 0x17d84, 0x13c82, 0x17d82, 0x11c58, 0x18e2e, - 0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, 0x11c46, 0x17dcc, - 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, - 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, - 0x13c50, 0x19e2c, 0x17cd0, 0x13c48, 0x19e26, 0x17cc8, - 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, 0x11c2c, 0x13c6c, - 0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16, - 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, - 0x17c64, 0x13c22, 0x17c62, 0x11c16, 0x13c36, 0x17c76, - 0x1be14, 0x1be12, 0x13c14, 0x17c34, 0x13c12, 0x17c32, - 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, - 0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e, - 0x10e8c, 0x10e86, 0x1065c, 0x10edc, 0x1064e, 0x10ece, - 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, 0x18f4c, 0x11e88, - 0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8, - 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, - 0x11eee, 0x19f50, 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, - 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, 0x19f6c, 0x18f26, - 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, - 0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8, - 0x1efd6, 0x1dfa4, 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, - 0x19f24, 0x1bf64, 0x19f22, 0x1bf62, 0x11e28, 0x18f16, - 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, - 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, - 0x1df94, 0x1df92, 0x19f14, 0x1bf34, 0x19f12, 0x1bf32, - 0x11e14, 0x13e34, 0x11e12, 0x17e74, 0x13e32, 0x17e72, - 0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, - 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, - 0x1032e, 0x1076e, 0x10f50, 0x187ac, 0x10f48, 0x187a6, - 0x10f44, 0x10f42, 0x1072c, 0x10f6c, 0x10726, 0x10f66, - 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, - 0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716, - 0x10f36, 0x11f76, 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, - 0x18f92, 0x19fb2, 0x10f14, 0x11f34, 0x10f12, 0x13f74, - 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a, - 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, - 0x107a4, 0x107a2, 0x10396, 0x107b6, 0x187d4, 0x187d2, - 0x10794, 0x10fb4, 0x10792, 0x10fb2, 0x1c7ea - } - }; - - private const float PREFERRED_RATIO = 3.0f; - private const float DEFAULT_MODULE_WIDTH = 0.357f; //1px in mm - private const float HEIGHT = 2.0f; //mm - - private BarcodeMatrix barcodeMatrix; - private bool compact; - private Compaction compaction; - private Encoding encoding; - private bool disableEci; - private int minCols; - private int maxCols; - private int maxRows; - private int minRows; - - internal PDF417() - : this(false) - { - } - - internal PDF417(bool compact) - { - this.compact = compact; - compaction = Compaction.AUTO; - encoding = null; // use default - disableEci = false; - minCols = 2; - maxCols = 30; - maxRows = 30; - minRows = 2; - } - - internal BarcodeMatrix BarcodeMatrix - { - get { return barcodeMatrix; } - } - - /// - /// Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E). - /// - /// the number of source codewords prior to the additional of the Symbol Length - /// Descriptor and any pad codewords - /// the number of error correction codewords - /// the number of columns in the symbol in the data region (excluding start, stop and - /// row indicator codewords) - /// the number of rows in the symbol (r) - private static int calculateNumberOfRows(int m, int k, int c) - { - int r = ((m + 1 + k)/c) + 1; - if (c*r >= (m + 1 + k + c)) - { - r--; - } - return r; - } - - /// - /// Calculates the number of pad codewords as described in 4.9.2 of ISO/IEC 15438:2001(E). - /// - /// the number of source codewords prior to the additional of the Symbol Length - /// Descriptor and any pad codewords - /// the number of error correction codewords - /// the number of columns in the symbol in the data region (excluding start, stop and - /// row indicator codewords) - /// the number of rows in the symbol - /// the number of pad codewords - private static int getNumberOfPadCodewords(int m, int k, int c, int r) - { - int n = c*r - k; - return n > m + 1 ? n - m - 1 : 0; - } - - private static void encodeChar(int pattern, int len, BarcodeRow logic) - { - int map = 1 << len - 1; - bool last = (pattern & map) != 0; //Initialize to inverse of first bit - int width = 0; - for (int i = 0; i < len; i++) - { - bool black = (pattern & map) != 0; - if (last == black) - { - width++; - } - else - { - logic.addBar(last, width); - - last = black; - width = 1; - } - map >>= 1; - } - logic.addBar(last, width); - } - - private void encodeLowLevel(String fullCodewords, - int c, - int r, - int errorCorrectionLevel, - BarcodeMatrix logic) - { - - int idx = 0; - for (int y = 0; y < r; y++) - { - int cluster = y%3; - logic.startRow(); - encodeChar(START_PATTERN, 17, logic.getCurrentRow()); - - int left; - int right; - if (cluster == 0) - { - left = (30*(y/3)) + ((r - 1)/3); - right = (30*(y/3)) + (c - 1); - } - else if (cluster == 1) - { - left = (30*(y/3)) + (errorCorrectionLevel*3) + ((r - 1)%3); - right = (30*(y/3)) + ((r - 1)/3); - } - else - { - left = (30*(y/3)) + (c - 1); - right = (30*(y/3)) + (errorCorrectionLevel*3) + ((r - 1)%3); - } - - int pattern = CODEWORD_TABLE[cluster][left]; - encodeChar(pattern, 17, logic.getCurrentRow()); - - for (int x = 0; x < c; x++) - { - pattern = CODEWORD_TABLE[cluster][fullCodewords[idx]]; - encodeChar(pattern, 17, logic.getCurrentRow()); - idx++; - } - - if (compact) - { - encodeChar(STOP_PATTERN, 1, logic.getCurrentRow()); // encodes stop line for compact pdf417 - } - else - { - pattern = CODEWORD_TABLE[cluster][right]; - encodeChar(pattern, 17, logic.getCurrentRow()); - - encodeChar(STOP_PATTERN, 18, logic.getCurrentRow()); - } - } - } - - /// - /// Generates the barcode logic. - /// - /// the message to encode - /// PDF417 error correction level to use - internal void generateBarcodeLogic(String msg, int errorCorrectionLevel) - { - - //1. step: High-level encoding - int errorCorrectionCodeWords = PDF417ErrorCorrection.getErrorCorrectionCodewordCount(errorCorrectionLevel); - String highLevel = PDF417HighLevelEncoder.encodeHighLevel(msg, compaction, encoding, disableEci); - int sourceCodeWords = highLevel.Length; - - int[] dimension = determineDimensions(sourceCodeWords, errorCorrectionCodeWords); - - int cols = dimension[0]; - int rows = dimension[1]; - - int pad = getNumberOfPadCodewords(sourceCodeWords, errorCorrectionCodeWords, cols, rows); - - //2. step: construct data codewords - if (sourceCodeWords + errorCorrectionCodeWords + 1 > 929) - { - // +1 for symbol length CW - throw new WriterException( - "Encoded message contains to many code words, message to big (" + msg.Length + " bytes)"); - } - int n = sourceCodeWords + pad + 1; - StringBuilder sb = new StringBuilder(n); - sb.Append((char) n); - sb.Append(highLevel); - for (int i = 0; i < pad; i++) - { - sb.Append((char) 900); //PAD characters - } - String dataCodewords = sb.ToString(); - - //3. step: Error correction - String ec = PDF417ErrorCorrection.generateErrorCorrection(dataCodewords, errorCorrectionLevel); - String fullCodewords = dataCodewords + ec; - - //4. step: low-level encoding - barcodeMatrix = new BarcodeMatrix(rows, cols); - encodeLowLevel(fullCodewords, cols, rows, errorCorrectionLevel, barcodeMatrix); - } - - /// - /// Determine optimal nr of columns and rows for the specified number of - /// codewords. - /// - /// number of code words - /// number of error correction code words - /// dimension object containing cols as width and rows as height - private int[] determineDimensions(int sourceCodeWords, int errorCorrectionCodeWords) - { - float ratio = 0.0f; - int[] dimension = null; - - for (int cols = minCols; cols <= maxCols; cols++) - { - - int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, cols); - - if (rows < minRows) - { - break; - } - - if (rows > maxRows) - { - continue; - } - - float newRatio = ((17*cols + 69)*DEFAULT_MODULE_WIDTH)/(rows*HEIGHT); - - // ignore if previous ratio is closer to preferred ratio - if (dimension != null && Math.Abs(newRatio - PREFERRED_RATIO) > Math.Abs(ratio - PREFERRED_RATIO)) - { - continue; - } - - ratio = newRatio; - dimension = new int[] {cols, rows}; - } - - // Handle case when min values were larger than necessary - if (dimension == null) - { - int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, minCols); - if (rows < minRows) - { - dimension = new int[] {minCols, minRows}; - } - } - - if (dimension == null) - { - throw new WriterException("Unable to fit message in columns"); - } - - return dimension; - } - - /// - /// Sets max/min row/col values - /// - /// maximum allowed columns - /// minimum allowed columns - /// maximum allowed rows - /// minimum allowed rows - internal void setDimensions(int maxCols, int minCols, int maxRows, int minRows) - { - this.maxCols = maxCols; - this.minCols = minCols; - this.maxRows = maxRows; - this.minRows = minRows; - } - - /// - /// Sets compaction to values stored in enum - /// - /// compaction mode to use - internal void setCompaction(Compaction compaction) - { - this.compaction = compaction; - } - - /// - /// Sets compact to be true or false - /// - /// if true, enables compaction - internal void setCompact(bool compact) - { - this.compact = compact; - } - - /// - /// Sets output encoding. - /// - /// sets character encoding to use - internal void setEncoding(String encodingname) - { -#if WindowsCE - try - { - this.encoding = Encoding.GetEncoding(encodingname); - } - catch (PlatformNotSupportedException) - { - // WindowsCE doesn't support all encodings. But it is device depended. - // So we try here the some different ones - this.encoding = Encoding.GetEncoding(1252); - } -#else - this.encoding = Encoding.GetEncoding(encodingname); -#endif - } - - /// - /// Sets the disable eci. - /// - /// if set to true don't add an ECI segment for different encodings than default. - internal void setDisableEci(bool disabled) - { - this.disableEci = disabled; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/PDF417EncodingOptions.cs b/zxing.core/xx/pdf417/encoder/PDF417EncodingOptions.cs deleted file mode 100644 index 0101d2b..0000000 --- a/zxing.core/xx/pdf417/encoder/PDF417EncodingOptions.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2012 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; -using ZXing.PDF417.Internal; - -namespace ZXing.PDF417 -{ - /// - /// The class holds the available options for the - /// - public class PDF417EncodingOptions : EncodingOptions - { - /// - /// Specifies whether to use compact mode for PDF417 (type ). - /// - public bool Compact - { - get - { - if (Hints.ContainsKey(EncodeHintType.PDF417_COMPACT)) - { - return (bool) Hints[EncodeHintType.PDF417_COMPACT]; - } - return false; - } - set { Hints[EncodeHintType.PDF417_COMPACT] = value; } - } - - /// - /// Specifies what compaction mode to use for PDF417 (type - /// ). - /// - public Compaction Compaction - { - get - { - if (Hints.ContainsKey(EncodeHintType.PDF417_COMPACTION)) - { - return (Compaction) Hints[EncodeHintType.PDF417_COMPACTION]; - } - return Compaction.AUTO; - } - set { Hints[EncodeHintType.PDF417_COMPACTION] = value; } - } - - /// - /// Specifies the minimum and maximum number of rows and columns for PDF417 (type - /// ). - /// - public Dimensions Dimensions - { - get - { - if (Hints.ContainsKey(EncodeHintType.PDF417_DIMENSIONS)) - { - return (Dimensions) Hints[EncodeHintType.PDF417_DIMENSIONS]; - } - return null; - } - set { Hints[EncodeHintType.PDF417_DIMENSIONS] = value; } - } - - /// - /// Specifies what degree of error correction to use - /// - public PDF417ErrorCorrectionLevel ErrorCorrection - { - get - { - if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) - { - var value = Hints[EncodeHintType.ERROR_CORRECTION]; - if (value is PDF417ErrorCorrectionLevel) - { - return (PDF417ErrorCorrectionLevel)value; - } - if (value is int) - { - return (PDF417ErrorCorrectionLevel)Enum.Parse(typeof(PDF417ErrorCorrectionLevel), value.ToString(), true); - } - } - return PDF417ErrorCorrectionLevel.L2; - } - set { Hints[EncodeHintType.ERROR_CORRECTION] = value; } - } - - /// - /// Specifies what character encoding to use where applicable (type {@link String}) - /// - public string CharacterSet - { - get - { - if (Hints.ContainsKey(EncodeHintType.CHARACTER_SET)) - { - return (string)Hints[EncodeHintType.CHARACTER_SET]; - } - return null; - } - set - { - if (value == null) - { - if (Hints.ContainsKey(EncodeHintType.CHARACTER_SET)) - Hints.Remove(EncodeHintType.CHARACTER_SET); - } - else - { - Hints[EncodeHintType.CHARACTER_SET] = value; - } - } - } - - /// - /// Explicitly disables ECI segment when generating PDF417 Code - /// That is against the specification but some - /// readers have problems if the charset is switched from - /// CP437 (default) to UTF-8 with the necessary ECI segment. - /// If you set the property to true you can use different encodings - /// and the ECI segment is omitted. - /// - public bool DisableECI - { - get - { - if (Hints.ContainsKey(EncodeHintType.DISABLE_ECI)) - { - return (bool)Hints[EncodeHintType.DISABLE_ECI]; - } - return false; - } - set - { - Hints[EncodeHintType.DISABLE_ECI] = value; - } - } - } -} diff --git a/zxing.core/xx/pdf417/encoder/PDF417ErrorCorrection.cs b/zxing.core/xx/pdf417/encoder/PDF417ErrorCorrection.cs deleted file mode 100644 index 1e5e212..0000000 --- a/zxing.core/xx/pdf417/encoder/PDF417ErrorCorrection.cs +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This file has been modified from its original form in Barcode4J. - */ - -using System; - -using System.Text; - -namespace ZXing.PDF417.Internal -{ - /// - /// PDF417 error correction code following the algorithm described in ISO/IEC 15438:2001(E) in - /// chapter 4.10. - /// - internal static class PDF417ErrorCorrection - { - /// - /// Tables of coefficients for calculating error correction words - /// (see annex F, ISO/IEC 15438:2001(E)) - /// - private static readonly int[][] EC_COEFFICIENTS = - { - new[] {27, 917}, - new[] {522, 568, 723, 809}, - new[] {237, 308, 436, 284, 646, 653, 428, 379}, - new[] - { - 274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, - 42, 176, 65 - }, - new[] - { - 361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, - 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, - 133, 231, 390, 685, 330, 63, 410 - }, - new[] - { - 539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, - 877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, - 376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, - 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648, - 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, - 623, 264, 543 - }, - new[] - { - 521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, - 925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, - 148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594, - 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193, - 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, - 463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447, - 90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 378, 382, - 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, - 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, - 587, 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834, - 315, 550, 86, 801, 4, 108, 539 - }, - new[] - { - 524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, - 786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, - 733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, - 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, 439, - 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, - 549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749, - 812, 684, 461, 334, 376, 849, 521, 307, 291, 803, 712, 19, - 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637, - 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, - 538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802, - 580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, - 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722, - 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, - 60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756, - 60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32, - 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73, - 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, - 791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, - 54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167, - 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, 404, - 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, - 55, 497, 10 - }, - new[] - { - 352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, - 380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, - 871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435, - 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539, - 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, - 916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752, - 472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 407, 855, - 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, - 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, - 192, 516, 258, 240, 518, 794, 395, 768, 848, 51, 610, 384, - 168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156, - 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40, - 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, - 92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8, - 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, - 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669, - 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, - 591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662, - 777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245, - 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842, - 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, - 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343, - 693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708, - 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, - 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, - 247, 184, 45, 787, 680, 18, 66, 407, 369, 54, 492, 228, - 613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207, - 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242, - 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, - 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459, - 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, - 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660, - 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, - 336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751, - 353, 62, 366, 691, 379, 687, 842, 37, 357, 720, 742, 330, - 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342, - 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, - 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762, - 752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, - 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, - 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, - 223, 849, 647, 63, 310, 863, 251, 366, 304, 282, 738, 675, - 410, 389, 244, 31, 121, 303, 263 - } - }; - - /// - /// Determines the number of error correction codewords for a specified error correction - /// level. - /// - /// the error correction level (0-8) - /// the number of codewords generated for error correction - internal static int getErrorCorrectionCodewordCount(int errorCorrectionLevel) - { - if (errorCorrectionLevel < 0 || errorCorrectionLevel > 8) - { - throw new ArgumentException("Error correction level must be between 0 and 8!"); - } - return 1 << (errorCorrectionLevel + 1); - } - - /// - /// Returns the recommended minimum error correction level as described in annex E of - /// ISO/IEC 15438:2001(E). - /// - /// the number of data codewords - /// the recommended minimum error correction level - internal static int getRecommendedMinimumErrorCorrectionLevel(int n) - { - if (n <= 0) - { - throw new ArgumentException("n must be > 0"); - } - if (n <= 40) - { - return 2; - } - if (n <= 160) - { - return 3; - } - if (n <= 320) - { - return 4; - } - if (n <= 863) - { - return 5; - } - throw new WriterException("No recommendation possible"); - } - - /// - /// Generates the error correction codewords according to 4.10 in ISO/IEC 15438:2001(E). - /// - /// the data codewords - /// the error correction level (0-8) - /// the String representing the error correction codewords - internal static String generateErrorCorrection(String dataCodewords, int errorCorrectionLevel) - { - int k = getErrorCorrectionCodewordCount(errorCorrectionLevel); - char[] e = new char[k]; - int sld = dataCodewords.Length; - for (int i = 0; i < sld; i++) - { - int t1 = (dataCodewords[i] + e[e.Length - 1])%929; - int t2; - int t3; - for (int j = k - 1; j >= 1; j--) - { - t2 = (t1*EC_COEFFICIENTS[errorCorrectionLevel][j])%929; - t3 = 929 - t2; - e[j] = (char) ((e[j - 1] + t3)%929); - } - t2 = (t1*EC_COEFFICIENTS[errorCorrectionLevel][0])%929; - t3 = 929 - t2; - e[0] = (char) (t3%929); - } - StringBuilder sb = new StringBuilder(k); - for (int j = k - 1; j >= 0; j--) - { - if (e[j] != 0) - { - e[j] = (char) (929 - e[j]); - } - sb.Append(e[j]); - } - return sb.ToString(); - } - } - - /// - /// defines the level of the error correction / count of error correction codewords - /// - public enum PDF417ErrorCorrectionLevel - { - L0 = 0, - L1, - L2, - L3, - L4, - L5, - L6, - L7, - L8 - } -} \ No newline at end of file diff --git a/zxing.core/xx/pdf417/encoder/PDF417HighLevelEncoder.cs b/zxing.core/xx/pdf417/encoder/PDF417HighLevelEncoder.cs deleted file mode 100644 index 023944f..0000000 --- a/zxing.core/xx/pdf417/encoder/PDF417HighLevelEncoder.cs +++ /dev/null @@ -1,775 +0,0 @@ -/* - * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This file has been modified from its original form in Barcode4J. - */ - -using System; -using System.Numerics; -using System.Text; - -using ZXing.Common; - -namespace ZXing.PDF417.Internal -{ - /// - /// PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in - /// annex P. - /// - internal static class PDF417HighLevelEncoder - { - /// - /// code for Text compaction - /// - private const int TEXT_COMPACTION = 0; - - /// - /// code for Byte compaction - /// - private const int BYTE_COMPACTION = 1; - - /// - /// code for Numeric compaction - /// - private const int NUMERIC_COMPACTION = 2; - - /// - /// Text compaction submode Alpha - /// - private const int SUBMODE_ALPHA = 0; - - /// - /// Text compaction submode Lower - /// - private const int SUBMODE_LOWER = 1; - - /// - /// Text compaction submode Mixed - /// - private const int SUBMODE_MIXED = 2; - - /// - /// Text compaction submode Punctuation - /// - private const int SUBMODE_PUNCTUATION = 3; - - /// - /// mode latch to Text Compaction mode - /// - private const int LATCH_TO_TEXT = 900; - - /// - /// mode latch to Byte Compaction mode (number of characters NOT a multiple of 6) - /// - private const int LATCH_TO_BYTE_PADDED = 901; - - /// - /// mode latch to Numeric Compaction mode - /// - private const int LATCH_TO_NUMERIC = 902; - - /// - /// mode shift to Byte Compaction mode - /// - private const int SHIFT_TO_BYTE = 913; - - /// - /// mode latch to Byte Compaction mode (number of characters a multiple of 6) - /// - private const int LATCH_TO_BYTE = 924; - - /// - /// identifier for a user defined Extended Channel Interpretation (ECI) - /// - private const int ECI_USER_DEFINED = 925; - - /// - /// identifier for a general purpose ECO format - /// - private const int ECI_GENERAL_PURPOSE = 926; - - /// - /// identifier for an ECI of a character set of code page - /// - private const int ECI_CHARSET = 927; - - /// - /// Raw code table for text compaction Mixed sub-mode - /// - private static readonly sbyte[] TEXT_MIXED_RAW = - { - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, - 35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0 - }; - - /// - /// Raw code table for text compaction: Punctuation sub-mode - /// - private static readonly sbyte[] TEXT_PUNCTUATION_RAW = - { - 59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, - 10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0 - }; - - private static readonly sbyte[] MIXED = new sbyte[128]; - private static readonly sbyte[] PUNCTUATION = new sbyte[128]; - - internal static string DEFAULT_ENCODING_NAME = "ISO-8859-1"; - - static PDF417HighLevelEncoder() - { - //Construct inverse lookups - for (int idx = 0; idx < MIXED.Length; idx++) - MIXED[idx] = -1; - for (sbyte i = 0; i < TEXT_MIXED_RAW.Length; i++) - { - sbyte b = TEXT_MIXED_RAW[i]; - if (b > 0) - { - MIXED[b] = i; - } - } - for (int idx = 0; idx < PUNCTUATION.Length; idx++) - PUNCTUATION[idx] = -1; - for (sbyte i = 0; i < TEXT_PUNCTUATION_RAW.Length; i++) - { - sbyte b = TEXT_PUNCTUATION_RAW[i]; - if (b > 0) - { - PUNCTUATION[b] = i; - } - } - } - - /// - /// Performs high-level encoding of a PDF417 message using the algorithm described in annex P - /// of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction - /// is used. - /// - /// the message - /// compaction mode to use - /// character encoding used to encode in default or byte compaction - /// or null for default / not applicable - /// if true, don't add an ECI segment for different encodings than default - /// the encoded message (the char values range from 0 to 928) - internal static String encodeHighLevel(String msg, Compaction compaction, Encoding encoding, bool disableEci) - { - //the codewords 0..928 are encoded as Unicode characters - var sb = new StringBuilder(msg.Length); - - if (encoding != null && !disableEci && String.Compare(DEFAULT_ENCODING_NAME, encoding.WebName, StringComparison.Ordinal) != 0) - { - CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding.WebName); - if (eci != null) - { - encodingECI(eci.Value, sb); - } - } - - int len = msg.Length; - int p = 0; - int textSubMode = SUBMODE_ALPHA; - - // User selected encoding mode - byte[] bytes = null; //Fill later and only if needed - if (compaction == Compaction.TEXT) - { - encodeText(msg, p, len, sb, textSubMode); - - } - else if (compaction == Compaction.BYTE) - { - bytes = toBytes(msg, encoding); - encodeBinary(bytes, p, bytes.Length, BYTE_COMPACTION, sb); - - } - else if (compaction == Compaction.NUMERIC) - { - sb.Append((char) LATCH_TO_NUMERIC); - encodeNumeric(msg, p, len, sb); - - } - else - { - int encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1 - while (p < len) - { - int n = determineConsecutiveDigitCount(msg, p); - if (n >= 13) - { - sb.Append((char) LATCH_TO_NUMERIC); - encodingMode = NUMERIC_COMPACTION; - textSubMode = SUBMODE_ALPHA; //Reset after latch - encodeNumeric(msg, p, n, sb); - p += n; - } - else - { - int t = determineConsecutiveTextCount(msg, p); - if (t >= 5 || n == len) - { - if (encodingMode != TEXT_COMPACTION) - { - sb.Append((char) LATCH_TO_TEXT); - encodingMode = TEXT_COMPACTION; - textSubMode = SUBMODE_ALPHA; //start with submode alpha after latch - } - textSubMode = encodeText(msg, p, t, sb, textSubMode); - p += t; - } - else - { - if (bytes == null) - { - bytes = toBytes(msg, encoding); - } - int b = determineConsecutiveBinaryCount(msg, bytes, p); - if (b == 0) - { - b = 1; - } - if (b == 1 && encodingMode == TEXT_COMPACTION) - { - //Switch for one byte (instead of latch) - encodeBinary(bytes, p, 1, TEXT_COMPACTION, sb); - } - else - { - //Mode latch performed by encodeBinary() - encodeBinary(bytes, - toBytes(msg.Substring(0, p), encoding).Length, - toBytes(msg.Substring(p, b), encoding).Length, - encodingMode, - sb); - encodingMode = BYTE_COMPACTION; - textSubMode = SUBMODE_ALPHA; //Reset after latch - } - p += b; - } - } - } - } - - return sb.ToString(); - } - - private static bool Contains(string[] stringArray, string lookFor) - { - var result = false; - lookFor = lookFor.ToUpper(); - for (var index = 0; index < stringArray.Length; index++) - { - if (stringArray[index] == lookFor) - { - result = true; - break; - } - } - - return result; - } - - private static byte[] toBytes(String msg, Encoding encoding) - { - // Defer instantiating default Charset until needed, since it may be for an unsupported - // encoding. - if (encoding == null) - { - try - { - encoding = Encoding.GetEncoding(DEFAULT_ENCODING_NAME); - } - catch (Exception ) - { - // continue - } - if (encoding == null) - { - // Fallbacks - try - { -#if WindowsCE - try - { - encoding = Encoding.GetEncoding(1252); - } - catch (PlatformNotSupportedException) - { - // WindowsCE doesn't support all encodings. But it is device depended. - // So we try here some different ones - encoding = Encoding.GetEncoding("CP437"); - } -#else - // Silverlight supports only UTF-8 and UTF-16 out-of-the-box - encoding = Encoding.GetEncoding("UTF-8"); -#endif - - } - catch (Exception uce) - { - throw new WriterException("No support for any encoding: " + DEFAULT_ENCODING_NAME, uce); - } - } - } - return encoding.GetBytes(msg); - } - - /// - /// Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E), - /// chapter 4.4.2. - /// - /// the message - /// the start position within the message - /// the number of characters to encode - /// receives the encoded codewords - /// should normally be SUBMODE_ALPHA - /// the text submode in which this method ends - /// - private static int encodeText(String msg, - int startpos, - int count, - StringBuilder sb, - int initialSubmode) - { - StringBuilder tmp = new StringBuilder(count); - int submode = initialSubmode; - int idx = 0; - while (true) - { - char ch = msg[startpos + idx]; - switch (submode) - { - case SUBMODE_ALPHA: - if (isAlphaUpper(ch)) - { - if (ch == ' ') - { - tmp.Append((char) 26); //space - } - else - { - tmp.Append((char) (ch - 65)); - } - } - else - { - if (isAlphaLower(ch)) - { - submode = SUBMODE_LOWER; - tmp.Append((char) 27); //ll - continue; - } - else if (isMixed(ch)) - { - submode = SUBMODE_MIXED; - tmp.Append((char) 28); //ml - continue; - } - else - { - tmp.Append((char) 29); //ps - tmp.Append((char) PUNCTUATION[ch]); - break; - } - } - break; - case SUBMODE_LOWER: - if (isAlphaLower(ch)) - { - if (ch == ' ') - { - tmp.Append((char) 26); //space - } - else - { - tmp.Append((char) (ch - 97)); - } - } - else - { - if (isAlphaUpper(ch)) - { - tmp.Append((char) 27); //as - tmp.Append((char) (ch - 65)); - //space cannot happen here, it is also in "Lower" - break; - } - else if (isMixed(ch)) - { - submode = SUBMODE_MIXED; - tmp.Append((char) 28); //ml - continue; - } - else - { - tmp.Append((char) 29); //ps - tmp.Append((char) PUNCTUATION[ch]); - break; - } - } - break; - case SUBMODE_MIXED: - if (isMixed(ch)) - { - tmp.Append((char) MIXED[ch]); - } - else - { - if (isAlphaUpper(ch)) - { - submode = SUBMODE_ALPHA; - tmp.Append((char) 28); //al - continue; - } - else if (isAlphaLower(ch)) - { - submode = SUBMODE_LOWER; - tmp.Append((char) 27); //ll - continue; - } - else - { - if (startpos + idx + 1 < count) - { - char next = msg[startpos + idx + 1]; - if (isPunctuation(next)) - { - submode = SUBMODE_PUNCTUATION; - tmp.Append((char) 25); //pl - continue; - } - } - tmp.Append((char) 29); //ps - tmp.Append((char) PUNCTUATION[ch]); - } - } - break; - default: //SUBMODE_PUNCTUATION - if (isPunctuation(ch)) - { - tmp.Append((char) PUNCTUATION[ch]); - } - else - { - submode = SUBMODE_ALPHA; - tmp.Append((char) 29); //al - continue; - } - break; - } - idx++; - if (idx >= count) - { - break; - } - } - char h = (char) 0; - int len = tmp.Length; - for (int i = 0; i < len; i++) - { - bool odd = (i%2) != 0; - if (odd) - { - h = (char) ((h*30) + tmp[i]); - sb.Append(h); - } - else - { - h = tmp[i]; - } - } - if ((len%2) != 0) - { - sb.Append((char) ((h*30) + 29)); //ps - } - return submode; - } - - /// - /// Encode parts of the message using Byte Compaction as described in ISO/IEC 15438:2001(E), - /// chapter 4.4.3. The Unicode characters will be converted to binary using the cp437 - /// codepage. - /// - /// the message converted to a byte array - /// the start position within the message - /// the number of bytes to encode - /// the mode from which this method starts - /// receives the encoded codewords - /// - private static void encodeBinary(byte[] bytes, - int startpos, - int count, - int startmode, - StringBuilder sb) - { - if (count == 1 && startmode == TEXT_COMPACTION) - { - sb.Append((char) SHIFT_TO_BYTE); - } - else - { - bool sixpack = ((count % 6) == 0); - if (sixpack) - { - sb.Append((char)LATCH_TO_BYTE); - } - else - { - sb.Append((char)LATCH_TO_BYTE_PADDED); - } - } - - int idx = startpos; - // Encode sixpacks - if (count >= 6) - { - char[] chars = new char[5]; - while ((startpos + count - idx) >= 6) - { - long t = 0; - for (int i = 0; i < 6; i++) - { - t <<= 8; - t += bytes[idx + i] & 0xff; - } - for (int i = 0; i < 5; i++) - { - chars[i] = (char) (t%900); - t /= 900; - } - for (int i = chars.Length - 1; i >= 0; i--) - { - sb.Append(chars[i]); - } - idx += 6; - } - } - //Encode rest (remaining n<5 bytes if any) - for (int i = idx; i < startpos + count; i++) - { - int ch = bytes[i] & 0xff; - sb.Append((char) ch); - } - } - - private static void encodeNumeric(String msg, int startpos, int count, StringBuilder sb) - { - int idx = 0; - StringBuilder tmp = new StringBuilder(count/3 + 1); - BigInteger num900 = new BigInteger(900); - BigInteger num0 = new BigInteger(0); - while (idx < count - 1) - { - tmp.Length = 0; - int len = Math.Min(44, count - idx); - String part = '1' + msg.Substring(startpos + idx, len); - BigInteger bigint = BigInteger.Parse(part); - do - { - BigInteger c = bigint%num900; - tmp.Append((char) c); - bigint = BigInteger.Divide(bigint, num900); - } while (!bigint.Equals(num0)); - - //Reverse temporary string - for (int i = tmp.Length - 1; i >= 0; i--) - { - sb.Append(tmp[i]); - } - idx += len; - } - } - - - private static bool isDigit(char ch) - { - return ch >= '0' && ch <= '9'; - } - - private static bool isAlphaUpper(char ch) - { - return ch == ' ' || (ch >= 'A' && ch <= 'Z'); - } - - private static bool isAlphaLower(char ch) - { - return ch == ' ' || (ch >= 'a' && ch <= 'z'); - } - - private static bool isMixed(char ch) - { - return MIXED[ch] != -1; - } - - private static bool isPunctuation(char ch) - { - return PUNCTUATION[ch] != -1; - } - - private static bool isText(char ch) - { - return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126); - } - - /// - /// Determines the number of consecutive characters that are encodable using numeric compaction. - /// - /// the message - /// the start position within the message - /// the requested character count - /// - private static int determineConsecutiveDigitCount(String msg, int startpos) - { - int count = 0; - int len = msg.Length; - int idx = startpos; - if (idx < len) - { - char ch = msg[idx]; - while (isDigit(ch) && idx < len) - { - count++; - idx++; - if (idx < len) - { - ch = msg[idx]; - } - } - } - return count; - } - - /// - /// Determines the number of consecutive characters that are encodable using text compaction. - /// - /// the message - /// the start position within the message - /// the requested character count - /// - private static int determineConsecutiveTextCount(String msg, int startpos) - { - int len = msg.Length; - int idx = startpos; - while (idx < len) - { - char ch = msg[idx]; - int numericCount = 0; - while (numericCount < 13 && isDigit(ch) && idx < len) - { - numericCount++; - idx++; - if (idx < len) - { - ch = msg[idx]; - } - } - if (numericCount >= 13) - { - return idx - startpos - numericCount; - } - if (numericCount > 0) - { - //Heuristic: All text-encodable chars or digits are binary encodable - continue; - } - ch = msg[idx]; - - //Check if character is encodable - if (!isText(ch)) - { - break; - } - idx++; - } - return idx - startpos; - } - - /// - /// Determines the number of consecutive characters that are encodable using binary compaction. - /// - /// the message - /// the message converted to a byte array - /// the start position within the message - /// the requested character count - /// - private static int determineConsecutiveBinaryCount(String msg, byte[] bytes, int startpos) - { - int len = msg.Length; - int idx = startpos; - int idxb = idx; // bytes index (may differ from idx for utf-8 and other unicode encodings) - while (idx < len) - { - char ch = msg[idx]; - int numericCount = 0; - - while (numericCount < 13 && isDigit(ch)) - { - numericCount++; - //textCount++; - int i = idx + numericCount; - if (i >= len) - { - break; - } - ch = msg[i]; - } - if (numericCount >= 13) - { - return idx - startpos; - } - ch = msg[idx]; - - //Check if character is encodable - //Sun returns a ASCII 63 (?) for a character that cannot be mapped. Let's hope all - //other VMs do the same - if (bytes[idxb] == 63 && ch != '?') - { - throw new WriterException("Non-encodable character detected: " + ch + " (Unicode: " + (int) ch + ')'); - } - idx++; - idxb++; - if (ch >= 256) // for non-ascii symbols - idxb++; - } - return idx - startpos; - } - - private static void encodingECI(int eci, StringBuilder sb) - { - if (eci >= 0 && eci < 900) - { - sb.Append((char) ECI_CHARSET); - sb.Append((char) eci); - } - else if (eci < 810900) - { - sb.Append((char) ECI_GENERAL_PURPOSE); - sb.Append((char) (eci/900 - 1)); - sb.Append((char) (eci%900)); - } - else if (eci < 811800) - { - sb.Append((char) ECI_USER_DEFINED); - sb.Append((char) (810900 - eci)); - } - else - { - throw new WriterException("ECI number not in valid range from 0..811799, but was " + eci); - } - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeReader.Extensions.cs b/zxing.core/xx/presentation/BarcodeReader.Extensions.cs deleted file mode 100644 index 0194ed4..0000000 --- a/zxing.core/xx/presentation/BarcodeReader.Extensions.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing -{ - using System.Windows.Media.Imaging; - - /// - /// extensions methods which are working directly on any IBarcodeReaderGeneric implementation - /// - public static class BarcodeReaderExtensions - { - /// - /// uses the IBarcodeReaderGeneric implementation and the class for decoding - /// - /// - /// - /// - public static Result Decode(this IBarcodeReaderGeneric reader, BitmapSource image) - { - var luminanceSource = new BitmapSourceLuminanceSource(image); - return reader.Decode(luminanceSource); - } - - /// - /// uses the IBarcodeReaderGeneric implementation and the class for decoding - /// - /// - /// - /// - public static Result[] DecodeMultiple(this IBarcodeReaderGeneric reader, BitmapSource image) - { - var luminanceSource = new BitmapSourceLuminanceSource(image); - return reader.DecodeMultiple(luminanceSource); - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeReader.cs b/zxing.core/xx/presentation/BarcodeReader.cs deleted file mode 100644 index 0b6806e..0000000 --- a/zxing.core/xx/presentation/BarcodeReader.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright 2012 ZXing.Net authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT 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.Windows.Media.Imaging; - -namespace ZXing.Presentation -{ - /// - /// A smart class to decode the barcode inside a bitmap object which is derived from BitmapSource - /// - public class BarcodeReader : BarcodeReader - { - private static readonly Func defaultCreateLuminanceSource = - bitmap => new BitmapSourceLuminanceSource(bitmap); - - /// - /// Initializes a new instance of the class. - /// - public BarcodeReader() - : this(null, defaultCreateLuminanceSource, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Sets the reader which should be used to find and decode the barcode. - /// If null then MultiFormatReader is used - /// Sets the function to create a luminance source object for a bitmap. - /// If null, default is used - /// Sets the function to create a binarizer object for a luminance source. - /// If null then HybridBinarizer is used - public BarcodeReader(Reader reader, - Func createLuminanceSource, - Func createBinarizer - ) - : base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Sets the reader which should be used to find and decode the barcode. - /// If null then MultiFormatReader is used - /// Sets the function to create a luminance source object for a bitmap. - /// If null, default is used - /// Sets the function to create a binarizer object for a luminance source. - /// If null then HybridBinarizer is used - /// The create RGB luminance source. - public BarcodeReader(Reader reader, - Func createLuminanceSource, - Func createBinarizer, - Func createRGBLuminanceSource - ) - : base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer, createRGBLuminanceSource) - { - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeWriter.Extensions.cs b/zxing.core/xx/presentation/BarcodeWriter.Extensions.cs deleted file mode 100644 index 3d4c77a..0000000 --- a/zxing.core/xx/presentation/BarcodeWriter.Extensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing -{ - using System.Windows.Media.Imaging; - - using Rendering; - - /// - /// extensions methods which are working directly on any BarcodeWriterGeneric implementation - /// - public static class BarcodeWriterExtensions - { - /// - /// uses the BarcodeWriterGeneric implementation and the class for decoding - /// - /// - /// - /// - public static WriteableBitmap WriteAsWriteableBitmap(this IBarcodeWriterGeneric writer, string content) - { - var bitmatrix = writer.Encode(content); - var renderer = new WriteableBitmapRenderer(); - return renderer.Render(bitmatrix, writer.Format, content, writer.Options); - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeWriter.cs b/zxing.core/xx/presentation/BarcodeWriter.cs deleted file mode 100644 index dd88f32..0000000 --- a/zxing.core/xx/presentation/BarcodeWriter.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright 2014 ZXing.Net authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT 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.Windows.Media.Imaging; - -using ZXing.Rendering; - -namespace ZXing.Presentation -{ - /// - /// A smart class to encode some content to a barcode image - /// - public class BarcodeWriter : BarcodeWriterGeneric - { - /// - /// Initializes a new instance of the class. - /// - public BarcodeWriter() - { - Renderer = new WriteableBitmapRenderer(); - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeWriterGeometry.Extensions.cs b/zxing.core/xx/presentation/BarcodeWriterGeometry.Extensions.cs deleted file mode 100644 index 6d7b364..0000000 --- a/zxing.core/xx/presentation/BarcodeWriterGeometry.Extensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing -{ - using System.Windows.Media; - - using Rendering; - - /// - /// extensions methods which are working directly on any BarcodeWriterGeneric implementation - /// - public static class BarcodeWriterGeometryExtensions - { - /// - /// uses the BarcodeWriterGeneric implementation and the class for decoding - /// - /// - /// - /// - public static Geometry WriteAsGeometry(this IBarcodeWriterGeneric writer, string content) - { - var bitmatrix = writer.Encode(content); - var renderer = new GeometryRenderer(); - return renderer.Render(bitmatrix, writer.Format, content, writer.Options); - } - } -} diff --git a/zxing.core/xx/presentation/BarcodeWriterGeometry.cs b/zxing.core/xx/presentation/BarcodeWriterGeometry.cs deleted file mode 100644 index 559c267..0000000 --- a/zxing.core/xx/presentation/BarcodeWriterGeometry.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.Windows.Media; - -using ZXing.Rendering; - -namespace ZXing.Presentation -{ - /// - /// A smart class to encode some content to a barcode image into a geometry - /// Autor: Rob Fonseca-Ensor - /// - public class BarcodeWriterGeometry : BarcodeWriter - { - /// - /// Initializes a new instance of the class. - /// - public BarcodeWriterGeometry() - { - Renderer = new GeometryRenderer(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/project.json b/zxing.core/xx/project.json deleted file mode 100644 index 3121628..0000000 --- a/zxing.core/xx/project.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "title": "ZXing for .NET Core", - "version": "0.14.0.2", - "projectUrl": "https://github.com/abrodersen/zxing-core", - "buildOptions": { - "compile": [ "**/*.cs" ], - "debugType": "portable" - }, - "packOptions": { - "owners": [ "ZXing.Net authors", "Aaron Brodersen" ], - "authors": [ "ZXing.Net authors", "Aaron Brodersen" ], - "summary": "zxing-core is a fork of ZXing.Net. It has been modified to be compatible with .NET Core.", - "licenseUrl": "https://raw.githubusercontent.com/abrodersen/zxing-core/master/LICENSE", - "iconUrl": "https://raw.githubusercontent.com/abrodersen/zxing-core/master/logo.jpg", - "repository": { - "type": "git", - "url": "git://github.com/abrodersen/zxing-core" - }, - "tags": [ - "ZXing", "barcode", "scanning", "1D", "2D", "UPC-A", "UPC-E", "EAN-8", "EAN-13", "QR", "ITF", "Codabar", "RSS-14", "Data", "Matrix", "PDF", "417", "PDF417", "Aztec" - ], - "releaseNotes": "update to netstandard1.3" - }, - "dependencies": { }, - "frameworks" : { - "netstandard1.3": { - "dependencies": { - "NETStandard.Library": "1.6.0" - } - } - } -} diff --git a/zxing.core/xx/qrcode/QRCodeReader.cs b/zxing.core/xx/qrcode/QRCodeReader.cs deleted file mode 100644 index 83c3fa8..0000000 --- a/zxing.core/xx/qrcode/QRCodeReader.cs +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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; - -using ZXing.Common; -using ZXing.QrCode.Internal; - -namespace ZXing.QrCode -{ - /// - /// This implementation can detect and decode QR Codes in an image. - /// Sean Owen - /// - public class QRCodeReader : Reader - { - private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; - - private readonly Decoder decoder = new Decoder(); - - /// - /// Gets the decoder. - /// - /// - protected Decoder getDecoder() - { - return decoder; - } - - /// - /// Locates and decodes a QR code in an image. - /// - /// a String representing the content encoded by the QR code - /// - public Result decode(BinaryBitmap image) - { - return decode(image, null); - } - - /// - /// 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 - /// - public Result decode(BinaryBitmap image, IDictionary hints) - { - DecoderResult decoderResult; - ResultPoint[] points; - if (image == null || image.BlackMatrix == null) - { - // something is wrong with the image - return null; - } - if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) - { - var bits = extractPureBits(image.BlackMatrix); - if (bits == null) - return null; - decoderResult = decoder.decode(bits, hints); - points = NO_POINTS; - } - else - { - var detectorResult = new Detector(image.BlackMatrix).detect(hints); - if (detectorResult == null) - return null; - decoderResult = decoder.decode(detectorResult.Bits, hints); - points = detectorResult.Points; - } - if (decoderResult == null) - return null; - - // If the code was mirrored: swap the bottom-left and the top-right points. - var data = decoderResult.Other as QRCodeDecoderMetaData; - if (data != null) - { - data.applyMirroredCorrection(points); - } - - var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); - var byteSegments = decoderResult.ByteSegments; - if (byteSegments != null) - { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); - } - var ecLevel = decoderResult.ECLevel; - if (ecLevel != null) - { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); - } - if (decoderResult.StructuredAppend) - { - result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE, decoderResult.StructuredAppendSequenceNumber); - result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_PARITY, decoderResult.StructuredAppendParity); - } - return result; - } - - /// - /// Resets any internal state the implementation has after a decode, to prepare it - /// for reuse. - /// - 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. - /// - /// - /// - private static BitMatrix extractPureBits(BitMatrix image) - { - int[] leftTopBlack = image.getTopLeftOnBit(); - int[] rightBottomBlack = image.getBottomRightOnBit(); - if (leftTopBlack == null || rightBottomBlack == null) - { - return null; - } - - float moduleSize; - if (!QRCodeReader.moduleSize(leftTopBlack, image, out moduleSize)) - return null; - - int top = leftTopBlack[1]; - int bottom = rightBottomBlack[1]; - int left = leftTopBlack[0]; - int right = rightBottomBlack[0]; - - // Sanity check! - if (left >= right || top >= bottom) - { - return null; - } - - 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) - { - return null; - } - if (matrixHeight != matrixWidth) - { - // Only possibly decode square regions - return null; - } - - // 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; - - // But careful that this does not sample off the edge - // "right" is the farthest-right valid pixel location -- right+1 is not necessarily - // This is positive by how much the inner x loop below would be too large - int nudgedTooFarRight = left + (int)((matrixWidth - 1) * moduleSize) - right; - if (nudgedTooFarRight > 0) - { - if (nudgedTooFarRight > nudge) - { - // Neither way fits; abort - return null; - } - left -= nudgedTooFarRight; - } - // See logic above - int nudgedTooFarDown = top + (int)((matrixHeight - 1) * moduleSize) - bottom; - if (nudgedTooFarDown > 0) - { - if (nudgedTooFarDown > nudge) - { - // Neither way fits; abort - return null; - } - top -= nudgedTooFarDown; - } - - // 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[left + (int)(x * moduleSize), iOffset]) - { - bits[x, y] = true; - } - } - } - return bits; - } - - private static bool moduleSize(int[] leftTopBlack, BitMatrix image, out float msize) - { - 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[x, y]) - { - if (++transitions == 5) - { - break; - } - inBlack = !inBlack; - } - x++; - y++; - } - if (x == width || y == height) - { - msize = 0.0f; - return false; - } - msize = (x - leftTopBlack[0]) / 7.0f; - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/QRCodeWriter.cs b/zxing.core/xx/qrcode/QRCodeWriter.cs deleted file mode 100644 index 0bf1bdf..0000000 --- a/zxing.core/xx/qrcode/QRCodeWriter.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; - -using ZXing.Common; -using ZXing.QrCode.Internal; - -namespace ZXing.QrCode -{ - /// - /// This object renders a QR Code as a BitMatrix 2D array of greyscale values. - /// - /// dswitkin@google.com (Daniel Switkin) - /// - public sealed class QRCodeWriter : Writer - { - private const int QUIET_ZONE_SIZE = 4; - - /// - /// 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) - /// - public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) - { - return encode(contents, format, width, height, null); - } - - /// - /// - /// 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) - /// - public BitMatrix encode(String contents, - BarcodeFormat format, - int width, - int height, - IDictionary hints) - { - if (String.IsNullOrEmpty(contents)) - { - throw new ArgumentException("Found empty contents"); - } - - if (format != BarcodeFormat.QR_CODE) - { - throw new ArgumentException("Can only encode QR_CODE, but got " + format); - } - - if (width < 0 || height < 0) - { - throw new ArgumentException("Requested dimensions are too small: " + width + 'x' + height); - } - - var errorCorrectionLevel = ErrorCorrectionLevel.L; - int quietZone = QUIET_ZONE_SIZE; - if (hints != null) - { - var requestedECLevel = hints.ContainsKey(EncodeHintType.ERROR_CORRECTION) ? (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION] : null; - if (requestedECLevel != null) - { - errorCorrectionLevel = requestedECLevel; - } - var quietZoneInt = hints.ContainsKey(EncodeHintType.MARGIN) ? (int)hints[EncodeHintType.MARGIN] : (int?)null; - if (quietZoneInt != null) - { - quietZone = quietZoneInt.Value; - } - } - - var 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) - { - var 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; - - var 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[inputX, inputY] == 1) - { - output.setRegion(outputX, outputY, multiple, multiple); - } - } - } - - return output; - } - } -} diff --git a/zxing.core/xx/qrcode/decoder/BitMatrixParser.cs b/zxing.core/xx/qrcode/decoder/BitMatrixParser.cs deleted file mode 100644 index 90d911f..0000000 --- a/zxing.core/xx/qrcode/decoder/BitMatrixParser.cs +++ /dev/null @@ -1,281 +0,0 @@ -/* -* 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 ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - /// Sean Owen - sealed class BitMatrixParser - { - private readonly BitMatrix bitMatrix; - private Version parsedVersion; - private FormatInformation parsedFormatInfo; - private bool mirrored; - - /// {@link BitMatrix} to parse - /// ReaderException if dimension is not >= 21 and 1 mod 4 - internal static BitMatrixParser createBitMatrixParser(BitMatrix bitMatrix) - { - int dimension = bitMatrix.Height; - if (dimension < 21 || (dimension & 0x03) != 1) - { - return null; - } - return new BitMatrixParser(bitMatrix); - } - - private BitMatrixParser(BitMatrix bitMatrix) - { - // Should only be called from createBitMatrixParser with the important checks before - this.bitMatrix = bitMatrix; - } - - ///

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() - { - if (parsedFormatInfo != null) - { - return parsedFormatInfo; - } - - // Read top-left format info bits - int formatInfoBits1 = 0; - for (int i = 0; i < 6; i++) - { - 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; - } - return null; - } - - ///

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() - { - 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); - } - } - - 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--) - { - versionBits = copyBit(i, j, versionBits); - } - } - - parsedVersion = Version.decodeVersionInformation(versionBits); - if (parsedVersion != null && parsedVersion.DimensionForVersion == dimension) - { - return parsedVersion; - } - return null; - } - - private int copyBit(int i, int j, int versionBits) - { - bool bit = mirrored ? bitMatrix[j, i] : bitMatrix[i, j]; - return bit ? (versionBits << 1) | 0x1 : versionBits << 1; - } - - ///

Reads the bits in the {@link BitMatrix} representing the finder pattern in the - /// correct order in order to reconstruct 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 byte[] readCodewords() - { - FormatInformation formatInfo = readFormatInformation(); - if (formatInfo == null) - return null; - Version version = readVersion(); - if (version == null) - return null; - - // 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(formatInfo.DataMask); - int dimension = bitMatrix.Height; - dataMask.unmaskBitMatrix(bitMatrix, dimension); - - BitMatrix functionPattern = version.buildFunctionPattern(); - - bool readingUp = true; - byte[] result = new byte[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[j - col, i]) - { - // Read a bit - bitsRead++; - currentByte <<= 1; - if (bitMatrix[j - col, i]) - { - currentByte |= 1; - } - // If we've made a whole byte, save it off - if (bitsRead == 8) - { - result[resultOffset++] = (byte)currentByte; - bitsRead = 0; - currentByte = 0; - } - } - } - } - readingUp ^= true; // readingUp = !readingUp; // switch directions - } - if (resultOffset != version.TotalCodewords) - { - return null; - } - return result; - } - - /** - * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state. - */ - internal void remask() - { - if (parsedFormatInfo == null) - { - return; // We have no format information, and have no data mask - } - DataMask dataMask = DataMask.forReference(parsedFormatInfo.DataMask); - int dimension = bitMatrix.Height; - dataMask.unmaskBitMatrix(bitMatrix, dimension); - } - - /** - * Prepare the parser for a mirrored operation. - * This flag has effect only on the {@link #readFormatInformation()} and the - * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the - * {@link #mirror()} method should be called. - * - * @param mirror Whether to read version and format information mirrored. - */ - internal void setMirror(bool mirror) - { - parsedVersion = null; - parsedFormatInfo = null; - mirrored = mirror; - } - - /** Mirror the bit matrix in order to attempt a second reading. */ - internal void mirror() - { - for (int x = 0; x < bitMatrix.Width; x++) - { - for (int y = x + 1; y < bitMatrix.Height; y++) - { - if (bitMatrix[x, y] != bitMatrix[y, x]) - { - bitMatrix.flip(y, x); - bitMatrix.flip(x, y); - } - } - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/DataBlock.cs b/zxing.core/xx/qrcode/decoder/DataBlock.cs deleted file mode 100644 index 97cabf6..0000000 --- a/zxing.core/xx/qrcode/decoder/DataBlock.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - ///

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.

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - internal sealed class DataBlock - { - private readonly int numDataCodewords; - private readonly byte[] codewords; - - private DataBlock(int numDataCodewords, byte[] 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 - /// - /// {@link DataBlock}s containing original bytes, "de-interleaved" from representation in the - /// QR Code - /// - internal static DataBlock[] getDataBlocks(byte[] rawCodewords, Version version, ErrorCorrectionLevel ecLevel) - { - - 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(); - foreach (var ecBlock in ecBlockArray) - { - totalBlocks += ecBlock.Count; - } - - // Now establish DataBlocks of the appropriate size and number of data codewords - DataBlock[] result = new DataBlock[totalBlocks]; - int numResultBlocks = 0; - foreach (var ecBlock in ecBlockArray) - { - for (int i = 0; i < ecBlock.Count; i++) - { - int numDataCodewords = ecBlock.DataCodewords; - int numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; - result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[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; - } - - internal int NumDataCodewords - { - get - { - return numDataCodewords; - } - } - - internal byte[] Codewords - { - get - { - return codewords; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/DataMask.cs b/zxing.core/xx/qrcode/decoder/DataMask.cs deleted file mode 100644 index 2b4f2dd..0000000 --- a/zxing.core/xx/qrcode/decoder/DataMask.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* -* 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 ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - ///

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.

- /// - ///

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.

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - abstract class DataMask - { - /// See ISO 18004:2006 6.8.1 - 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() - { - } - - ///

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)) - { - 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) - { - if (reference < 0 || reference > 7) - { - throw new System.ArgumentException(); - } - 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) - { - return ((i + j) & 0x01) == 0; - } - } - - /// 001: mask bits for which x mod 2 == 0 - private sealed class DataMask001 : DataMask - { - internal override bool isMasked(int i, int j) - { - return (i & 0x01) == 0; - } - } - - /// 010: mask bits for which y mod 3 == 0 - private sealed class DataMask010 : DataMask - { - internal override bool isMasked(int i, int j) - { - return j % 3 == 0; - } - } - - /// 011: mask bits for which (x + y) mod 3 == 0 - private sealed class DataMask011 : DataMask - { - internal override bool isMasked(int i, int j) - { - return (i + j) % 3 == 0; - } - } - - /// 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) - { - return ((((int)((uint)i >> 1)) + (j / 3)) & 0x01) == 0; - } - } - - /// 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) - { - 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 sealed class DataMask110 : DataMask - { - internal override bool isMasked(int i, int j) - { - 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 sealed class DataMask111 : DataMask - { - internal override bool isMasked(int i, int j) - { - return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs b/zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs deleted file mode 100644 index 4af430c..0000000 --- a/zxing.core/xx/qrcode/decoder/DecodedBitStreamParser.cs +++ /dev/null @@ -1,524 +0,0 @@ -/* -* 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; -using System.Text; - -using ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - ///

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

- /// Sean Owen - ///
- internal static class 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; - - internal static DecoderResult decode(byte[] bytes, - Version version, - ErrorCorrectionLevel ecLevel, - IDictionary hints) - { - var bits = new BitSource(bytes); - var result = new StringBuilder(50); - var byteSegments = new List(1); - var symbolSequence = -1; - var parityData = -1; - - try - { - CharacterSetECI currentCharacterSetECI = null; - bool fc1InEffect = false; - Mode mode; - do - { - // While still another segment to read... - if (bits.available() < 4) - { - // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here - mode = Mode.TERMINATOR; - } - else - { - try - { - mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits - } - catch (ArgumentException) - { - return null; - } - } - if (mode != Mode.TERMINATOR) - { - 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) - { - return null; - } - // not really supported; but sequence number and parity is added later to the result metadata - // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue - symbolSequence = bits.readBits(8); - parityData = bits.readBits(8); - } - else if (mode == Mode.ECI) - { - // Count doesn't apply to ECI - int value = parseECIValue(bits); - currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); - if (currentCharacterSetECI == null) - { - return null; - } - } - else - { - // First handle Hanzi mode which does not start with character count - if (mode == Mode.HANZI) - { - //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) - { - if (!decodeHanziSegment(bits, result, countHanzi)) - return null; - } - } - else - { - // "Normal" QR code modes: - // How many characters will follow, encoded in this mode? - int count = bits.readBits(mode.getCharacterCountBits(version)); - if (mode == Mode.NUMERIC) - { - if (!decodeNumericSegment(bits, result, count)) - return null; - } - else if (mode == Mode.ALPHANUMERIC) - { - if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) - return null; - } - else if (mode == Mode.BYTE) - { - if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints)) - return null; - } - else if (mode == Mode.KANJI) - { - if (!decodeKanjiSegment(bits, result, count)) - return null; - } - else - { - return null; - } - } - } - } - } while (mode != Mode.TERMINATOR); - } - catch (ArgumentException) - { - // from readBits() calls - return null; - } - -#if WindowsCE - var resultString = result.ToString().Replace("\n", "\r\n"); -#else - var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine); -#endif - return new DecoderResult(bytes, - resultString, - byteSegments.Count == 0 ? null : byteSegments, - ecLevel == null ? null : ecLevel.ToString(), - symbolSequence, parityData); - } - - /// - /// See specification GBT 18284-2000 - /// - /// The bits. - /// The result. - /// The count. - /// - private static bool decodeHanziSegment(BitSource bits, - StringBuilder result, - int count) - { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) - { - return false; - } - - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as GB2312 afterwards - byte[] buffer = new byte[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] = (byte)((assembledTwoBytes >> 8) & 0xFF); - buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF); - offset += 2; - count--; - } - - try - { - result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length)); - } -#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) - catch (ArgumentException) - { - try - { - // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 - result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); - } - catch (Exception) - { - return false; - } - } -#endif - catch (Exception) - { - return false; - } - - return true; - } - - private static bool decodeKanjiSegment(BitSource bits, - StringBuilder result, - int count) - { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) - { - return false; - } - - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as Shift_JIS afterwards - byte[] buffer = new byte[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] = (byte)(assembledTwoBytes >> 8); - buffer[offset + 1] = (byte)assembledTwoBytes; - offset += 2; - count--; - } - // Shift_JIS may not be supported in some environments: - try - { - result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length)); - } -#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) - catch (ArgumentException) - { - try - { - // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 - result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); - } - catch (Exception) - { - return false; - } - } -#endif - catch (Exception) - { - return false; - } - return true; - } - - private static bool decodeByteSegment(BitSource bits, - StringBuilder result, - int count, - CharacterSetECI currentCharacterSetECI, - IList byteSegments, - IDictionary hints) - { - // Don't crash trying to read more bits than we have available. - if (count << 3 > bits.available()) - { - return false; - } - - byte[] readBytes = new byte[count]; - for (int i = 0; i < count; i++) - { - readBytes[i] = (byte)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.EncodingName; - } - try - { - result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length)); - } -#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) - catch (ArgumentException) - { - try - { - // Silverlight only supports a limited number of character sets, trying fallback to UTF-8 - result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length)); - } - catch (Exception) - { - return false; - } - } -#endif -#if WindowsCE - catch (PlatformNotSupportedException) - { - try - { - // WindowsCE doesn't support all encodings. But it is device depended. - // So we try here the some different ones - if (encoding == "ISO-8859-1") - { - result.Append(Encoding.GetEncoding(1252).GetString(readBytes, 0, readBytes.Length)); - } - else - { - result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length)); - } - } - catch (Exception) - { - return false; - } - } -#endif - catch (Exception) - { - return false; - } - byteSegments.Add(readBytes); - - return true; - } - - private static char toAlphaNumericChar(int value) - { - if (value >= ALPHANUMERIC_CHARS.Length) - { - throw FormatException.Instance; - } - return ALPHANUMERIC_CHARS[value]; - } - - private static bool 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) - { - return false; - } - 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) - { - return false; - } - 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.Remove(i, 1); - result.Insert(i, new[] { (char)0x1D }); - } - } - } - } - - return true; - } - - private static bool 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) - { - return false; - } - int threeDigitsBits = bits.readBits(10); - if (threeDigitsBits >= 1000) - { - return false; - } - 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) - { - return false; - } - int twoDigitsBits = bits.readBits(7); - if (twoDigitsBits >= 100) - { - return false; - } - result.Append(toAlphaNumericChar(twoDigitsBits / 10)); - result.Append(toAlphaNumericChar(twoDigitsBits % 10)); - } - else if (count == 1) - { - // One digit left over to read - if (bits.available() < 4) - { - return false; - } - int digitBits = bits.readBits(4); - if (digitBits >= 10) - { - return false; - } - result.Append(toAlphaNumericChar(digitBits)); - } - - return true; - } - - 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 new ArgumentException("Bad ECI bits starting with byte " + firstByte); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/Decoder.cs b/zxing.core/xx/qrcode/decoder/Decoder.cs deleted file mode 100644 index 9fefda7..0000000 --- a/zxing.core/xx/qrcode/decoder/Decoder.cs +++ /dev/null @@ -1,195 +0,0 @@ -/* -* 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.Collections.Generic; - -using ZXing.Common; -using ZXing.Common.ReedSolomon; - -namespace ZXing.QrCode.Internal -{ - /// - ///

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

- ///
- /// - /// Sean Owen - /// - public sealed class Decoder - { - private readonly ReedSolomonDecoder rsDecoder; - - /// - /// Initializes a new instance of the class. - /// - public Decoder() - { - rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256); - } - - /// - ///

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 - /// decoding hints that should be used to influence decoding - /// - /// text and bytes encoded within the QR Code - /// - public DecoderResult decode(bool[][] image, IDictionary hints) - { - var dimension = image.Length; - var bits = new BitMatrix(dimension); - for (int i = 0; i < dimension; i++) - { - for (int j = 0; j < dimension; j++) - { - bits[j, i] = image[i][j]; - } - } - return decode(bits, hints); - } - - /// - ///

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 - /// decoding hints that should be used to influence decoding - /// - /// text and bytes encoded within the QR Code - /// - public DecoderResult decode(BitMatrix bits, IDictionary hints) - { - // Construct a parser and read version, error-correction level - var parser = BitMatrixParser.createBitMatrixParser(bits); - if (parser == null) - return null; - - var result = decode(parser, hints); - if (result == null) - { - // Revert the bit matrix - parser.remask(); - - // Will be attempting a mirrored reading of the version and format info. - parser.setMirror(true); - - // Preemptively read the version. - var version = parser.readVersion(); - if (version == null) - return null; - - // Preemptively read the format information. - var formatinfo = parser.readFormatInformation(); - if (formatinfo == null) - return null; - - /* - * Since we're here, this means we have successfully detected some kind - * of version and format information when mirrored. This is a good sign, - * that the QR code may be mirrored, and we should try once more with a - * mirrored content. - */ - // Prepare for a mirrored reading. - parser.mirror(); - - result = decode(parser, hints); - - if (result != null) - { - // Success! Notify the caller that the code was mirrored. - result.Other = new QRCodeDecoderMetaData(true); - } - } - - return result; - } - - private DecoderResult decode(BitMatrixParser parser, IDictionary hints) - { - Version version = parser.readVersion(); - if (version == null) - return null; - var formatinfo = parser.readFormatInformation(); - if (formatinfo == null) - return null; - ErrorCorrectionLevel ecLevel = formatinfo.ErrorCorrectionLevel; - - // Read codewords - byte[] codewords = parser.readCodewords(); - if (codewords == null) - return null; - // Separate into data blocks - DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); - - // Count total number of data bytes - int totalBytes = 0; - foreach (var dataBlock in dataBlocks) - { - totalBytes += dataBlock.NumDataCodewords; - } - byte[] resultBytes = new byte[totalBytes]; - int resultOffset = 0; - - // Error-correct and copy data blocks together into a stream of bytes - foreach (var dataBlock in dataBlocks) - { - byte[] codewordBytes = dataBlock.Codewords; - int numDataCodewords = dataBlock.NumDataCodewords; - if (!correctErrors(codewordBytes, numDataCodewords)) - return null; - 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, 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 - /// - private bool correctErrors(byte[] 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++) - { - codewordsInts[i] = codewordBytes[i] & 0xFF; - } - int numECCodewords = codewordBytes.Length - numDataCodewords; - - if (!rsDecoder.decode(codewordsInts, numECCodewords)) - return false; - - // 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] = (byte)codewordsInts[i]; - } - - return true; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs b/zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs deleted file mode 100644 index c87112f..0000000 --- a/zxing.core/xx/qrcode/decoder/ErrorCorrectionLevel.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - /// - ///

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

- ///
- /// Sean Owen - public sealed class ErrorCorrectionLevel - { - /// 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 = new [] { M, L, H, Q }; - - private readonly int bits; - - private ErrorCorrectionLevel(int ordinal, int bits, String name) - { - this.ordinal_Renamed_Field = ordinal; - this.bits = bits; - this.name = name; - } - - /// - /// Gets the bits. - /// - public int Bits - { - get - { - return bits; - } - } - - /// - /// Gets the name. - /// - public String Name - { - get - { - return name; - } - } - - private readonly int ordinal_Renamed_Field; - private readonly String name; - - /// - /// Ordinals this instance. - /// - /// - public int ordinal() - { - return ordinal_Renamed_Field; - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override String ToString() - { - return name; - } - - /// - /// Fors the bits. - /// - /// int containing the two bits encoding a QR Code's error correction level - /// - /// representing the encoded error correction level - /// - public static ErrorCorrectionLevel forBits(int bits) - { - if (bits < 0 || bits >= FOR_BITS.Length) - { - throw new ArgumentException(); - } - return FOR_BITS[bits]; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/FormatInformation.cs b/zxing.core/xx/qrcode/decoder/FormatInformation.cs deleted file mode 100644 index 77691f0..0000000 --- a/zxing.core/xx/qrcode/decoder/FormatInformation.cs +++ /dev/null @@ -1,197 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - - ///

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 - { - 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[][] - { - new [] { 0x5412, 0x00 }, - new [] { 0x5125, 0x01 }, - new [] { 0x5E7C, 0x02 }, - new [] { 0x5B4B, 0x03 }, - new [] { 0x45F9, 0x04 }, - new [] { 0x40CE, 0x05 }, - new [] { 0x4F97, 0x06 }, - new [] { 0x4AA0, 0x07 }, - new [] { 0x77C4, 0x08 }, - new [] { 0x72F3, 0x09 }, - new [] { 0x7DAA, 0x0A }, - new [] { 0x789D, 0x0B }, - new [] { 0x662F, 0x0C }, - new [] { 0x6318, 0x0D }, - new [] { 0x6C41, 0x0E }, - new [] { 0x6976, 0x0F }, - new [] { 0x1689, 0x10 }, - new [] { 0x13BE, 0x11 }, - new [] { 0x1CE7, 0x12 }, - new [] { 0x19D0, 0x13 }, - new [] { 0x0762, 0x14 }, - new [] { 0x0255, 0x15 }, - new [] { 0x0D0C, 0x16 }, - new [] { 0x083B, 0x17 }, - new [] { 0x355F, 0x18 }, - new [] { 0x3068, 0x19 }, - new [] { 0x3F31, 0x1A }, - new [] { 0x3A06, 0x1B }, - new [] { 0x24B4, 0x1C }, - new [] { 0x2183, 0x1D }, - new [] { 0x2EDA, 0x1E }, - new [] { 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 = new [] - { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; - - private readonly ErrorCorrectionLevel errorCorrectionLevel; - private readonly byte dataMask; - - private FormatInformation(int formatInfo) - { - // Bits 3,4 - errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); - // Bottom 3 bits - dataMask = (byte)(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)]; - } - - /// - /// Decodes the format information. - /// - /// format info indicator, with mask still applied - /// The masked format info2. - /// - /// information about the format it specifies, or 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) - { - 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 = Int32.MaxValue; - int bestFormatInfo = 0; - foreach (var 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) - { - 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; - } - - internal ErrorCorrectionLevel ErrorCorrectionLevel - { - get - { - return errorCorrectionLevel; - } - } - - internal byte DataMask - { - get - { - return dataMask; - } - } - - public override int GetHashCode() - { - return (errorCorrectionLevel.ordinal() << 3) | dataMask; - } - - public override bool Equals(Object o) - { - if (!(o is FormatInformation)) - { - return false; - } - var other = (FormatInformation)o; - return errorCorrectionLevel == other.errorCorrectionLevel && dataMask == other.dataMask; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/Mode.cs b/zxing.core/xx/qrcode/decoder/Mode.cs deleted file mode 100644 index 5beff18..0000000 --- a/zxing.core/xx/qrcode/decoder/Mode.cs +++ /dev/null @@ -1,179 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - /// - ///

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 - public sealed class Mode - { - /// - /// Gets the name. - /// - public String Name - { - get - { - return name; - } - } - - // No, we can't use an enum here. J2ME doesn't support it. - - /// - /// - /// - public static readonly Mode TERMINATOR = new Mode(new int[] { 0, 0, 0 }, 0x00, "TERMINATOR"); // Not really a mode... - /// - /// - /// - public static readonly Mode NUMERIC = new Mode(new int[] { 10, 12, 14 }, 0x01, "NUMERIC"); - /// - /// - /// - public static readonly Mode ALPHANUMERIC = new Mode(new int[] { 9, 11, 13 }, 0x02, "ALPHANUMERIC"); - /// - /// - /// - public static readonly Mode STRUCTURED_APPEND = new Mode(new int[] { 0, 0, 0 }, 0x03, "STRUCTURED_APPEND"); // Not supported - /// - /// - /// - public static readonly Mode BYTE = new Mode(new int[] { 8, 16, 16 }, 0x04, "BYTE"); - /// - /// - /// - public static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply - /// - /// - /// - public static readonly Mode KANJI = new Mode(new int[] { 8, 10, 12 }, 0x08, "KANJI"); - /// - /// - /// - public static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION"); - /// - /// - /// - public static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION"); - /// See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. - public static readonly Mode HANZI = new Mode(new int[] { 8, 10, 12 }, 0x0D, "HANZI"); - - private readonly int[] characterCountBitsForVersions; - private readonly int bits; - private readonly String name; - - private Mode(int[] characterCountBitsForVersions, int bits, System.String name) - { - this.characterCountBitsForVersions = characterCountBitsForVersions; - this.bits = bits; - this.name = name; - } - - /// - /// Fors the bits. - /// - /// four bits encoding a QR Code data 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 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 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]; - } - - /// - /// Gets the bits. - /// - public int Bits - { - get - { - return bits; - } - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override String ToString() - { - return name; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs b/zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs deleted file mode 100644 index db12696..0000000 --- a/zxing.core/xx/qrcode/decoder/QRCodeDecoderMetaData.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.QrCode.Internal -{ - /// - /// Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the - /// decoding caller. Callers are expected to process this. - /// - public sealed class QRCodeDecoderMetaData - { - private readonly bool mirrored; - - /// - /// Initializes a new instance of the class. - /// - /// if set to true [mirrored]. - public QRCodeDecoderMetaData(bool mirrored) - { - this.mirrored = mirrored; - } - - /// - /// true if the QR Code was mirrored. - /// - public bool IsMirrored - { - get { return mirrored; } - } - - /// - /// Apply the result points' order correction due to mirroring. - /// - /// Array of points to apply mirror correction to. - public void applyMirroredCorrection(ResultPoint[] points) - { - if (!mirrored || points == null || points.Length < 3) - { - return; - } - ResultPoint bottomLeft = points[0]; - points[0] = points[2]; - points[2] = bottomLeft; - // No need to 'fix' top-left and alignment pattern. - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/decoder/Version.cs b/zxing.core/xx/qrcode/decoder/Version.cs deleted file mode 100644 index e39ab71..0000000 --- a/zxing.core/xx/qrcode/decoder/Version.cs +++ /dev/null @@ -1,685 +0,0 @@ -/* -* 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 ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - /// - /// See ISO 18004:2006 Annex D - /// - /// Sean Owen - public sealed class Version - { - /// 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 = new[] - { - 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].getECBlocks(); - foreach (var ecBlock in ecbArray) - { - total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); - } - this.totalCodewords = total; - } - - /// - /// Gets the version number. - /// - public int VersionNumber - { - get - { - return versionNumber; - } - - } - - /// - /// Gets the alignment pattern centers. - /// - public int[] AlignmentPatternCenters - { - get - { - return alignmentPatternCenters; - } - - } - - /// - /// Gets the total codewords. - /// - public int TotalCodewords - { - get - { - return totalCodewords; - } - - } - - /// - /// Gets the dimension for version. - /// - public int DimensionForVersion - { - get - { - return 17 + 4 * versionNumber; - } - - } - - /// - /// Gets the EC blocks for level. - /// - /// The ec level. - /// - public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) - { - return ecBlocks[ecLevel.ordinal()]; - } - - ///

Deduces version information purely from QR Code dimensions.

- /// - ///
- /// dimension in modules - /// - /// for a QR Code of that dimension or null - public static Version getProvisionalVersionForDimension(int dimension) - { - if (dimension % 4 != 1) - { - return null; - } - try - { - return getVersionForNumber((dimension - 17) >> 2); - } - catch (ArgumentException) - { - return null; - } - } - - /// - /// Gets the version for number. - /// - /// The version number. - /// - public static Version getVersionForNumber(int versionNumber) - { - if (versionNumber < 1 || versionNumber > 40) - { - throw new ArgumentException(); - } - return VERSIONS[versionNumber - 1]; - } - - internal static Version decodeVersionInformation(int versionBits) - { - int bestDifference = 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 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; - } - - /// - /// Gets the EC codewords per block. - /// - public int ECCodewordsPerBlock - { - get - { - return ecCodewordsPerBlock; - } - } - - /// - /// Gets the num blocks. - /// - public int NumBlocks - { - get - { - int total = 0; - foreach (var ecBlock in ecBlocks) - { - total += ecBlock.Count; - } - return total; - } - } - - /// - /// Gets the total EC codewords. - /// - public int TotalECCodewords - { - get - { - return ecCodewordsPerBlock * NumBlocks; - } - } - - /// - /// Gets the EC blocks. - /// - /// - 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 - { - private readonly int count; - private readonly int dataCodewords; - - internal ECB(int count, int dataCodewords) - { - this.count = count; - this.dataCodewords = dataCodewords; - } - - /// - /// Gets the count. - /// - public int Count - { - get - { - return count; - } - - } - /// - /// Gets the data codewords. - /// - public int DataCodewords - { - get - { - return dataCodewords; - } - - } - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - 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/zxing.core/xx/qrcode/detector/AlignmentPattern.cs b/zxing.core/xx/qrcode/detector/AlignmentPattern.cs deleted file mode 100644 index 7439897..0000000 --- a/zxing.core/xx/qrcode/detector/AlignmentPattern.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - ///

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

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - public sealed class AlignmentPattern : ResultPoint - { - private 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) - { - 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. - /// - /// The i. - /// The j. - /// New size of the module. - /// - 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/zxing.core/xx/qrcode/detector/AlignmentPatternFinder.cs b/zxing.core/xx/qrcode/detector/AlignmentPatternFinder.cs deleted file mode 100644 index 362750d..0000000 --- a/zxing.core/xx/qrcode/detector/AlignmentPatternFinder.cs +++ /dev/null @@ -1,324 +0,0 @@ -/* -* 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; - -using ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - ///

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, - /// 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.

- /// - ///
- /// Sean Owen - /// - /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source - /// - sealed class AlignmentPatternFinder - { - 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.

- /// - ///
- /// {@link AlignmentPattern} if 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[j, i]) - { - j++; - } - int currentState = 0; - while (j < maxJ) - { - if (image[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 (confirmed != null) - { - return confirmed; - } - } - } - - // Hmm, nothing we saw was observed and confirmed twice. If we had - // any guess at all, return it. - if (possibleCenters.Count != 0) - { - return possibleCenters[0]; - } - - return null; - } - - /// 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) - { - var result = (end - stateCount[2]) - stateCount[1] / 2.0f; - if (Single.IsNaN(result)) - return null; - return result; - } - - /// 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 maxVariance = moduleSize / 2.0f; - for (int i = 0; i < 3; i++) - { - 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 - /// The original state count total. - /// - /// vertical center of alignment pattern, or null if not found - /// - private float? crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) - { - 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[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 null; - } - while (i >= 0 && !image[centerJ, i] && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return null; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image[centerJ, i] && stateCount[1] <= maxCount) - { - stateCount[1]++; - i++; - } - if (i == maxI || stateCount[1] > maxCount) - { - return null; - } - while (i < maxI && !image[centerJ, i] && stateCount[2] <= maxCount) - { - stateCount[2]++; - i++; - } - if (stateCount[2] > maxCount) - { - return null; - } - - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) - { - return null; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : null; - } - - ///

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) - { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - float? centerJ = centerFromEnd(stateCount, j); - if (centerJ == null) - return null; - float? centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal); - if (centerI != null) - { - float estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; - foreach (var center in possibleCenters) - { - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI.Value, centerJ.Value)) - { - return center.combineEstimate(centerI.Value, centerJ.Value, estimatedModuleSize); - } - } - // Hadn't found this before; save it - var point = new AlignmentPattern(centerJ.Value, centerI.Value, estimatedModuleSize); - possibleCenters.Add(point); - if (resultPointCallback != null) - { - resultPointCallback(point); - } - } - return null; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/detector/Detector.cs b/zxing.core/xx/qrcode/detector/Detector.cs deleted file mode 100644 index 7105f8e..0000000 --- a/zxing.core/xx/qrcode/detector/Detector.cs +++ /dev/null @@ -1,434 +0,0 @@ -/* -* 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; - -using ZXing.Common; -using ZXing.Common.Detector; - -namespace ZXing.QrCode.Internal -{ - /// - ///

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

- ///
- /// Sean Owen - public class Detector - { - private readonly BitMatrix image; - private ResultPointCallback resultPointCallback; - - /// - /// Initializes a new instance of the class. - /// - /// The image. - public Detector(BitMatrix image) - { - this.image = image; - } - - /// - /// Gets the image. - /// - virtual protected internal BitMatrix Image - { - get - { - return image; - } - } - - /// - /// Gets the result point callback. - /// - virtual protected internal ResultPointCallback ResultPointCallback - { - get - { - return resultPointCallback; - } - } - - /// - ///

Detects a QR Code in an image.

- ///
- /// - /// encapsulating results of detecting a QR Code - /// - public virtual DetectorResult detect() - { - return detect(null); - } - - /// - ///

Detects a QR Code in an image.

- ///
- /// optional hints to detector - /// - /// encapsulating results of detecting a QR Code - /// - public virtual DetectorResult detect(IDictionary hints) - { - resultPointCallback = hints == null || !hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK) ? null : (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]; - - FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback); - FinderPatternInfo info = finder.find(hints); - if (info == null) - return null; - - return processFinderPatternInfo(info); - } - - /// - /// Processes the finder pattern info. - /// - /// The info. - /// - protected internal virtual 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) - { - return null; - } - int dimension; - if (!computeDimension(topLeft, topRight, bottomLeft, moduleSize, out dimension)) - return null; - Internal.Version provisionalVersion = Internal.Version.getProvisionalVersionForDimension(dimension); - if (provisionalVersion == null) - return null; - 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) - { - alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); - if (alignmentPattern == null) - continue; - break; - } - // 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); - if (bits == null) - return null; - - ResultPoint[] points; - if (alignmentPattern == null) - { - points = new ResultPoint[] { bottomLeft, topLeft, topRight }; - } - else - { - points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; - } - return new DetectorResult(bits, points); - } - - private static PerspectiveTransform createTransform(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) - { - //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; - } - - 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); - } - - 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.

- ///
- private static bool computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize, out int dimension) - { - int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); - dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; - switch (dimension & 0x03) - { - // mod 4 - case 0: - dimension++; - break; - // 1? do nothing - case 2: - dimension--; - break; - case 3: - return true; - } - return true; - } - - /// - ///

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

- ///
- /// detected top-left finder pattern center - /// detected top-right finder pattern center - /// detected bottom-left finder pattern center - /// estimated module size - protected internal virtual 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 - /// {@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) - { - //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 (Single.IsNaN(moduleSizeEst1)) - { - return moduleSizeEst2 / 7.0f; - } - if (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; - } - - /// 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) - { - - 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 - } - - ///

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) - { - 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 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) - { - 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[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 Single.NaN; - - } - - /// - ///

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 - /// - /// if found, or null otherwise - /// - protected AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, float allowanceFactor) - { - // 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 = Math.Max(0, estAlignmentX - allowance); - int alignmentAreaRightX = Math.Min(image.Width - 1, estAlignmentX + allowance); - if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) - { - return null; - } - - int alignmentAreaTopY = Math.Max(0, estAlignmentY - allowance); - int alignmentAreaBottomY = Math.Min(image.Height - 1, estAlignmentY + allowance); - - var alignmentFinder = new AlignmentPatternFinder( - image, - alignmentAreaLeftX, - alignmentAreaTopY, - alignmentAreaRightX - alignmentAreaLeftX, - alignmentAreaBottomY - alignmentAreaTopY, - overallEstModuleSize, - resultPointCallback); - - return alignmentFinder.find(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/detector/FinderPattern.cs b/zxing.core/xx/qrcode/detector/FinderPattern.cs deleted file mode 100644 index 27c5f0f..0000000 --- a/zxing.core/xx/qrcode/detector/FinderPattern.cs +++ /dev/null @@ -1,107 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - /// - ///

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.

- ///
- /// Sean Owen - public sealed class FinderPattern : ResultPoint - { - private readonly float estimatedModuleSize; - private int count; - - internal FinderPattern(float posX, float posY, float estimatedModuleSize) - : this(posX, posY, estimatedModuleSize, 1) - { - this.estimatedModuleSize = estimatedModuleSize; - this.count = 1; - } - - internal FinderPattern(float posX, float posY, float estimatedModuleSize, int count) - : base(posX, posY) - { - this.estimatedModuleSize = estimatedModuleSize; - this.count = count; - } - - /// - /// Gets the size of the estimated module. - /// - /// - /// The size of the estimated module. - /// - 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) - { - 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. - /// - /// The i. - /// The j. - /// New size of the module. - /// - 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/zxing.core/xx/qrcode/detector/FinderPatternFinder.cs b/zxing.core/xx/qrcode/detector/FinderPatternFinder.cs deleted file mode 100644 index 37462cd..0000000 --- a/zxing.core/xx/qrcode/detector/FinderPatternFinder.cs +++ /dev/null @@ -1,813 +0,0 @@ -/* -* 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; - -using ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - /// - ///

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. - ///

- /// Sean Owen - public class FinderPatternFinder - { - private const int CENTER_QUORUM = 2; - /// - /// 1 pixel/module times 3 modules/center - /// - protected internal const int MIN_SKIP = 3; - /// - /// support up to version 10 for mobile clients - /// - protected internal const int MAX_MODULES = 57; - private const int INTEGER_MATH_SHIFT = 8; - - private readonly BitMatrix image; - private 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) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image. - /// The result point callback. - public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback) - { - this.image = image; - this.possibleCenters = new List(); - this.crossCheckStateCount = new int[5]; - this.resultPointCallback = resultPointCallback; - } - - /// - /// Gets the image. - /// - virtual protected internal BitMatrix Image - { - get - { - return image; - } - } - - /// - /// Gets the possible centers. - /// - virtual protected internal List PossibleCenters - { - get - { - return possibleCenters; - } - } - - internal virtual FinderPatternInfo find(IDictionary hints) - { - bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); - bool pureBarcode = hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE); - 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 (image[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, pureBarcode); - 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 - { - 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; - } - 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, pureBarcode); - if (confirmed) - { - iSkip = stateCount[0]; - if (hasSkipped) - { - // Found a third one - done = haveMultiplyConfirmedCenters(); - } - } - } - } - - FinderPattern[] patternInfo = selectBestPatterns(); - if (patternInfo == null) - return null; - - 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) - { - var result = (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; - if (Single.IsNaN(result)) - return null; - return result; - } - - /// 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 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 vertical and horizontal scan finds a potential finder pattern, this method - /// "cross-cross-cross-checks" by scanning down diagonally 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 - /// The original state count total. - /// true if proportions are withing expected limits - private bool crossCheckDiagonal(int startI, int centerJ, int maxCount, int originalStateCountTotal) - { - int[] stateCount = CrossCheckStateCount; - - // Start counting up, left from center finding black center mass - int i = 0; - while (startI >= i && centerJ >= i && image[centerJ - i, startI - i]) - { - stateCount[2]++; - i++; - } - - if (startI < i || centerJ < i) - { - return false; - } - - // Continue up, left finding white space - while (startI >= i && centerJ >= i && !image[centerJ - i, startI - i] && - stateCount[1] <= maxCount) - { - stateCount[1]++; - i++; - } - - // If already too many modules in this state or ran off the edge: - if (startI < i || centerJ < i || stateCount[1] > maxCount) - { - return false; - } - - // Continue up, left finding black border - while (startI >= i && centerJ >= i && image[centerJ - i, startI - i] && - stateCount[0] <= maxCount) - { - stateCount[0]++; - i++; - } - if (stateCount[0] > maxCount) - { - return false; - } - - int maxI = image.Height; - int maxJ = image.Width; - - // Now also count down, right from center - i = 1; - while (startI + i < maxI && centerJ + i < maxJ && image[centerJ + i, startI + i]) - { - stateCount[2]++; - i++; - } - - // Ran off the edge? - if (startI + i >= maxI || centerJ + i >= maxJ) - { - return false; - } - - while (startI + i < maxI && centerJ + i < maxJ && !image[centerJ + i, startI + i] && - stateCount[3] < maxCount) - { - stateCount[3]++; - i++; - } - - if (startI + i >= maxI || centerJ + i >= maxJ || stateCount[3] >= maxCount) - { - return false; - } - - while (startI + i < maxI && centerJ + i < maxJ && image[centerJ + i, startI + i] && - stateCount[4] < maxCount) - { - stateCount[4]++; - i++; - } - - if (stateCount[4] >= maxCount) - { - return false; - } - - // If we found a finder-pattern-like section, but its size is more than 100% different than - // the original, assume it's a false positive - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - return Math.Abs(stateCountTotal - originalStateCountTotal) < 2*originalStateCountTotal && - foundPatternCross(stateCount); - } - - /// - ///

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 - /// The original state count total. - /// - /// vertical center of finder pattern, or null if not found - /// - private float? crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) - { - int maxI = image.Height; - int[] stateCount = CrossCheckStateCount; - - // Start counting up from center - int i = startI; - while (i >= 0 && image[centerJ, i]) - { - stateCount[2]++; - i--; - } - if (i < 0) - { - return null; - } - while (i >= 0 && !image[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 null; - } - while (i >= 0 && image[centerJ, i] && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return null; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image[centerJ, i]) - { - stateCount[2]++; - i++; - } - if (i == maxI) - { - return null; - } - while (i < maxI && !image[centerJ, i] && stateCount[3] < maxCount) - { - stateCount[3]++; - i++; - } - if (i == maxI || stateCount[3] >= maxCount) - { - return null; - } - while (i < maxI && image[centerJ, i] && stateCount[4] < maxCount) - { - stateCount[4]++; - i++; - } - if (stateCount[4] >= maxCount) - { - return null; - } - - // 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 null; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : null; - } - - ///

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) - { - int maxJ = image.Width; - int[] stateCount = CrossCheckStateCount; - - int j = startJ; - while (j >= 0 && image[j, centerI]) - { - stateCount[2]++; - j--; - } - if (j < 0) - { - return null; - } - while (j >= 0 && !image[j, centerI] && stateCount[1] <= maxCount) - { - stateCount[1]++; - j--; - } - if (j < 0 || stateCount[1] > maxCount) - { - return null; - } - while (j >= 0 && image[j, centerI] && stateCount[0] <= maxCount) - { - stateCount[0]++; - j--; - } - if (stateCount[0] > maxCount) - { - return null; - } - - j = startJ + 1; - while (j < maxJ && image[j, centerI]) - { - stateCount[2]++; - j++; - } - if (j == maxJ) - { - return null; - } - while (j < maxJ && !image[j, centerI] && stateCount[3] < maxCount) - { - stateCount[3]++; - j++; - } - if (j == maxJ || stateCount[3] >= maxCount) - { - return null; - } - while (j < maxJ && image[j, centerI] && stateCount[4] < maxCount) - { - stateCount[4]++; - j++; - } - if (stateCount[4] >= maxCount) - { - return null; - } - - // 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 null; - } - - return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : null; - } - - /// - ///

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. - /// And then we cross-cross-cross check with another diagonal scan.

- /// 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 in "pure barcode" mode - /// - /// true if a finder pattern candidate was found this time - /// - protected bool handlePossibleCenter(int[] stateCount, int i, int j, bool pureBarcode) - { - int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + - stateCount[4]; - float? centerJ = centerFromEnd(stateCount, j); - if (centerJ == null) - return false; - float? centerI = crossCheckVertical(i, (int)centerJ.Value, stateCount[2], stateCountTotal); - if (centerI != null) - { - // Re-cross check - centerJ = crossCheckHorizontal((int)centerJ.Value, (int)centerI.Value, stateCount[2], stateCountTotal); - if (centerJ != null && - (!pureBarcode || crossCheckDiagonal((int) centerI, (int) centerJ, stateCount[2], stateCountTotal))) - { - float estimatedModuleSize = stateCountTotal / 7.0f; - bool found = false; - for (int index = 0; index < possibleCenters.Count; index++) - { - var center = possibleCenters[index]; - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI.Value, centerJ.Value)) - { - possibleCenters.RemoveAt(index); - possibleCenters.Insert(index, center.combineEstimate(centerI.Value, centerJ.Value, estimatedModuleSize)); - - found = true; - break; - } - } - if (!found) - { - var point = new FinderPattern(centerJ.Value, centerI.Value, estimatedModuleSize); - - possibleCenters.Add(point); - if (resultPointCallback != null) - { - - resultPointCallback(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; - } - ResultPoint firstConfirmedCenter = null; - foreach (var 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; - //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)(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 {@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; - foreach (var 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 / max; - float totalDeviation = 0.0f; - for (int i = 0; i < max; i++) - { - var pattern = possibleCenters[i]; - totalDeviation += 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 - /// - private FinderPattern[] selectBestPatterns() - { - int startSize = possibleCenters.Count; - if (startSize < 3) - { - // Couldn't find enough finder patterns - return null; - } - - // 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 (var center in possibleCenters) - { - float size = center.EstimatedModuleSize; - totalModuleSize += size; - square += size * size; - } - float average = totalModuleSize / 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 (var possibleCenter in possibleCenters) - { - totalModuleSize += possibleCenter.EstimatedModuleSize; - } - - float average = totalModuleSize / possibleCenters.Count; - - possibleCenters.Sort(new CenterComparator(average)); - - //possibleCenters.subList(3, possibleCenters.Count).clear(); - possibleCenters = possibleCenters.GetRange(0, 3); - } - - return new[] - { - possibleCenters[0], - possibleCenters[1], - possibleCenters[2] - }; - } - - /// - /// Orders by furthest from average - /// - private sealed class FurthestFromAverageComparator : IComparer - { - private readonly float average; - - public FurthestFromAverageComparator(float f) - { - average = f; - } - - public int Compare(FinderPattern x, FinderPattern y) - { - float dA = Math.Abs(y.EstimatedModuleSize - average); - float dB = Math.Abs(x.EstimatedModuleSize - average); - return dA < dB ? -1 : dA == dB ? 0 : 1; - } - } - - ///

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

- private sealed class CenterComparator : IComparer - { - private readonly float average; - - public CenterComparator(float f) - { - average = f; - } - - public int Compare(FinderPattern x, FinderPattern y) - { - if (y.Count == x.Count) - { - float dA = Math.Abs(y.EstimatedModuleSize - average); - float dB = Math.Abs(x.EstimatedModuleSize - average); - return dA < dB ? 1 : dA == dB ? 0 : -1; - } - return y.Count - x.Count; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/detector/FinderPatternInfo.cs b/zxing.core/xx/qrcode/detector/FinderPatternInfo.cs deleted file mode 100644 index 4654d92..0000000 --- a/zxing.core/xx/qrcode/detector/FinderPatternInfo.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* -* 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 ZXing.QrCode.Internal -{ - /// - ///

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

- ///
- /// Sean Owen - public sealed class FinderPatternInfo - { - private readonly FinderPattern bottomLeft; - private readonly FinderPattern topLeft; - private readonly FinderPattern topRight; - - /// - /// Initializes a new instance of the class. - /// - /// The pattern centers. - public FinderPatternInfo(FinderPattern[] patternCenters) - { - this.bottomLeft = patternCenters[0]; - this.topLeft = patternCenters[1]; - this.topRight = patternCenters[2]; - } - - /// - /// Gets the bottom left. - /// - public FinderPattern BottomLeft - { - get - { - return bottomLeft; - } - } - - /// - /// Gets the top left. - /// - public FinderPattern TopLeft - { - get - { - return topLeft; - } - } - - /// - /// Gets the top right. - /// - public FinderPattern TopRight - { - get - { - return topRight; - } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/encoder/BlockPair.cs b/zxing.core/xx/qrcode/encoder/BlockPair.cs deleted file mode 100644 index c4c1691..0000000 --- a/zxing.core/xx/qrcode/encoder/BlockPair.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -namespace ZXing.QrCode.Internal -{ - internal sealed class BlockPair - { - private readonly byte[] dataBytes; - private readonly byte[] errorCorrectionBytes; - - public BlockPair(byte[] data, byte[] errorCorrection) - { - dataBytes = data; - errorCorrectionBytes = errorCorrection; - } - - public byte[] DataBytes - { - get { return dataBytes; } - } - - public byte[] ErrorCorrectionBytes - { - get { return errorCorrectionBytes; } - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/encoder/ByteMatrix.cs b/zxing.core/xx/qrcode/encoder/ByteMatrix.cs deleted file mode 100644 index 1912073..0000000 --- a/zxing.core/xx/qrcode/encoder/ByteMatrix.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Text; - -namespace ZXing.QrCode.Internal -{ - /// - /// JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned - /// 0, 1 and 2 I'm going to use less memory and go with bytes. - /// - /// dswitkin@google.com (Daniel Switkin) - public sealed class ByteMatrix - { - private readonly byte[][] bytes; - private readonly int width; - private readonly int height; - - /// - /// Initializes a new instance of the class. - /// - /// The width. - /// The height. - public ByteMatrix(int width, int height) - { - bytes = new byte[height][]; - for (var i = 0; i < height; i++) - bytes[i] = new byte[width]; - this.width = width; - this.height = height; - } - - /// - /// Gets the height. - /// - public int Height - { - get { return height; } - } - - /// - /// Gets the width. - /// - public int Width - { - get { return width; } - } - - /// - /// Gets or sets the with the specified x. - /// - public int this[int x, int y] - { - get { return bytes[y][x]; } - set { bytes[y][x] = (byte)value; } - } - - /// - /// an internal representation as bytes, in row-major order. array[y][x] represents point (x,y) - /// - public byte[][] Array - { - get { return bytes; } - } - - /// - /// Sets the specified x. - /// - /// The x. - /// The y. - /// The value. - public void set(int x, int y, byte value) - { - bytes[y][x] = value; - } - - /// - /// Sets the specified x. - /// - /// The x. - /// The y. - /// if set to true [value]. - public void set(int x, int y, bool value) - { - bytes[y][x] = (byte)(value ? 1 : 0); - } - - /// - /// Clears the specified value. - /// - /// The value. - public void clear(byte value) - { - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - bytes[y][x] = value; - } - } - } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - override public String ToString() - { - var result = new StringBuilder(2 * width * height + 2); - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - { - switch (bytes[y][x]) - { - case 0: - result.Append(" 0"); - break; - case 1: - result.Append(" 1"); - break; - default: - result.Append(" "); - break; - } - } - result.Append('\n'); - } - return result.ToString(); - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/encoder/Encoder.cs b/zxing.core/xx/qrcode/encoder/Encoder.cs deleted file mode 100644 index 2831a50..0000000 --- a/zxing.core/xx/qrcode/encoder/Encoder.cs +++ /dev/null @@ -1,758 +0,0 @@ -/* -* Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -using ZXing.Common; -using ZXing.Common.ReedSolomon; - -namespace ZXing.QrCode.Internal -{ - /// - /// - /// satorux@google.com (Satoru Takabayashi) - creator - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - public static class 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, // 0x00-0x0f - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f - 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f - }; - - internal static String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; - - // 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. - /// - /// text to encode - /// error correction level to use - /// representing the encoded QR code - public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) - { - return encode(content, ecLevel, null); - } - - /// - /// Encodes the specified content. - /// - /// The content. - /// The ec level. - /// The hints. - /// - public static QRCode encode(String content, - ErrorCorrectionLevel ecLevel, - IDictionary hints) - { - // Determine what character encoding has been specified by the caller, if any -#if !SILVERLIGHT || WINDOWS_PHONE - String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; - if (encoding == null) - { - encoding = DEFAULT_BYTE_MODE_ENCODING; - } - bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); -#else - // Silverlight supports only UTF-8 and UTF-16 out-of-the-box - const string encoding = "UTF-8"; - // caller of the method can only control if the ECI segment should be written - // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment - bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)); -#endif - - // 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 && generateECI) - { - CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); - if (eci != null) - { - var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) ? (bool)hints[EncodeHintType.DISABLE_ECI] : false); - if (!eciIsExplicitDisabled) - { - appendECI(eci, headerBits); - } - } - } - - // (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 - { - ECLevel = ecLevel, - Mode = mode, - 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; - } - - /// - /// Gets the alphanumeric code. - /// - /// The code. - /// 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) - { - return ALPHANUMERIC_TABLE[code]; - } - return -1; - } - - /// - /// Chooses the mode. - /// - /// The content. - /// - 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 {@link Mode#KANJI}. - /// - /// The content. - /// The encoding. - /// - private static Mode chooseMode(String content, 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; - } - if (hasNumeric) - { - - return Mode.NUMERIC; - } - return Mode.BYTE; - } - - private static bool isOnlyDoubleByteKanji(String content) - { - byte[] bytes; - try - { - bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content); - } - catch (Exception ) - { - 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; - } - - private static int chooseMaskPattern(BitArray bits, - ErrorCorrectionLevel ecLevel, - Version version, - ByteMatrix matrix) - { - int minPenalty = 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; - } - - 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++) - { - 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; - } - } - throw new WriterException("Data too big"); - } - - /// - /// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). - /// - /// The num data bytes. - /// The bits. - internal static void terminateBits(int numDataBytes, BitArray bits) - { - int capacity = numDataBytes << 3; - if (bits.Size > capacity) - { - throw new WriterException("data bits cannot fit in the QR Code" + bits.Size + " > " + - capacity); - } - for (int i = 0; i < 4 && bits.Size < capacity; ++i) - { - bits.appendBit(false); - } - // 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) - { - for (int i = numBitsInLastByte; i < 8; i++) - { - bits.appendBit(false); - } - } - // 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) - { - bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); - } - if (bits.Size != capacity) - { - throw new WriterException("Bits size does not equal capacity"); - } - } - - /// - /// 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) - /// - /// The num total bytes. - /// The num data bytes. - /// The num RS blocks. - /// The block ID. - /// The num data bytes in block. - /// The num EC bytes in block. - internal static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, - int numDataBytes, - int numRSBlocks, - int blockID, - int[] numDataBytesInBlock, - int[] numECBytesInBlock) - { - 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; - } - } - - /// - /// 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. - /// - /// The bits. - /// The num total bytes. - /// The num data bytes. - /// The num RS blocks. - /// - 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. - var 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]; - byte[] dataBytes = new byte[size]; - bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size); - byte[] 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) - { - byte[] 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) - { - byte[] 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 byte[] generateECBytes(byte[] 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); - - byte[] ecBytes = new byte[numEcBytesInBlock]; - for (int i = 0; i < numEcBytesInBlock; i++) - { - ecBytes[i] = (byte)toEncode[numDataBytes + i]; - - } - return ecBytes; - } - - /// - /// Append mode info. On success, store the result in "bits". - /// - /// The mode. - /// The bits. - internal static void appendModeInfo(Mode mode, BitArray bits) - { - bits.appendBits(mode.Bits, 4); - } - - - /// - /// Append length info. On success, store the result in "bits". - /// - /// The num letters. - /// The version. - /// The mode. - /// The bits. - 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". - /// - /// The content. - /// The mode. - /// The bits. - /// The encoding. - internal static void appendBytes(String content, - Mode mode, - BitArray bits, - String encoding) - { - 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); - } - - 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++; - } - } - } - - 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++; - } - } - } - - internal static void append8BitBytes(String content, BitArray bits, String encoding) - { - byte[] bytes; - try - { - bytes = Encoding.GetEncoding(encoding).GetBytes(content); - } -#if WindowsCE - catch (PlatformNotSupportedException) - { - try - { - // WindowsCE doesn't support all encodings. But it is device depended. - // So we try here the some different ones - if (encoding == "ISO-8859-1") - { - bytes = Encoding.GetEncoding(1252).GetBytes(content); - } - else - { - bytes = Encoding.GetEncoding("UTF-8").GetBytes(content); - } - } - catch (Exception uee) - { - throw new WriterException(uee.Message, uee); - } - } -#endif - catch (Exception uee) - { - throw new WriterException(uee.Message, uee); - } - foreach (byte b in bytes) - { - bits.appendBits(b, 8); - } - } - - internal static void appendKanjiBytes(String content, BitArray bits) - { - byte[] bytes; - try - { - bytes = Encoding.GetEncoding("Shift_JIS").GetBytes(content); - } - catch (Exception uee) - { - throw new WriterException(uee.Message, 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/zxing.core/xx/qrcode/encoder/MaskUtil.cs b/zxing.core/xx/qrcode/encoder/MaskUtil.cs deleted file mode 100644 index 1321293..0000000 --- a/zxing.core/xx/qrcode/encoder/MaskUtil.cs +++ /dev/null @@ -1,271 +0,0 @@ -/* -* Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System; - -namespace ZXing.QrCode.Internal -{ - /// - /// - /// - /// Satoru Takabayashi - /// Daniel Switkin - /// Sean Owen - public static class 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; - - /// - /// 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. - /// - /// The matrix. - /// - 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. 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. - /// - /// The matrix. - /// - public static int applyMaskPenaltyRule2(ByteMatrix matrix) - { - int penalty = 0; - var 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]) - { - penalty++; - } - } - } - 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). - /// - /// The matrix. - /// - public static int applyMaskPenaltyRule3(ByteMatrix matrix) - { - int numPenalties = 0; - byte[][] 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++) - { - byte[] arrayY = array[y]; // We can at least optimize this access - if (x + 6 < width && - arrayY[x] == 1 && - arrayY[x + 1] == 0 && - arrayY[x + 2] == 1 && - arrayY[x + 3] == 1 && - arrayY[x + 4] == 1 && - arrayY[x + 5] == 0 && - arrayY[x + 6] == 1 && - (isWhiteHorizontal(arrayY, x - 4, x) || isWhiteHorizontal(arrayY, x + 7, x + 11))) - { - numPenalties++; - } - 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 && - (isWhiteVertical(array, x, y - 4, y) || isWhiteVertical(array, x, y + 7, y + 11))) - { - numPenalties++; - } - } - } - return numPenalties * N3; - } - - private static bool isWhiteHorizontal(byte[] rowArray, int from, int to) - { - for (int i = from; i < to; i++) - { - if (i >= 0 && i < rowArray.Length && rowArray[i] == 1) - { - return false; - } - } - return true; - } - - private static bool isWhiteVertical(byte[][] array, int col, int from, int to) - { - for (int i = from; i < to; i++) - { - if (i >= 0 && i < array.Length && array[i][col] == 1) - { - return false; - } - } - return true; - } - - /// - /// 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. - /// - /// The matrix. - /// - public static int applyMaskPenaltyRule4(ByteMatrix matrix) - { - int numDarkCells = 0; - var array = matrix.Array; - int width = matrix.Width; - int height = matrix.Height; - for (int y = 0; y < height; y++) - { - var arrayY = array[y]; - for (int x = 0; x < width; x++) - { - if (arrayY[x] == 1) - { - numDarkCells++; - } - } - } - var numTotalCells = matrix.Height * matrix.Width; - var darkRatio = (double)numDarkCells / numTotalCells; - var 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. - /// - /// The mask pattern. - /// The x. - /// The y. - /// - public static bool getDataMaskBit(int maskPattern, int x, int y) - { - 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 = (((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 ArgumentException("Invalid mask pattern: " + maskPattern); - - } - return intermediate == 0; - } - - /// - /// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both - /// vertical and horizontal orders respectively. - /// - /// The matrix. - /// if set to true [is horizontal]. - /// - 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; - var 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) - { - numSameBitCells++; - } - 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/zxing.core/xx/qrcode/encoder/MatrixUtil.cs b/zxing.core/xx/qrcode/encoder/MatrixUtil.cs deleted file mode 100644 index 90dae10..0000000 --- a/zxing.core/xx/qrcode/encoder/MatrixUtil.cs +++ /dev/null @@ -1,604 +0,0 @@ -/* -* Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System; -using ZXing.Common; - -namespace ZXing.QrCode.Internal -{ - /// - /// - /// - /// - /// satorux@google.com (Satoru Takabayashi) - creator - /// - public static class MatrixUtil - { - 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 } - }; - - 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. - 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. - 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 2. 2 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. - /// - /// The matrix. - public static void clearMatrix(ByteMatrix matrix) - { - matrix.clear(2); - } - - /// - /// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On - /// success, store the result in "matrix" and return true. - /// - /// The data bits. - /// The ec level. - /// The version. - /// The mask pattern. - /// The matrix. - public 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 - /// - /// The version. - /// The matrix. - public 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. - /// - /// The ec level. - /// The mask pattern. - /// The matrix. - public 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) - { - // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in - // "typeInfoBits". - int bit = typeInfoBits[typeInfoBits.Size - 1 - i] ? 1 : 0; - - // 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[x1, y1] = bit; - - if (i < 8) - { - // Right top corner. - int x2 = matrix.Width - i - 1; - int y2 = 8; - matrix[x2, y2] = bit; - } - else - { - // Left bottom corner. - int x2 = 8; - int y2 = matrix.Height - 7 + (i - 8); - matrix[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. - /// - /// The version. - /// The matrix. - public static void maybeEmbedVersionInfo(Version version, ByteMatrix matrix) - { - if (version.VersionNumber < 7) - { - // Version info is necessary if version >= 7. - 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. - var bit = versionInfoBits[bitIndex] ? 1 : 0; - bitIndex--; - // Left bottom corner. - matrix[i, matrix.Height - 11 + j] = bit; - // Right bottom corner. - matrix[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. - /// - /// The data bits. - /// The mask pattern. - /// The matrix. - public 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[xx, y])) - { - continue; - } - int bit; - if (bitIndex < dataBits.Size) - { - bit = dataBits[bitIndex] ? 1 : 0; - ++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[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 - /// - /// The value_ renamed. - /// - public static int findMSBSet(int value_Renamed) - { - int numDigits = 0; - while (value_Renamed != 0) - { - value_Renamed = (int)((uint)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. - /// - /// The value. - /// The poly. - /// - public static int calculateBCHCode(int value, int poly) - { - if (poly == 0) - throw new ArgumentException("0 polynominal", "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. - /// - /// The ec level. - /// The mask pattern. - /// The bits. - public 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. - /// - /// The version. - /// The bits. - public 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. - /// - /// The value. - /// - /// true if the specified value is empty; otherwise, false. - /// - private static bool isEmpty(int value) - { - return value == 2; - } - - 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[i, 6])) - { - matrix[i, 6] = bit; - } - // Vertical line. - if (isEmpty(matrix[6, i])) - { - matrix[6, i] = bit; - } - } - } - - /// - /// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) - /// - /// The matrix. - private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) - { - if (matrix[8, matrix.Height - 8] == 0) - { - throw new WriterException(); - } - matrix[8, matrix.Height - 8] = 1; - } - - private static void embedHorizontalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) - { - for (int x = 0; x < 8; ++x) - { - if (!isEmpty(matrix[xStart + x, yStart])) - { - throw new WriterException(); - } - matrix[xStart + x, yStart] = 0; - } - } - - private static void embedVerticalSeparationPattern(int xStart, int yStart, ByteMatrix matrix) - { - for (int y = 0; y < 7; ++y) - { - if (!isEmpty(matrix[xStart, yStart + y])) - { - throw new WriterException(); - } - matrix[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. - /// - /// The x start. - /// The y start. - /// The matrix. - 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[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[xStart + x, yStart + y] = POSITION_DETECTION_PATTERN[y][x]; - } - } - } - - /// - /// Embed position detection patterns and surrounding vertical/horizontal separators. - /// - /// The matrix. - 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. - const 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. - const 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. - /// - /// The version. - /// The matrix. - 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[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/zxing.core/xx/qrcode/encoder/QRCode.cs b/zxing.core/xx/qrcode/encoder/QRCode.cs deleted file mode 100644 index 1d71ada..0000000 --- a/zxing.core/xx/qrcode/encoder/QRCode.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* -* Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -using System; -using System.Text; - -namespace ZXing.QrCode.Internal -{ - /// satorux@google.com (Satoru Takabayashi) - creator - /// dswitkin@google.com (Daniel Switkin) - ported from C++ - public sealed class QRCode - { - /// - /// - /// - public static int NUM_MASK_PATTERNS = 8; - - /// - /// Initializes a new instance of the class. - /// - public QRCode() - { - MaskPattern = -1; - } - - /// - /// Gets or sets the mode. - /// - /// - /// The mode. - /// - public Mode Mode { get; set; } - - /// - /// Gets or sets the EC level. - /// - /// - /// The EC level. - /// - public ErrorCorrectionLevel ECLevel { get; set; } - - /// - /// Gets or sets the version. - /// - /// - /// The version. - /// - public Version Version { get; set; } - - /// - /// Gets or sets the mask pattern. - /// - /// - /// The mask pattern. - /// - public int MaskPattern { get; set; } - - /// - /// Gets or sets the matrix. - /// - /// - /// The matrix. - /// - public ByteMatrix Matrix { get; set; } - - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override String ToString() - { - var result = new StringBuilder(200); - result.Append("<<\n"); - result.Append(" mode: "); - result.Append(Mode); - result.Append("\n ecLevel: "); - result.Append(ECLevel); - result.Append("\n version: "); - if (Version == null) - result.Append("null"); - else - result.Append(Version); - result.Append("\n maskPattern: "); - result.Append(MaskPattern); - 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. - /// - /// The mask pattern. - /// - /// true if [is valid mask pattern] [the specified mask pattern]; otherwise, false. - /// - public static bool isValidMaskPattern(int maskPattern) - { - return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; - } - } -} \ No newline at end of file diff --git a/zxing.core/xx/qrcode/encoder/QrCodeEncodingOptions.cs b/zxing.core/xx/qrcode/encoder/QrCodeEncodingOptions.cs deleted file mode 100644 index 4f2d4ae..0000000 --- a/zxing.core/xx/qrcode/encoder/QrCodeEncodingOptions.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2012 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; -using ZXing.QrCode.Internal; - -namespace ZXing.QrCode -{ - /// - /// The class holds the available options for the QrCodeWriter - /// - public class QrCodeEncodingOptions : EncodingOptions - { - /// - /// 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 - /// {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}. - /// - public ErrorCorrectionLevel ErrorCorrection - { - get - { - if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) - { - return (ErrorCorrectionLevel) Hints[EncodeHintType.ERROR_CORRECTION]; - } - return null; - } - set - { - if (value == null) - { - if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION)) - Hints.Remove(EncodeHintType.ERROR_CORRECTION); - } - else - { - Hints[EncodeHintType.ERROR_CORRECTION] = value; - } - } - } - - /// - /// Specifies what character encoding to use where applicable (type {@link String}) - /// - public string CharacterSet - { - get - { - if (Hints.ContainsKey(EncodeHintType.CHARACTER_SET)) - { - return (string) Hints[EncodeHintType.CHARACTER_SET]; - } - return null; - } - set - { - if (value == null) - { - if (Hints.ContainsKey(EncodeHintType.CHARACTER_SET)) - Hints.Remove(EncodeHintType.CHARACTER_SET); - } - else - { - Hints[EncodeHintType.CHARACTER_SET] = value; - } - } - } - - /// - /// Explicitly disables ECI segment when generating QR Code - /// That is against the specification of QR Code but some - /// readers have problems if the charset is switched from - /// ISO-8859-1 (default) to UTF-8 with the necessary ECI segment. - /// If you set the property to true you can use UTF-8 encoding - /// and the ECI segment is omitted. - /// - public bool DisableECI - { - get - { - if (Hints.ContainsKey(EncodeHintType.DISABLE_ECI)) - { - return (bool)Hints[EncodeHintType.DISABLE_ECI]; - } - return false; - } - set - { - Hints[EncodeHintType.DISABLE_ECI] = value; - } - } - } -} diff --git a/zxing.core/xx/renderer/IBarcodeRenderer.cs b/zxing.core/xx/renderer/IBarcodeRenderer.cs deleted file mode 100644 index 15e10d0..0000000 --- a/zxing.core/xx/renderer/IBarcodeRenderer.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; - -namespace ZXing.Rendering -{ -#if !(WINDOWS_PHONE || WindowsCE) - /// - /// Interface for a class to convert a BitMatrix to an output image format - /// - public interface IBarcodeRenderer -#else - /// - /// Interface for a class to convert a BitMatrix to an output image format - /// - public interface IBarcodeRenderer -#endif - { - /// - /// Renders the specified matrix to its graphically representation - /// - /// The matrix. - /// The format. - /// The encoded content of the barcode which should be included in the image. - /// That can be the numbers below a 1D barcode or something other. - /// - TOutput Render(BitMatrix matrix, BarcodeFormat format, string content); - - /// - /// Renders the specified matrix to its graphically representation - /// - /// The matrix. - /// The format. - /// The encoded content of the barcode which should be included in the image. - /// That can be the numbers below a 1D barcode or something other. - /// The options. - /// - TOutput Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options); - } -} diff --git a/zxing.core/xx/renderer/PixelData.cs b/zxing.core/xx/renderer/PixelData.cs deleted file mode 100644 index d01ad8e..0000000 --- a/zxing.core/xx/renderer/PixelData.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2012 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.IO; - -namespace ZXing.Rendering -{ - public sealed class PixelData - { - internal PixelData(int width, int height, byte[] pixels) - { - Height = height; - Width = width; - Pixels = pixels; - } - - public byte[] Pixels { get; private set; } - public int Width { get; private set; } - public int Height { get; private set; } - -#if (NET45 || NET40 || NET35 || NET20 || WindowsCE) && !UNITY - public System.Drawing.Bitmap ToBitmap() - { -#if WindowsCE - var bmp = new System.Drawing.Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb); - var bmpData = bmp.LockBits( - new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), - System.Drawing.Imaging.ImageLockMode.WriteOnly, - System.Drawing.Imaging.PixelFormat.Format32bppRgb); -#else - var bmp = new System.Drawing.Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - bmp.SetResolution(96, 96); - var bmpData = bmp.LockBits( - new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), - System.Drawing.Imaging.ImageLockMode.WriteOnly, - System.Drawing.Imaging.PixelFormat.Format32bppArgb); -#endif - try - { - //Copy the data from the byte array into BitmapData.Scan0 - System.Runtime.InteropServices.Marshal.Copy(Pixels, 0, bmpData.Scan0, Pixels.Length); - } - finally - { - //Unlock the pixels - bmp.UnlockBits(bmpData); - } - - return bmp; - } -#endif - -#if UNITY - // Unity3D -#endif - -#if NETFX_CORE - public Windows.UI.Xaml.Media.Imaging.WriteableBitmap ToBitmap() - { - var bmp = new Windows.UI.Xaml.Media.Imaging.WriteableBitmap(Width, Height); - using (var stream = System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.AsStream(bmp.PixelBuffer)) - { - stream.Write(Pixels, 0, Pixels.Length); - } - bmp.Invalidate(); - return bmp; - } -#endif - -#if SILVERLIGHT - public System.Windows.Media.Imaging.WriteableBitmap ToBitmap() - { - var bmp = new System.Windows.Media.Imaging.WriteableBitmap(Width, Height); - bmp.SetSource(new MemoryStream(Pixels)); - bmp.Invalidate(); - return bmp; - } -#endif - -#if MONOANDROID - public Android.Graphics.Bitmap ToBitmap() - { - var pixels = Pixels; - var colors = new int[Width*Height]; - for (var index = 0; index < Width*Height; index++) - { - colors[index] = - pixels[index*4] << 24 | - pixels[index*4 + 1] << 16 | - pixels[index*4 + 2] << 8 | - pixels[index*4 + 3]; - } - return Android.Graphics.Bitmap.CreateBitmap(colors, Width, Height, Android.Graphics.Bitmap.Config.Argb8888); - } -#endif - -#if MONOTOUCH -#if __UNIFIED__ -using UIKit; -#else -using MonoTouch.UIKit; -#endif -#endif - - } -} diff --git a/zxing.core/xx/renderer/RawRenderer.cs b/zxing.core/xx/renderer/RawRenderer.cs deleted file mode 100644 index 8bef55a..0000000 --- a/zxing.core/xx/renderer/RawRenderer.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2014 ZXing.Net authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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 ZXing.Common; - -namespace ZXing.Rendering -{ - /// - /// Renders a to a byte array with ARGB 32bit data - /// - [Obsolete("please use PixelDataRenderer instead")] - public class RawRenderer : IBarcodeRenderer - { - public struct Color - { - public static Color Black = new Color(0); - public static Color White = new Color(0x00FFFFFF); - - public byte A; - public byte R; - public byte G; - public byte B; - - public Color(int color) - { - A = (byte)((color & 0xFF000000) >> 24); - R = (byte)((color & 0x00FF0000) >> 16); - G = (byte)((color & 0x0000FF00) >> 8); - B = (byte)((color & 0x000000FF)); - } - } - - /// - /// Gets or sets the foreground color. - /// - /// - /// The foreground color. - /// - public Color Foreground { get; set; } - /// - /// Gets or sets the background color. - /// - /// - /// The background color. - /// - public Color Background { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public RawRenderer() - { - Foreground = Color.Black; - Background = Color.White; - } - - /// - /// Renders the specified matrix. - /// - /// The matrix. - /// The format. - /// The content. - /// - public byte[] Render(BitMatrix matrix, BarcodeFormat format, string content) - { - return Render(matrix, format, content, null); - } - - /// - /// Renders the specified matrix. - /// - /// The matrix. - /// The format. - /// The content. - /// The options. - /// - virtual public byte[] Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options) - { - int width = matrix.Width; - int height = matrix.Height; - bool outputContent = (options == null || !options.PureBarcode) && - !String.IsNullOrEmpty(content) && (format == BarcodeFormat.CODE_39 || - format == BarcodeFormat.CODE_128 || - format == BarcodeFormat.EAN_13 || - format == BarcodeFormat.EAN_8 || - format == BarcodeFormat.CODABAR || - format == BarcodeFormat.ITF || - format == BarcodeFormat.UPC_A || - format == BarcodeFormat.MSI || - format == BarcodeFormat.PLESSEY); - int emptyArea = outputContent ? 16 : 0; - int pixelsize = 1; - - if (options != null) - { - if (options.Width > width) - { - width = options.Width; - } - if (options.Height > height) - { - height = options.Height; - } - // calculating the scaling factor - pixelsize = width / matrix.Width; - if (pixelsize > height / matrix.Height) - { - pixelsize = height / matrix.Height; - } - } - - var pixels = new byte[width*height*4]; - var index = 0; - - for (int y = 0; y < matrix.Height - emptyArea; y++) - { - for (var pixelsizeHeight = 0; pixelsizeHeight < pixelsize; pixelsizeHeight++) - { - for (var x = 0; x < matrix.Width; x++) - { - var color = matrix[x, y] ? Foreground : Background; - for (var pixelsizeWidth = 0; pixelsizeWidth < pixelsize; pixelsizeWidth++) - { - pixels[index++] = color.A; - pixels[index++] = color.R; - pixels[index++] = color.G; - pixels[index++] = color.B; - } - } - for (var x = pixelsize * matrix.Width; x < width; x++) - { - pixels[index++] = Background.A; - pixels[index++] = Background.R; - pixels[index++] = Background.G; - pixels[index++] = Background.B; - } - } - } - for (int y = matrix.Height * pixelsize - emptyArea; y < height; y++) - { - for (var x = 0; x < width; x++) - { - pixels[index++] = Background.A; - pixels[index++] = Background.R; - pixels[index++] = Background.G; - pixels[index++] = Background.B; - } - } - - return pixels; - } - } -} diff --git a/zxing.core/zxing.core/zxing.core.csproj b/zxing.core/zxing.core/zxing.core.csproj index ec2fc35..ce0fad0 100644 --- a/zxing.core/zxing.core/zxing.core.csproj +++ b/zxing.core/zxing.core/zxing.core.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net462;net472 + netcoreapp3.1 true
- /// Records EAN prefix to GS1 Member Organization, where the member organization - /// correlates strongly with a country. This is an imperfect means of identifying - /// a country of origin by EAN-13 barcode value. See - /// - /// http://en.wikipedia.org/wiki/List_of_GS1_country_codes. - /// - /// Sean Owen - ///