rhodes 2.0.3 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +17 -0
- data/Rakefile +189 -110
- data/bin/rhodes +4 -0
- data/bin/rhodes.bat +1 -0
- data/lib/build/compileERB/default.rb +1 -1
- data/lib/build/jake.rb +54 -2
- data/lib/extensions/barcode/ext/barcode/platform/android/Rakefile +84 -0
- data/lib/extensions/barcode/ext/barcode/platform/android/jni/src/imageprovider.cpp +164 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/Barcode.files +146 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/Rakefile +93 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/Rhode/com/rho/rubyext/BarcodeRecognizer.java +177 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/AUTHORS +35 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/COPYING +201 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/README +11 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/BarcodeFormat.java +88 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/Binarizer.java +80 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/BinaryBitmap.java +128 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/ChecksumException.java +37 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/DecodeHintType.java +79 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/EncodeHintType.java +39 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/FormatException.java +38 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/LuminanceSource.java +113 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/MultiFormatReader.java +164 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/MultiFormatWriter.java +55 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/NotFoundException.java +37 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/Reader.java +64 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/ReaderException.java +98 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/Result.java +102 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/ResultMetadataType.java +63 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/ResultPoint.java +127 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/ResultPointCallback.java +29 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/Writer.java +54 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/WriterException.java +35 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/AbstractDoCoMoResultParser.java +39 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/AddressBookAUResultParser.java +73 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/AddressBookDoCoMoResultParser.java +85 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/AddressBookParsedResult.java +122 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/BizcardResultParser.java +94 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/BookmarkDoCoMoResultParser.java +46 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/CalendarParsedResult.java +130 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/EmailAddressParsedResult.java +61 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/EmailAddressResultParser.java +64 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/EmailDoCoMoResultParser.java +87 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/GeoParsedResult.java +107 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/GeoResultParser.java +64 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ISBNParsedResult.java +39 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ISBNResultParser.java +54 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ParsedResult.java +73 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ParsedResultType.java +52 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ProductParsedResult.java +49 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ProductResultParser.java +66 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/ResultParser.java +313 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/SMSMMSResultParser.java +103 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/SMSParsedResult.java +75 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/TelParsedResult.java +54 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/TelResultParser.java +44 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/TextParsedResult.java +48 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/URIParsedResult.java +113 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/URIResultParser.java +87 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/URLTOResultParser.java +47 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/VCardResultParser.java +195 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/VEventResultParser.java +56 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/AbstractNDEFResultParser.java +45 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/NDEFRecord.java +87 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/NDEFSmartPosterParsedResult.java +63 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/NDEFSmartPosterResultParser.java +81 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/NDEFTextResultParser.java +57 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/client/result/optional/NDEFURIResultParser.java +95 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/BitArray.java +174 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/BitMatrix.java +190 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/BitSource.java +97 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/ByteArray.java +95 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/ByteMatrix.java +93 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/CharacterSetECI.java +110 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/Collections.java +53 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/Comparator.java +27 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/DecoderResult.java +63 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/DefaultGridSampler.java +81 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/DetectorResult.java +46 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/ECI.java +52 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/GlobalHistogramBinarizer.java +196 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/GridSampler.java +171 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/HybridBinarizer.java +158 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/PerspectiveTransform.java +148 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/detector/MonochromeRectangleDetector.java +209 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/reedsolomon/GF256.java +142 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/reedsolomon/GF256Poly.java +263 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/reedsolomon/ReedSolomonDecoder.java +189 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/reedsolomon/ReedSolomonEncoder.java +75 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/common/reedsolomon/ReedSolomonException.java +31 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/DataMatrixReader.java +159 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/decoder/BitMatrixParser.java +446 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/decoder/DataBlock.java +118 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/decoder/DecodedBitStreamParser.java +456 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/decoder/Decoder.java +134 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/decoder/Version.java +242 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/datamatrix/detector/Detector.java +283 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/ByQuadrantReader.java +96 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/GenericMultipleBarcodeReader.java +156 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/MultipleBarcodeReader.java +37 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/qrcode/QRCodeMultiReader.java +80 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/qrcode/detector/MultiDetector.java +72 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/multi/qrcode/detector/MultiFinderPatternFinder.java +324 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/Code128Reader.java +473 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/Code39Reader.java +330 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/EAN13Reader.java +135 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/EAN13Writer.java +82 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/EAN8Reader.java +72 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/EAN8Writer.java +77 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/ITFReader.java +348 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/MultiFormatOneDReader.java +96 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/MultiFormatUPCEANReader.java +107 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/OneDReader.java +297 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/UPCAReader.java +75 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/UPCEANReader.java +332 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/UPCEANWriter.java +129 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/UPCEReader.java +153 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/rss/DataCharacter.java +37 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/rss/FinderPattern.java +48 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/rss/Pair.java +32 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/rss/RSS14Reader.java +557 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/oned/rss/RSSUtils.java +155 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/pdf417/PDF417Reader.java +149 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/pdf417/decoder/BitMatrixParser.java +1157 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/pdf417/decoder/DecodedBitStreamParser.java +627 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/pdf417/decoder/Decoder.java +149 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/pdf417/detector/Detector.java +501 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/QRCodeReader.java +164 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/QRCodeWriter.java +151 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/BitMatrixParser.java +203 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/DataBlock.java +123 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/DataMask.java +155 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/DecodedBitStreamParser.java +361 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/Decoder.java +150 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/ErrorCorrectionLevel.java +86 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/FormatInformation.java +171 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/Mode.java +112 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/decoder/Version.java +586 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/AlignmentPattern.java +48 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java +279 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/Detector.java +396 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/FinderPattern.java +63 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java +540 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/detector/FinderPatternInfo.java +49 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/BitVector.java +155 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/BlockPair.java +39 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/Encoder.java +568 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/MaskUtil.java +219 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/MatrixUtil.java +524 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/core/src/com/google/zxing/qrcode/encoder/QRCode.java +240 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/AdvancedMultimediaManager.java +153 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/DefaultMultimediaManager.java +40 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/LCDUIImageLuminanceSource.java +95 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/MANIFEST.MF.template +11 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/Menu.java +96 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/MultimediaManager.java +39 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/SnapshotThread.java +143 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/SplashThread.java +127 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/VideoCanvas.java +71 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/ZXing/javame/src/com/google/zxing/client/j2me/ZXingMIDlet.java +292 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/barcode.jdp +193 -0
- data/lib/extensions/barcode/ext/barcode/platform/bb/run.bat +3 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Barcode.xcodeproj/project.pbxproj +596 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Barcode_Prefix.pch +7 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Classes/ImageProvider.cpp +25 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Classes/ImageProvider.h +15 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Classes/ImageProvider.mm +159 -0
- data/lib/extensions/barcode/ext/barcode/platform/iphone/Rakefile +61 -0
- data/lib/extensions/barcode/ext/barcode/platform/wm/Barcode.vcproj +271 -0
- data/lib/extensions/barcode/ext/barcode/platform/wm/Rakefile +46 -0
- data/lib/extensions/barcode/ext/barcode/platform/wm/src/wm_imageprovider.cpp +159 -0
- data/lib/extensions/barcode/ext/barcode/shared/ruby/barcode.i +8 -0
- data/lib/extensions/barcode/ext/barcode/shared/ruby/barcode_wrap.c +2200 -0
- data/lib/extensions/barcode/ext/barcode/shared/src/rho_imageprovider.h +16 -0
- data/lib/extensions/barcode/ext/barcode/shared/src/zbar.c +69 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/config.h +264 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/inttypes.h +259 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/rho_bridge.c +29 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/COPYING +27 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/README +95 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Decoder.h +201 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Exception.h +187 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Image.h +321 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ImageScanner.h +130 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Processor.h +223 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/QZBar.h +169 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/QZBarImage.h +72 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Scanner.h +162 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Symbol.h +529 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Video.h +170 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/Window.h +136 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarCaptureReader.h +99 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarImage.h +69 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarImageScanner.h +50 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarReaderController.h +142 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarReaderView.h +119 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarReaderViewController.h +99 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/ZBarSymbol.h +67 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar/zbargtk.h +205 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/include/zbar.h +1415 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/config.c +157 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/convert.c +1172 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/debug.h +87 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/code128.c +528 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/code128.h +49 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/code39.c +335 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/code39.h +50 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/ean.c +660 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/ean.h +86 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/i25.c +243 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/i25.h +50 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/pdf417.c +223 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/pdf417.h +49 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/pdf417_hash.h +545 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/qr_finder.c +102 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder/qr_finder.h +23 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder.c +409 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/decoder.h +219 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/error.c +183 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/error.h +226 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/event.h +62 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/image.c +358 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/image.h +142 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/img_scanner.c +819 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/img_scanner.h +38 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/jpeg.c +241 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/mutex.h +160 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/lock.c +227 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/null.c +62 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/posix.c +337 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/posix.h +138 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/win.c +335 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor/x.c +269 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor.c +700 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/processor.h +126 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/bch15_5.c +184 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/bch15_5.h +20 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/binarize.c +639 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/binarize.h +17 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/isaac.c +139 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/isaac.h +41 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/qrdec.c +3957 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/qrdec.h +168 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/qrdectxt.c +405 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/rs.c +799 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/rs.h +66 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/util.c +140 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode/util.h +48 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/qrcode.h +66 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/refcnt.c +48 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/refcnt.h +96 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/scanner.c +317 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/svg.c +184 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/svg.h +65 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/symbol.c +325 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/symbol.h +93 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/thread.h +127 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/timer.h +151 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/unistd.h +1 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video/null.c +37 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video/v4l1.c +435 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video/v4l2.c +509 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video/vfw.c +494 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video.c +384 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/video.h +160 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/dib.c +75 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/null.c +103 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/vfw.c +104 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/win.c +334 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/win.h +46 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/x.c +356 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/x.h +74 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/ximage.c +219 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window/xv.c +273 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window.c +318 -0
- data/lib/extensions/barcode/ext/barcode/shared/zbar/zbar/zbar/window.h +144 -0
- data/lib/extensions/barcode/ext/build +17 -0
- data/lib/extensions/barcode/ext/build.bat +29 -0
- data/lib/extensions/barcode/ext.yml +3 -0
- data/lib/extensions/crypt/crypt/rijndael.rb +4 -0
- data/lib/extensions/digest/ext/Rakefile +18 -0
- data/lib/extensions/digest/ext/digest.vcproj +134 -0
- data/lib/extensions/digest-md5/ext/Rakefile +18 -0
- data/lib/extensions/digest-md5/ext/digest-md5.vcproj +132 -0
- data/lib/extensions/digest-md5/ext/md5init.c +2 -2
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/expectations/expectations.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/expectations/should.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/expectations.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/fileutils.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/background.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/bug.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/compliance.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/conflict.rb +0 -0
- data/{spec/framework_spec/app → lib/extensions/mspec}/mspec/guards/endian.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/extensions.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/guard.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/noncompliance.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/platform.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/quarantine.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/runner.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/superuser.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/support.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/tty.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards/version.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/guards.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/argv.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/bignum.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/const_lookup.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/ducktype.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/enumerator_class.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/environment.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/fixture.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/flunk.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/fs.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/hash.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/infinity.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/io.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/language_version.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/metaclass.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/mock_to_path.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/nan.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/ruby_exe.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/scratch.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers/tmp.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/helpers.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/base.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_an_instance_of.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_ancestor_of.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_close.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_empty.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_false.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_kind_of.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_nil.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/be_true.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/complain.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/eql.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/equal.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/equal_element.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/equal_utf16.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/have_constant.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/have_instance_method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/have_method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/have_private_instance_method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/have_public_instance_method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/include.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/match_yaml.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/output.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/output_to_fd.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/raise_error.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/respond_to.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers/stringsymboladapter.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/matchers.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/mocks/mock.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/mocks/object.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/mocks/proxy.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/mocks.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/pp.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/debug.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/filter.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/gdb.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/tag.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/taglist.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/tagpurge.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/tally.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions/timer.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/actions.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/context.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/example.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/exception.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/filters/match.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/filters/profile.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/filters/regexp.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/filters/tag.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/filters.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/describe.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/dotted.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/file.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/html.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/method.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/specdoc.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/spinner.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/summary.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/unit.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters/yaml.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/formatters.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/mspec.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/object.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/shared.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner/tag.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/runner.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/utils/name_map.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/utils/options.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/utils/ruby_name.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/utils/script.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/utils/version.rb +0 -0
- data/{res/generators/templates/spec/app → lib/extensions/mspec}/mspec/version.rb +0 -0
- data/lib/extensions/rexml/rexml/parsers/xpathparser.rb +2 -1
- data/lib/extensions/rexml/rexml/xpath_parser.rb +10 -5
- data/lib/extensions/rhospec/rhospec.rb +348 -0
- data/lib/extensions/rhoxml/rexml/attribute.rb +188 -0
- data/lib/extensions/rhoxml/rexml/element.rb +57 -1
- data/lib/extensions/rhoxml/rexml/parsers/streamparser.rb +2 -2
- data/lib/extensions/rhoxml/rexml/xpath_parser.rb +10 -5
- data/lib/framework/builtinME.rb +40 -2
- data/lib/framework/rho/render.rb +19 -15
- data/lib/framework/rho/rho.rb +88 -50
- data/lib/framework/rho/rhoapplication.rb +11 -3
- data/lib/framework/rho/rhocontact.rb +5 -2
- data/lib/framework/rho/rhosupport.rb +2 -2
- data/lib/framework/rho/rhoutils.rb +6 -4
- data/lib/framework/rhodes.rb +2 -2
- data/lib/framework/rhoframework.rb +2 -1
- data/lib/framework/rholang/lang_es.rb +120 -0
- data/lib/framework/rholang/localization_simplified.rb +7 -10
- data/lib/framework/rholang/rhoerror_es.rb +36 -0
- data/lib/framework/rholang/rhomsg_es.rb +28 -0
- data/lib/framework/rhom/rhom_db_adapter.rb +113 -33
- data/lib/framework/rhom/rhom_object_factory.rb +347 -134
- data/lib/framework/version.rb +2 -2
- data/lib/rhodes.rb +2 -2
- data/platform/android/Rhodes/AndroidManifest.xml +3 -2
- data/platform/android/Rhodes/gen/com/rhomobile/rhodes/R.java +40 -28
- data/platform/android/Rhodes/jni/include/rhodes/JNIRhodes.h +2 -0
- data/platform/android/Rhodes/jni/include/rhodes/RhoClassFactory.h +0 -2
- data/platform/android/Rhodes/jni/include/rhodes/details/rhojava.inc +6 -1
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_RhodesService.h +155 -0
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_file_RhoFileApi.h +55 -0
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_geolocation_GeoLocationImpl.h +8 -0
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_signature_Signature.h +21 -0
- data/platform/android/Rhodes/jni/include/rhodes.h +3 -0
- data/platform/android/Rhodes/jni/src/RhoClassFactory.cpp +0 -6
- data/platform/android/Rhodes/jni/src/callbacks.cpp +5 -5
- data/platform/android/Rhodes/jni/src/fileapi.cpp +987 -0
- data/platform/android/Rhodes/jni/src/geolocation.cpp +13 -0
- data/platform/android/Rhodes/jni/src/logconf.cpp +1 -1
- data/platform/android/Rhodes/jni/src/nativeview.cpp +35 -0
- data/platform/android/Rhodes/jni/src/phonebook.cpp +2 -0
- data/platform/android/Rhodes/jni/src/rhodes.cpp +111 -29
- data/platform/android/Rhodes/jni/src/signature.cpp +33 -0
- data/platform/android/Rhodes/jni/src/webview.cpp +6 -0
- data/platform/android/Rhodes/res/drawable/signature_cancel.png +0 -0
- data/platform/android/Rhodes/res/drawable/signature_clear.png +0 -0
- data/platform/android/Rhodes/res/drawable/signature_ok.png +0 -0
- data/platform/android/Rhodes/res/layout/signature.xml +54 -0
- data/platform/android/Rhodes/res/values/strings.xml +22 -20
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/AndroidR.java +8 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/NativeBar.java +6 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/NavBar.java +6 -4
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhoActivity.java +18 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhoMenu.java +4 -4
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/Rhodes.java +26 -689
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesService.java +599 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RingtoneManager.java +1 -1
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/SplashScreen.java +7 -16
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/Utils.java +30 -14
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/WebView.java +11 -27
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/alert/Alert.java +24 -21
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/camera/Camera.java +8 -8
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/camera/FileList.java +5 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/camera/ImageCapture.java +27 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/camera/ImageCaptureCallback.java +4 -1
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/datetime/DateTimePicker.java +4 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/datetime/DateTimePickerScreen.java +4 -4
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/file/RhoFileApi.java +192 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/geolocation/GeoLocation.java +18 -1
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/geolocation/GeoLocationImpl.java +48 -6
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +2 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +39 -40
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +47 -17
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mapview/MapView.java +23 -11
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/nativeview/RhoNativeViewManager.java +14 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorNew.java +5 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/ContactAccessorOld.java +4 -7
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/phonebook/Phonebook.java +2 -1
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/ImageCapture.java +182 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/Signature.java +89 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/SignatureView.java +286 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/ui/LogOptionsDialog.java +12 -8
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/ui/LogViewDialog.java +5 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/util/PerformOnUiThread.java +55 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/ChromeClientNew.java +14 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/ChromeClientOld.java +37 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/RhoWebSettings.java +10 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/RhoWebSettingsNew.java +17 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/RhoWebSettingsOld.java +29 -0
- data/platform/android/build/RhodesSRC_build.files +13 -1
- data/platform/android/build/android.rake +136 -69
- data/platform/android/build/androidcommon.rb +1 -1
- data/platform/android/build/librhocommon_build.files +2 -3
- data/platform/android/build/librhodes_build.files +3 -1
- data/platform/android/build/librhomain_build.files +1 -0
- data/platform/android/build/libruby_build.files +1 -0
- data/platform/bb/Hsqldb/src/com/rho/db/HsqlDBResult.java +1 -1
- data/platform/bb/RubyVM/RubyVM.jdp +415 -416
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/Capabilities.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/DateTimeTokenizer.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/Extensions.java +11 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/FilePath.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/IRhoLogSink.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/IRhoRubyHelper.java +35 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/Mutex.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/Properties.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/RhoAppAdapter.java +96 -0
- data/platform/bb/RubyVM/src/com/rho/RhoClassFactory.java +125 -0
- data/platform/bb/RubyVM/src/com/rho/RhoConf.java +403 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoEmptyLogger.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoEmptyProfiler.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoLogConf.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoLogFileSink.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoLogOutputSink.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/RhoLogger.java +278 -0
- data/platform/bb/RubyVM/src/com/rho/RhoParamArray.java +33 -0
- data/platform/bb/RubyVM/src/com/rho/RhoParams.java +62 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoProfiler.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/RhoRuby.java +257 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/RhoThread.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/RhodesApp.java +307 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/SplashScreen.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/Sprintf.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/StringScanner.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/TestProfiler.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/TestRhoLog.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/ThreadQueue.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/TimeInterval.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/Tokenizer.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/db/DBAdapter.java +1198 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/db/DBAttrManager.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/db/DBException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/db/IDBCallback.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/db/IDBResult.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/db/IDBStorage.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/file/IFile.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/file/IFileAccess.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/file/IRAFile.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/file/RandomAccessFile.java +240 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/file/SimpleFile.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/net/AsyncHttp.java +386 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/net/IHttpConnection.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/net/INetworkAccess.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/net/NetRequest.java +706 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/net/NetResponse.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/net/RhoConnection.java +847 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/net/URI.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/rjson/RJSONTokener.java +247 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/sync/ClientRegister.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/sync/ISyncProtocol.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/sync/ISyncStatusListener.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/sync/JSONArrayIterator.java +62 -0
- data/platform/bb/RubyVM/src/com/rho/sync/JSONEntry.java +75 -0
- data/platform/bb/RubyVM/src/com/rho/sync/JSONStructIterator.java +74 -0
- data/platform/bb/RubyVM/src/com/rho/sync/SyncEngine.java +918 -0
- data/platform/bb/RubyVM/src/com/rho/sync/SyncNotify.java +596 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/rho/sync/SyncProtocol_3.java +0 -0
- data/platform/bb/RubyVM/src/com/rho/sync/SyncSource.java +960 -0
- data/platform/bb/RubyVM/src/com/rho/sync/SyncThread.java +825 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/ObjectSpace_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyArray_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyBignum_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyDir_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyENV_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyExceptionValue_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyFileTestModule_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyFile_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyFixnum_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyFloat_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyGC_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyHash_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyIO_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyInteger_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyMatchData_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyMethodValue_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyNumeric_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyObject_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyProc_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyRandom_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyRange_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyRegexp_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyStringIO_Methods.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/GeneratedMethods/RubyString_Methods.java +275 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyStruct_Methods.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/GeneratedMethods/RubySymbol_Methods.java +44 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyThreadGroup_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyThread_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyTime_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/GeneratedMethods/RubyTopSelf_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/ArrayPacker.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/AttrReader.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/AttrWriter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/ErrnoModuleBuilder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/IErrno.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/InputStreamExecutor.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/ObjectFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/OutputStreamExecutor.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyArray.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyBignum.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyData.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/builtin/RubyDir.java +310 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyENV.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/builtin/RubyFile.java +318 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyFileTestModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyFixnum.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyFloat.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyGC.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyHash.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/builtin/RubyIO.java +398 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyIOExecutor.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/builtin/RubyIOFileExecutor.java +218 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyIOPipeSinkExecutor.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyIOPipeSourceExecutor.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyInteger.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyMatchData.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyMethodValue.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyMutex.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyNumeric.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyProc.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyRandom.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyRange.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyRegexp.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/builtin/RubyString.java +1521 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyStruct.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyThread.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyThreadGroup.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyTime.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyTopSelf.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/builtin/RubyTypesUtil.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/AtExitBlocks.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/ClassFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/GlobalVariables.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/MethodBlockBase.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/MethodCache.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/ObjectSpace.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RhoSupport.java +367 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyAPI.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyBasic.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyBinding.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyBlock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyClass.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyClass_Methods.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RubyConstant.java +31 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyExceptionValue.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyExceptionValueForThrow.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyID.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyIncludeClass.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyKernelModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyKernelModule_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyMarshalModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyMarshalModule_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyMathModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyMathModule_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyModule_Methods.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyNoArgBlock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyNoArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyNoOrOneArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyObject.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyOneArgBlock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyOneArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyOneOrTwoArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyProgram.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RubyRuntime.java +526 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubySingletonClass.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubySpecialValue.java +0 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RubySymbol.java +309 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyTwoArgBlock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyTwoArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyValue.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyVarArgBlock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/RubyVarArgMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/DummyMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyAllocMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyLevelClass.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyLevelConstant.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyLevelMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyLevelModule.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/RubyLevelObject.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/annotation/UndefMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/CgMethodItem.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/DummyMethod.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/MethodFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/MethodFactoryHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/MethodType.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/NoArgRunMethodHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/OneArgRunMethodHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyClassBuilder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyClassFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyModuleBuilder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyModuleFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyObjectBuilder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyObjectFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RubyTypeFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/RunMethodHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/TwoArgRunMethodHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/lang/util/VarArgRunMethodHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/com/xruby/runtime/stdlib/RubyStringIO.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/CharConversionException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/Closeable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/DataInput.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/DataOutput.java +0 -0
- data/platform/bb/RubyVM/src/j2me/io/File.java +222 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/FileFilter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/FileInputStream.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/FileNotFoundException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/FileOutputStream.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/FilenameFilter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/Flushable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/InvalidClassException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/InvalidObjectException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/NotActiveException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/NotSerializableException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectInput.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectInputStream.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectInputValidation.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectOutput.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectOutputStream.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/ObjectStreamException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/OptionalDataException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/RandomAccessFile.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/Serializable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/StreamCorruptedException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/SyncFailedException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/io/WriteAbortedException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/ArrayMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/AssertMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/CalendarMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/CharSequence.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/CharacterDataLatin1.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/CharacterMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/CloneNotSupportedException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Cloneable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Comparable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Convert.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/EnumConstantNotPresentException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/IllegalStateException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Iterable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/MathEx.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/NoSuchFieldException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/NoSuchMethodException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Number.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/PrintStreamMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/Readable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/SecurityException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/StringBufferMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/StringMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/SystemMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/ThreadLocal.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/TimeZoneMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/TypeNotPresentException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/lang/UnsupportedOperationException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/math/HugeDigit.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/math/HugeInt.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/math/HugeIntHelper.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/Buffer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/BufferUnderflowException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/ByteBuffer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/ByteOrder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/CharBuffer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/InvalidMarkException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/channels/FileChannel.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/nio/channels/Pipe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/text/ParsePosition.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/ArrayList.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Collection.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Collections.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Comparator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/ConcurrentModificationException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/DuplicateFormatFlagsException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/EventListener.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/FormatFlagsConversionMismatchException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Formattable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Formatter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/FormatterClosedException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/HashMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/HashSet.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatCodePointException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatConversionException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatFlagsException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatPrecisionException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/IllegalFormatWidthException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/InputMismatchException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/InvalidPropertiesFormatException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Iterator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/LinkedHashMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/LinkedHashSet.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/LinkedList.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/List.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/ListIterator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Locale.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Map.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/MissingFormatArgumentException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/MissingFormatWidthException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/MissingResourceException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/NavigableMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/NavigableSet.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/NoSuchElementException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Observable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Observer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Queue.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/RandomAccess.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/RandomMe.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/Set.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/SortedMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/SortedSet.java +0 -0
- data/platform/bb/RubyVM/src/j2me/util/StringParser.java +245 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/TooManyListenersException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/UnknownFormatConversionException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/UnknownFormatFlagsException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/WeakHashMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/concurrent/ConcurrentHashMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/concurrent/ConcurrentMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/concurrent/atomic/AtomicLong.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/concurrent/locks/ReentrantLock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/logging/Level.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/logging/LogRecord.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/logging/Logger.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/zip/ZipEntry.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2me/util/zip/ZipFile.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2mex/realtime/MemoryArea.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2mex/realtime/NoHeapRealtimeThread.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/j2mex/realtime/RealtimeThread.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/Javolution.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/JavolutionError.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/Allocator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/AllocatorContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ArrayFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ConcurrentContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ConcurrentException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ConcurrentThread.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/Context.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/HeapContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ImmortalContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/LocalContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/LogContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/ObjectFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/PersistentContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/SecurityContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/context/StackContext.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/AppendableWriter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/CharSequenceReader.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/UTF8ByteBufferReader.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/UTF8ByteBufferWriter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/UTF8StreamReader.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/io/UTF8StreamWriter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/ClassInitializer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Configurable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Enum.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Immutable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/MathLib.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Realtime.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Reference.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Reflection.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/Reusable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/lang/ValueType.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/Appendable.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/CharArray.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/CharSet.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/Text.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/TextBuilder.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/TextFormat.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/text/TypeFormat.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastCollection.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastComparator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastIterator.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastList.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/FastSet.java +0 -0
- data/platform/bb/RubyVM/src/javolution/util/FastTable.java +975 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/Index.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/LocalMap.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/ReentrantLock.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/StandardLog.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/doc-files/list-add.png +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/javolution/util/doc-files/map-put.png +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/io/GlobFilenameFilter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/io/RegexFilenameFilter.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/GenericPatternCache.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/GlobCompiler.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/MalformedCachePatternException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/PatternCache.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/PatternCacheLRU.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/PatternMatchingEngineFactory.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/perl/MalformedPerl5PatternException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/perl/ParsedSubstitutionEntry.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/perl/Perl5Util.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/CharStringPointer.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/MalformedPatternException.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/MatchResult.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/OpCode.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Pattern.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/PatternCompiler.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/PatternCompilerOptions.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/PatternMatcher.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/PatternMatcherInput.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/PatternMatchingEngine.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5Compiler.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5MatchResult.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5Matcher.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5Pattern.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5Repetition.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Perl5Substitution.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/StringSubstitution.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Substitution.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/text/regex/Util.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/util/Cache.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/util/CacheLRU.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/util/GenericCache.java +0 -0
- data/platform/{shared/rubyJVM → bb/RubyVM}/src/org/apache/oro/util/GenericCacheEntry.java +0 -0
- data/platform/bb/RubyVM/src/org/json/me/RhoJSONArray.java +871 -0
- data/platform/bb/RubyVM/src/org/json/me/RhoJSONException.java +27 -0
- data/platform/bb/RubyVM/src/org/json/me/RhoJSONObject.java +1290 -0
- data/platform/bb/RubyVM/src/org/json/me/RhoJSONString.java +18 -0
- data/platform/bb/RubyVM/src/org/json/me/RhoJSONTokener.java +460 -0
- data/platform/bb/build/RubyVM_build.files +412 -411
- data/platform/bb/build/bb.rake +240 -90
- data/platform/bb/rhodes/platform/6.0/com/rho/BrowserAdapter5.java +155 -0
- data/platform/bb/rhodes/platform/6.0/com/rho/RhoMainScreen.java +36 -0
- data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +5 -0
- data/platform/bb/rhodes/src/com/rho/file/Jsr75RAFileImpl.java +2 -2
- data/platform/bb/rhodes/src/com/rho/net/BaseSocket.java +6 -0
- data/platform/bb/rhodes/src/com/rho/net/NetworkAccess.java +1 -1
- data/platform/bb/rhodes/src/com/rho/net/SSLSocket.java +15 -0
- data/platform/bb/rhodes/src/com/rho/net/TCPSocket.java +15 -0
- data/platform/bb/rhodes/src/com/rho/rubyext/GeoLocation.java +2 -2
- data/platform/bb/rhodes/src/com/rho/rubyext/WebView.java +8 -3
- data/platform/bb/rhodes/src/rhomobile/PushListeningThread.java +39 -9
- data/platform/bb/rhodes/src/rhomobile/RhodesApplication.java +40 -42
- data/platform/bb/rhodes/src/rhomobile/RingtoneManager.java +2 -10
- data/platform/bb/rhodes/src/rhomobile/mapview/GoogleMapField.java +10 -10
- data/platform/iphone/Classes/AppManager/AppManager.m +9 -2
- data/platform/iphone/Classes/Camera/PickImageDelegate.m +6 -4
- data/platform/iphone/Classes/DateTimePicker.m +2 -0
- data/platform/iphone/Classes/DateTimePickerDelegate.m +19 -7
- data/platform/iphone/Classes/GeoLocation/LocationController.m +4 -0
- data/platform/iphone/Classes/MapView/MapViewController.h +1 -1
- data/platform/iphone/Classes/MapView/MapViewController.m +4 -1
- data/platform/iphone/Classes/NativeBar.m +7 -1
- data/platform/iphone/Classes/NavBar.m +4 -1
- data/platform/iphone/Classes/Phonebook/phonebook.m +5 -0
- data/platform/iphone/Classes/RhoAlert.h +1 -1
- data/platform/iphone/Classes/RhoAlert.m +8 -0
- data/platform/iphone/Classes/RhoMainView.h +0 -1
- data/platform/iphone/Classes/RhoNativeViewManager.mm +224 -0
- data/platform/iphone/Classes/RhoNativeViewManagerOC.h +45 -0
- data/platform/iphone/Classes/Rhodes.h +4 -1
- data/platform/iphone/Classes/Rhodes.m +157 -55
- data/platform/iphone/Classes/Signature/SignatureDelegate.h +29 -0
- data/platform/iphone/Classes/Signature/SignatureDelegate.m +98 -0
- data/platform/iphone/Classes/Signature/SignatureView.h +31 -0
- data/platform/iphone/Classes/Signature/SignatureView.m +216 -0
- data/platform/iphone/Classes/Signature/SignatureViewController.h +25 -0
- data/platform/iphone/Classes/Signature/SignatureViewController.m +163 -0
- data/platform/iphone/Classes/SimpleMainView.h +11 -1
- data/platform/iphone/Classes/SimpleMainView.m +243 -57
- data/platform/iphone/Classes/TabbedMainView.h +2 -0
- data/platform/iphone/Classes/TabbedMainView.m +9 -10
- data/platform/iphone/Classes/WebView.m +38 -24
- data/platform/iphone/Classes/rho/net/NetRequestImpl.m +11 -1
- data/platform/iphone/Entitlements.plist +6 -0
- data/platform/iphone/Info.plist +1 -1
- data/platform/iphone/RhoLib/RhoLib.xcodeproj/project.pbxproj +20 -16
- data/platform/iphone/rbuild/iphone.rake +138 -134
- data/platform/iphone/rhorubylib/rhorubylib.xcodeproj/project.pbxproj +19 -7
- data/platform/iphone/rhorunner.xcodeproj/project.pbxproj +65 -23
- data/platform/shared/SyncClient/RhoError.h +29 -0
- data/platform/shared/SyncClient/SyncClient.cpp +860 -0
- data/platform/shared/SyncClient/SyncClient.h +76 -0
- data/platform/shared/common/IRhoClassFactory.h +1 -3
- data/platform/shared/common/PosixThreadImpl.cpp +30 -12
- data/platform/shared/common/PosixThreadImpl.h +1 -0
- data/platform/shared/common/RhoAppAdapter.h +34 -0
- data/platform/shared/common/RhoConf.cpp +6 -5
- data/platform/shared/common/RhoConf.h +2 -1
- data/platform/shared/common/RhoFile.cpp +22 -3
- data/platform/shared/common/RhoFile.h +1 -1
- data/platform/shared/common/RhoNativeViewManager.h +43 -0
- data/platform/shared/common/RhoPort.h +16 -0
- data/platform/shared/common/RhoStd.h +9 -2
- data/platform/shared/common/RhoThread.h +2 -2
- data/platform/shared/common/RhodesApp.cpp +193 -111
- data/platform/shared/common/RhodesApp.h +28 -27
- data/platform/shared/common/RhodesAppBase.cpp +130 -0
- data/platform/shared/common/RhodesAppBase.h +64 -0
- data/platform/shared/common/SplashScreen.cpp +1 -1
- data/platform/shared/common/ThreadQueue.cpp +3 -3
- data/platform/shared/common/ThreadQueue.h +7 -7
- data/platform/shared/common/Tokenizer.h +2 -1
- data/platform/shared/common/iphone/RhoClassFactory.cpp +22 -0
- data/platform/shared/common/iphone/RhoClassfactory.h +29 -0
- data/platform/shared/common/iphone/RhoFileImpl.m +46 -0
- data/platform/shared/common/iphone/RhoThreadImpl.m +24 -0
- data/platform/shared/common/rhoparams.cpp +188 -0
- data/platform/shared/common/rhoparams.h +35 -42
- data/platform/shared/curl/lib/url.c +1 -1
- data/platform/shared/db/DBAdapter.cpp +68 -22
- data/platform/shared/db/DBAdapter.h +36 -5
- data/platform/shared/db/DBAttrManager.cpp +4 -0
- data/platform/shared/db/DBAttrManager.h +2 -1
- data/platform/shared/db/DBResult.cpp +2 -2
- data/platform/shared/db/DBResult.h +25 -5
- data/{res/build-tools → platform/shared/db/res}/db/syncdb.schema +0 -0
- data/{res/build-tools → platform/shared/db/res}/db/syncdb.triggers +0 -0
- data/platform/shared/json/JSONIterator.cpp +4 -2
- data/platform/shared/json/RJSONTokener.c +16 -13
- data/platform/shared/logging/RhoLog.cpp +1 -1
- data/platform/shared/logging/RhoLogConf.cpp +12 -0
- data/platform/shared/net/AsyncHttp.cpp +62 -63
- data/platform/shared/net/AsyncHttp.h +26 -17
- data/platform/shared/net/CURLNetRequest.cpp +248 -156
- data/platform/shared/net/CURLNetRequest.h +42 -16
- data/platform/shared/net/HttpServer.cpp +58 -84
- data/platform/shared/net/HttpServer.h +6 -5
- data/platform/shared/net/URI.cpp +39 -0
- data/platform/shared/net/URI.h +3 -0
- data/platform/{iphone/Classes/rho/net → shared/net/iphone}/sslimpl.cpp +0 -0
- data/platform/{iphone/Classes/rho/net → shared/net/iphone}/sslimpl.h +0 -0
- data/platform/shared/net/ssl.cpp +1 -1
- data/platform/shared/ruby/ext/alert/alert.i +1 -1
- data/platform/shared/ruby/ext/alert/alert_wrap.c +8 -8
- data/platform/shared/ruby/ext/asynchttp/asynchttp.i +10 -17
- data/platform/shared/ruby/ext/asynchttp/asynchttp_wrap.c +20 -340
- data/platform/shared/ruby/ext/mapview/mapview.i +1 -1
- data/platform/shared/ruby/ext/mapview/mapview_wrap.c +8 -8
- data/platform/shared/ruby/ext/nativebar/nativebar.i +1 -1
- data/platform/shared/ruby/ext/nativebar/nativebar_wrap.c +8 -8
- data/platform/shared/ruby/ext/navbar/navbar.i +1 -1
- data/platform/shared/ruby/ext/navbar/navbar_wrap.c +8 -8
- data/platform/shared/ruby/ext/rho/rhoruby.c +29 -9
- data/platform/shared/ruby/ext/rho/rhoruby.h +45 -7
- data/platform/shared/ruby/ext/rhoconf/rhoconf.i +9 -2
- data/platform/shared/ruby/ext/rhoconf/rhoconf_wrap.c +431 -122
- data/platform/shared/ruby/ext/signature/signature.i +8 -0
- data/platform/shared/ruby/ext/signature/signature_wrap.c +2184 -0
- data/platform/shared/ruby/ext/sqlite3_api/sqlite3_api_wrap.c +32 -26
- data/platform/shared/ruby/ext/syncengine/syncengine.i +8 -10
- data/platform/shared/ruby/ext/syncengine/syncengine_wrap.c +449 -208
- data/platform/shared/ruby/ext/webview/webview.i +1 -1
- data/platform/shared/ruby/ext/webview/webview_wrap.c +11 -11
- data/platform/shared/ruby/file.c +19 -11
- data/platform/shared/ruby/linux/ruby/config.h +8 -8
- data/platform/shared/ruby/strftime.c +9 -1
- data/platform/shared/ruby/wince/io_wce.c +69 -29
- data/platform/shared/ruby/wince/sys/stat.c +1 -1
- data/platform/shared/ruby/wince/sys/timeb.c +1 -0
- data/platform/shared/ruby/wince/wince.h +1 -0
- data/platform/shared/rubyext/GeoLocation.cpp +27 -11
- data/platform/shared/rubyext/GeoLocation.h +8 -2
- data/platform/shared/rubyext/RhoAppAdapter.cpp +41 -0
- data/platform/shared/rubyext/System.cpp +1 -18
- data/platform/shared/rubyext/WebView.h +3 -1
- data/platform/shared/sync/ClientRegister.cpp +2 -3
- data/platform/shared/sync/ClientRegister.h +0 -2
- data/platform/shared/sync/SyncEngine.cpp +136 -65
- data/platform/shared/sync/SyncEngine.h +9 -4
- data/platform/shared/sync/SyncNotify.cpp +123 -180
- data/platform/shared/sync/SyncNotify.h +34 -24
- data/platform/shared/sync/SyncSource.cpp +36 -33
- data/platform/shared/sync/SyncSource.h +9 -3
- data/platform/shared/sync/SyncThread.cpp +116 -38
- data/platform/shared/sync/SyncThread.h +26 -30
- data/platform/shared/test/test_helper.cpp +50 -0
- data/platform/shared/test/test_helper.h +2 -0
- data/platform/shared/xruby/src/com/xruby/compiler/codedom/AsciiValueExpression.java +54 -48
- data/platform/shared/xruby/src/com/xruby/compiler/codegen/ClassGeneratorForRubyProgram.java +95 -95
- data/platform/shared/xruby/src/com/xruby/compiler/codegen/RubyCompilerImpl.java +1 -1
- data/platform/shared/xruby/src/com/xruby/compiler/codegen/RubyIDClassGenerator.java +102 -100
- data/platform/wm/RhoLib/RhoLib.vcproj +10 -10
- data/platform/wm/build/build_inf.js +1 -1
- data/platform/wm/build/wm.rake +73 -14
- data/platform/wm/rhodes/Alert.cpp +1 -1
- data/platform/wm/rhodes/MainWindow.cpp +23 -4
- data/platform/wm/rhodes/MainWindow.h +3 -1
- data/platform/wm/rhodes/Rhodes.cpp +6 -5
- data/platform/wm/rhodes/Vibrate.cpp +1 -1
- data/platform/wm/rhodes/camera/Camera.cpp +2 -2
- data/platform/wm/rhodes/phonebook/phonebook.cpp +2 -0
- data/platform/wm/rhodes/rho/common/RhoClassFactory.cpp +2 -7
- data/platform/wm/rhodes/rho/common/RhoClassFactory.h +0 -6
- data/platform/wm/rhodes/rho/common/RhoThreadImpl.h +1 -0
- data/platform/wm/rhodes/rho/net/NetRequest.cpp +1 -1
- data/platform/wm/rhodes/rho/net/NetRequest.h +1 -0
- data/platform/wm/rhodes/rho/net/NetRequestImpl.cpp +8 -3
- data/platform/wm/rhodes/rho/net/NetRequestImpl.h +1 -0
- data/platform/wm/rhodes/rho/rubyext/SystemImpl.cpp +13 -10
- data/platform/wm/rhodes/rho/rubyext/WebView.cpp +11 -1
- data/platform/wm/rhodes/rhodes.vcproj +26 -9
- data/platform/wm/rhodes/signature/Signature.cpp +28 -0
- data/platform/wm/rhodes/signature/Signature.h +3 -0
- data/platform/wm/rhodes/stdafx.h +5 -0
- data/platform/wm/rubylib/rubylib.vcproj +11 -3
- data/platform/wm/syncengine/syncengine.vcproj +1 -1
- data/platform/wm/tcmalloc/tcmalloc.vcproj +1 -0
- data/rakefile.rb +189 -110
- data/res/build-tools/xruby-0.3.3.jar +0 -0
- data/res/generators/rhogen.rb +9 -9
- data/res/generators/templates/application/app/Settings/home.erb +15 -18
- data/res/generators/templates/application/app/Settings/index.erb +26 -42
- data/res/generators/templates/application/app/Settings/login.erb +19 -23
- data/res/generators/templates/application/app/Settings/reset.erb +12 -13
- data/res/generators/templates/application/app/Settings/wait.erb +2 -2
- data/res/generators/templates/application/app/application.rb +6 -2
- data/res/generators/templates/application/app/helpers/application_helper.rb +39 -21
- data/res/generators/templates/application/app/index.erb +21 -18
- data/res/generators/templates/application/app/layout.erb +38 -21
- data/res/generators/templates/application/build.yml +2 -1
- data/res/generators/templates/application/public/css/android.css +122 -88
- data/res/generators/templates/application/public/css/iphone.css +161 -133
- data/res/generators/templates/application/public/css/windows_mobile.css +126 -116
- data/res/generators/templates/application/public/images/iphone/jqtouch/backButton.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/blueButton.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/cancel.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/chevron.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/grayButton.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/listArrowSel.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/listGroup.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/loading.gif +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/on_off.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/pinstripes.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/selection.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/thumb.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/toggle.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/toggleOn.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/toolButton.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/toolbar.png +0 -0
- data/res/generators/templates/application/public/images/iphone/jqtouch/whiteButton.png +0 -0
- data/res/generators/templates/application/public/jqtouch/jqtouch.css +378 -0
- data/res/generators/templates/application/public/jqtouch/jqtouch.js +741 -0
- data/res/generators/templates/application/public/jqtouch/jqtouch.transitions.js +60 -0
- data/res/generators/templates/application/public/jqtouch/jquery.1.3.2.min.js +19 -0
- data/res/generators/templates/application/rhoconfig.txt +6 -0
- data/res/generators/templates/model/controller.rb +1 -2
- data/res/generators/templates/model/edit.erb +22 -18
- data/res/generators/templates/model/index.erb +25 -25
- data/res/generators/templates/model/model.rb +4 -1
- data/res/generators/templates/model/new.erb +20 -17
- data/res/generators/templates/model/show.erb +16 -12
- data/res/generators/templates/spec/app/mspec.rb +4 -1
- data/res/generators/templates/spec/app/spec_runner.rb +4 -6
- data/rhobuild.yml.example +13 -7
- data/rhodes.gemspec +3 -2
- data/spec/framework_spec/app/SpecRunner/controller.rb +0 -2
- data/spec/framework_spec/app/mspec.rb +4 -1
- data/spec/framework_spec/app/spec/core/dir/mkdir_spec.rb +3 -2
- data/spec/framework_spec/app/spec/core/dir/path_spec.rb +1 -1
- data/spec/framework_spec/app/spec/core/dir/shared/delete.rb +4 -2
- data/spec/framework_spec/app/spec/core/file/basename_spec.rb +10 -10
- data/spec/framework_spec/app/spec/core/file/constants/constants_spec.rb +2 -0
- data/spec/framework_spec/app/spec/core/file/inspect_spec.rb +5 -3
- data/spec/framework_spec/app/spec/core/file/path_spec.rb +1 -1
- data/spec/framework_spec/app/spec/core/file/shared/fnmatch.rb +5 -5
- data/spec/framework_spec/app/spec/core/file/shared/stat.rb +2 -2
- data/spec/framework_spec/app/spec/core/file/split_spec.rb +2 -1
- data/spec/framework_spec/app/spec/core/math/atanh_spec.rb +8 -6
- data/spec/framework_spec/app/spec/shared/file/readable.rb +2 -1
- data/spec/framework_spec/app/spec_runner.rb +50 -30
- data/spec/framework_spec/build.yml +7 -4
- data/spec/perfomance_spec/Rakefile +27 -0
- data/spec/perfomance_spec/app/Perftest/controller.rb +92 -0
- data/spec/perfomance_spec/app/Perftest/index.erb +21 -0
- data/spec/perfomance_spec/app/Perftest/perftest.rb +4 -0
- data/spec/perfomance_spec/app/application.rb +4 -0
- data/spec/perfomance_spec/app/index.erb +0 -0
- data/spec/perfomance_spec/app/layout.erb +25 -0
- data/spec/perfomance_spec/build.yml +22 -0
- data/spec/perfomance_spec/icon/icon.ico +0 -0
- data/spec/perfomance_spec/icon/icon.png +0 -0
- data/spec/perfomance_spec/public/css/android.css +287 -0
- data/spec/perfomance_spec/public/css/blackberry.css +114 -0
- data/spec/perfomance_spec/public/css/iphone.css +382 -0
- data/{res/generators/templates/application → spec/perfomance_spec}/public/css/webkit.css +0 -0
- data/spec/perfomance_spec/public/css/windows_mobile.css +212 -0
- data/spec/perfomance_spec/public/pinstripes.png +0 -0
- data/spec/perfomance_spec/rhoconfig.txt +34 -0
- data/spec/phone_spec/app/Account/account.rb +7 -0
- data/spec/phone_spec/app/Account_s/account_s.rb +50 -0
- data/spec/phone_spec/app/Barcode/Barcode_UPC_01.png +0 -0
- data/spec/phone_spec/app/Barcode/Barcode_UPC_02.jpg +0 -0
- data/spec/{framework_spec → phone_spec}/app/BlobTest/blob_test.rb +0 -0
- data/spec/{framework_spec → phone_spec}/app/BlobTest/test.png +0 -0
- data/spec/{framework_spec → phone_spec}/app/BlobTest/test2.png +0 -0
- data/spec/{framework_spec → phone_spec}/app/Case/case.rb +0 -0
- data/spec/phone_spec/app/Case_s/case_s.rb +25 -0
- data/spec/phone_spec/app/Customer/customer.rb +7 -0
- data/spec/phone_spec/app/Customer_s/customer_s.rb +21 -0
- data/spec/phone_spec/app/Data/big_test.json +1 -0
- data/spec/phone_spec/app/Data/reqTest.rb +5 -0
- data/spec/phone_spec/app/Data/test1.xml +6 -0
- data/spec/phone_spec/app/Data/test_log.txt +1 -0
- data/spec/phone_spec/app/Product/product.rb +29 -0
- data/spec/phone_spec/app/Product_s/product_s.rb +22 -0
- data/spec/phone_spec/app/Spec/asynchttp_spec.rb +131 -38
- data/spec/phone_spec/app/Spec/barcode_spec.rb +19 -0
- data/spec/phone_spec/app/Spec/blobsync_spec.rb +154 -0
- data/spec/{framework_spec/app/spec → phone_spec/app/Spec}/bsearch_spec.rb +0 -0
- data/spec/phone_spec/app/Spec/bulksync_spec.rb +74 -0
- data/spec/phone_spec/app/Spec/contacts_spec.rb +23 -25
- data/spec/phone_spec/app/Spec/crypt_spec.rb +14 -0
- data/spec/phone_spec/app/Spec/date_spec.rb +17 -0
- data/spec/{framework_spec/app/spec → phone_spec/app/Spec}/fixtures/client_info.txt +0 -0
- data/spec/phone_spec/app/Spec/fixtures/object_values.txt +90 -0
- data/spec/phone_spec/app/Spec/json_spec.rb +79 -42
- data/spec/phone_spec/app/Spec/mapview_spec.rb +10 -12
- data/spec/phone_spec/app/Spec/nativebar_spec.rb +5 -7
- data/spec/phone_spec/app/Spec/navbar_spec.rb +6 -9
- data/spec/phone_spec/app/Spec/pagination/fixtures/object_values.txt +91 -0
- data/spec/phone_spec/app/Spec/rho_controller_spec.rb +156 -0
- data/spec/phone_spec/app/Spec/rho_spec.rb +483 -0
- data/spec/phone_spec/app/Spec/rhofile_spec.rb +52 -18
- data/spec/phone_spec/app/Spec/rhom_object_spec.rb +835 -0
- data/spec/phone_spec/app/Spec/syncengine_spec.rb +287 -0
- data/spec/phone_spec/app/Spec/xml_spec.rb +88 -24
- data/spec/phone_spec/app/Spec/xruby_spec.rb +61 -4
- data/spec/phone_spec/app/SpecRunner/controller.rb +22 -0
- data/spec/phone_spec/app/SpecRunner/index.erb +17 -0
- data/spec/phone_spec/app/index.erb +1 -1
- data/spec/phone_spec/app/spec_runner.rb +41 -0
- data/spec/phone_spec/build.yml +16 -6
- data/spec/phone_spec/rhoconfig.txt +2 -1
- data/spec/phone_spec/server.rb +5 -0
- metadata +944 -696
- data/platform/android/Rhodes/jni/include/rhodes/SystemInfoImpl.h +0 -26
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_Rhodes.h +0 -131
- data/platform/android/Rhodes/jni/src/syncengine.cpp +0 -13
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesInstance.java +0 -40
- data/platform/iphone/Classes/RhoFileImpl.m +0 -40
- data/platform/iphone/Classes/rho/common/RhoClassFactory.cpp +0 -26
- data/platform/iphone/Classes/rho/common/RhoClassFactory.h +0 -34
- data/platform/iphone/Classes/rho/common/SystemInfoImpl.h +0 -20
- data/platform/shared/common/ISystemInfo.h +0 -16
- data/platform/shared/common/rhoparams.c +0 -105
- data/platform/shared/rubyJVM/src/com/rho/Convert.java +0 -1989
- data/platform/shared/rubyJVM/src/com/rho/IRhoRubyHelper.java +0 -34
- data/platform/shared/rubyJVM/src/com/rho/RhoClassFactory.java +0 -122
- data/platform/shared/rubyJVM/src/com/rho/RhoConf.java +0 -370
- data/platform/shared/rubyJVM/src/com/rho/RhoLogger.java +0 -275
- data/platform/shared/rubyJVM/src/com/rho/RhoRuby.java +0 -333
- data/platform/shared/rubyJVM/src/com/rho/RhodesApp.java +0 -308
- data/platform/shared/rubyJVM/src/com/rho/db/DBAdapter.java +0 -1189
- data/platform/shared/rubyJVM/src/com/rho/file/RandomAccessFile.java +0 -229
- data/platform/shared/rubyJVM/src/com/rho/net/AsyncHttp.java +0 -401
- data/platform/shared/rubyJVM/src/com/rho/net/NetRequest.java +0 -692
- data/platform/shared/rubyJVM/src/com/rho/net/RhoConnection.java +0 -847
- data/platform/shared/rubyJVM/src/com/rho/rjson/RJSONTokener.java +0 -247
- data/platform/shared/rubyJVM/src/com/rho/sync/JSONArrayIterator.java +0 -62
- data/platform/shared/rubyJVM/src/com/rho/sync/JSONEntry.java +0 -75
- data/platform/shared/rubyJVM/src/com/rho/sync/JSONStructIterator.java +0 -74
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncEngine.java +0 -846
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncNotify.java +0 -664
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncSource.java +0 -954
- data/platform/shared/rubyJVM/src/com/rho/sync/SyncThread.java +0 -822
- data/platform/shared/rubyJVM/src/com/xruby/GeneratedMethods/RubyString_Methods.java +0 -264
- data/platform/shared/rubyJVM/src/com/xruby/GeneratedMethods/RubySymbol_Methods.java +0 -37
- data/platform/shared/rubyJVM/src/com/xruby/runtime/builtin/RubyDir.java +0 -307
- data/platform/shared/rubyJVM/src/com/xruby/runtime/builtin/RubyFile.java +0 -312
- data/platform/shared/rubyJVM/src/com/xruby/runtime/builtin/RubyIO.java +0 -395
- data/platform/shared/rubyJVM/src/com/xruby/runtime/builtin/RubyIOFileExecutor.java +0 -218
- data/platform/shared/rubyJVM/src/com/xruby/runtime/builtin/RubyString.java +0 -1462
- data/platform/shared/rubyJVM/src/com/xruby/runtime/lang/RhoSupport.java +0 -364
- data/platform/shared/rubyJVM/src/com/xruby/runtime/lang/RubyConstant.java +0 -26
- data/platform/shared/rubyJVM/src/com/xruby/runtime/lang/RubyRuntime.java +0 -482
- data/platform/shared/rubyJVM/src/com/xruby/runtime/lang/RubySymbol.java +0 -303
- data/platform/shared/rubyJVM/src/j2me/io/File.java +0 -222
- data/platform/shared/rubyJVM/src/j2me/util/StringParser.java +0 -236
- data/platform/shared/rubyJVM/src/javolution/context/package.html +0 -123
- data/platform/shared/rubyJVM/src/javolution/io/package.html +0 -5
- data/platform/shared/rubyJVM/src/javolution/lang/package.html +0 -4
- data/platform/shared/rubyJVM/src/javolution/text/package.html +0 -56
- data/platform/shared/rubyJVM/src/javolution/util/FastTable.java +0 -975
- data/platform/shared/rubyJVM/src/javolution/util/package.html +0 -244
- data/platform/shared/rubyJVM/src/org/json/me/JSONArray.java +0 -871
- data/platform/shared/rubyJVM/src/org/json/me/JSONException.java +0 -27
- data/platform/shared/rubyJVM/src/org/json/me/JSONObject.java +0 -1290
- data/platform/shared/rubyJVM/src/org/json/me/JSONString.java +0 -18
- data/platform/shared/rubyJVM/src/org/json/me/JSONTokener.java +0 -460
- data/platform/shared/rubyext/RhoRuby.cpp +0 -31
- data/platform/shared/rubyext/RhoRuby.h +0 -32
- data/platform/wm/rhodes/rho/common/SystemInfoImpl.h +0 -21
- data/res/generators/templates/spec/app/fileutils.rb +0 -1592
- data/res/generators/templates/spec/app/mspec/guards/endian.rb +0 -44
- data/spec/framework_spec/app/Account/account.rb +0 -7
- data/spec/framework_spec/app/BulkTest/bulk_test.rb +0 -9
- data/spec/framework_spec/app/Customer/customer.rb +0 -6
- data/spec/framework_spec/app/Product/controller.rb +0 -62
- data/spec/framework_spec/app/Product/product.rb +0 -9
- data/spec/framework_spec/app/fileutils.rb +0 -1592
- data/spec/framework_spec/app/mspec/expectations/expectations.rb +0 -17
- data/spec/framework_spec/app/mspec/expectations/should.rb +0 -25
- data/spec/framework_spec/app/mspec/expectations.rb +0 -2
- data/spec/framework_spec/app/mspec/fileutils.rb +0 -1589
- data/spec/framework_spec/app/mspec/guards/background.rb +0 -21
- data/spec/framework_spec/app/mspec/guards/bug.rb +0 -24
- data/spec/framework_spec/app/mspec/guards/compliance.rb +0 -37
- data/spec/framework_spec/app/mspec/guards/conflict.rb +0 -18
- data/spec/framework_spec/app/mspec/guards/extensions.rb +0 -20
- data/spec/framework_spec/app/mspec/guards/guard.rb +0 -165
- data/spec/framework_spec/app/mspec/guards/noncompliance.rb +0 -20
- data/spec/framework_spec/app/mspec/guards/platform.rb +0 -43
- data/spec/framework_spec/app/mspec/guards/quarantine.rb +0 -17
- data/spec/framework_spec/app/mspec/guards/runner.rb +0 -34
- data/spec/framework_spec/app/mspec/guards/superuser.rb +0 -17
- data/spec/framework_spec/app/mspec/guards/support.rb +0 -20
- data/spec/framework_spec/app/mspec/guards/tty.rb +0 -20
- data/spec/framework_spec/app/mspec/guards/version.rb +0 -38
- data/spec/framework_spec/app/mspec/guards.rb +0 -16
- data/spec/framework_spec/app/mspec/helpers/argv.rb +0 -43
- data/spec/framework_spec/app/mspec/helpers/bignum.rb +0 -5
- data/spec/framework_spec/app/mspec/helpers/const_lookup.rb +0 -9
- data/spec/framework_spec/app/mspec/helpers/ducktype.rb +0 -33
- data/spec/framework_spec/app/mspec/helpers/enumerator_class.rb +0 -9
- data/spec/framework_spec/app/mspec/helpers/environment.rb +0 -32
- data/spec/framework_spec/app/mspec/helpers/fixture.rb +0 -20
- data/spec/framework_spec/app/mspec/helpers/flunk.rb +0 -5
- data/spec/framework_spec/app/mspec/helpers/fs.rb +0 -58
- data/spec/framework_spec/app/mspec/helpers/hash.rb +0 -27
- data/spec/framework_spec/app/mspec/helpers/infinity.rb +0 -5
- data/spec/framework_spec/app/mspec/helpers/io.rb +0 -17
- data/spec/framework_spec/app/mspec/helpers/language_version.rb +0 -20
- data/spec/framework_spec/app/mspec/helpers/metaclass.rb +0 -7
- data/spec/framework_spec/app/mspec/helpers/mock_to_path.rb +0 -7
- data/spec/framework_spec/app/mspec/helpers/nan.rb +0 -5
- data/spec/framework_spec/app/mspec/helpers/ruby_exe.rb +0 -123
- data/spec/framework_spec/app/mspec/helpers/scratch.rb +0 -17
- data/spec/framework_spec/app/mspec/helpers/tmp.rb +0 -32
- data/spec/framework_spec/app/mspec/helpers.rb +0 -19
- data/spec/framework_spec/app/mspec/matchers/base.rb +0 -95
- data/spec/framework_spec/app/mspec/matchers/be_an_instance_of.rb +0 -26
- data/spec/framework_spec/app/mspec/matchers/be_ancestor_of.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/be_close.rb +0 -27
- data/spec/framework_spec/app/mspec/matchers/be_empty.rb +0 -20
- data/spec/framework_spec/app/mspec/matchers/be_false.rb +0 -20
- data/spec/framework_spec/app/mspec/matchers/be_kind_of.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/be_nil.rb +0 -20
- data/spec/framework_spec/app/mspec/matchers/be_true.rb +0 -20
- data/spec/framework_spec/app/mspec/matchers/complain.rb +0 -56
- data/spec/framework_spec/app/mspec/matchers/eql.rb +0 -26
- data/spec/framework_spec/app/mspec/matchers/equal.rb +0 -26
- data/spec/framework_spec/app/mspec/matchers/equal_element.rb +0 -78
- data/spec/framework_spec/app/mspec/matchers/equal_utf16.rb +0 -34
- data/spec/framework_spec/app/mspec/matchers/have_constant.rb +0 -30
- data/spec/framework_spec/app/mspec/matchers/have_instance_method.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/have_method.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/have_private_instance_method.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/have_public_instance_method.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/include.rb +0 -32
- data/spec/framework_spec/app/mspec/matchers/match_yaml.rb +0 -47
- data/spec/framework_spec/app/mspec/matchers/method.rb +0 -14
- data/spec/framework_spec/app/mspec/matchers/output.rb +0 -67
- data/spec/framework_spec/app/mspec/matchers/output_to_fd.rb +0 -71
- data/spec/framework_spec/app/mspec/matchers/raise_error.rb +0 -49
- data/spec/framework_spec/app/mspec/matchers/respond_to.rb +0 -24
- data/spec/framework_spec/app/mspec/matchers/stringsymboladapter.rb +0 -8
- data/spec/framework_spec/app/mspec/matchers.rb +0 -25
- data/spec/framework_spec/app/mspec/mocks/mock.rb +0 -159
- data/spec/framework_spec/app/mspec/mocks/object.rb +0 -24
- data/spec/framework_spec/app/mspec/mocks/proxy.rb +0 -151
- data/spec/framework_spec/app/mspec/mocks.rb +0 -3
- data/spec/framework_spec/app/mspec/pp.rb +0 -893
- data/spec/framework_spec/app/mspec/runner/actions/debug.rb +0 -17
- data/spec/framework_spec/app/mspec/runner/actions/filter.rb +0 -40
- data/spec/framework_spec/app/mspec/runner/actions/gdb.rb +0 -17
- data/spec/framework_spec/app/mspec/runner/actions/tag.rb +0 -133
- data/spec/framework_spec/app/mspec/runner/actions/taglist.rb +0 -56
- data/spec/framework_spec/app/mspec/runner/actions/tagpurge.rb +0 -56
- data/spec/framework_spec/app/mspec/runner/actions/tally.rb +0 -116
- data/spec/framework_spec/app/mspec/runner/actions/timer.rb +0 -22
- data/spec/framework_spec/app/mspec/runner/actions.rb +0 -8
- data/spec/framework_spec/app/mspec/runner/context.rb +0 -188
- data/spec/framework_spec/app/mspec/runner/example.rb +0 -34
- data/spec/framework_spec/app/mspec/runner/exception.rb +0 -43
- data/spec/framework_spec/app/mspec/runner/filters/match.rb +0 -22
- data/spec/framework_spec/app/mspec/runner/filters/profile.rb +0 -54
- data/spec/framework_spec/app/mspec/runner/filters/regexp.rb +0 -7
- data/spec/framework_spec/app/mspec/runner/filters/tag.rb +0 -29
- data/spec/framework_spec/app/mspec/runner/filters.rb +0 -4
- data/spec/framework_spec/app/mspec/runner/formatters/describe.rb +0 -24
- data/spec/framework_spec/app/mspec/runner/formatters/dotted.rb +0 -98
- data/spec/framework_spec/app/mspec/runner/formatters/file.rb +0 -19
- data/spec/framework_spec/app/mspec/runner/formatters/html.rb +0 -81
- data/spec/framework_spec/app/mspec/runner/formatters/method.rb +0 -93
- data/spec/framework_spec/app/mspec/runner/formatters/specdoc.rb +0 -41
- data/spec/framework_spec/app/mspec/runner/formatters/spinner.rb +0 -99
- data/spec/framework_spec/app/mspec/runner/formatters/summary.rb +0 -11
- data/spec/framework_spec/app/mspec/runner/formatters/unit.rb +0 -21
- data/spec/framework_spec/app/mspec/runner/formatters/yaml.rb +0 -44
- data/spec/framework_spec/app/mspec/runner/formatters.rb +0 -10
- data/spec/framework_spec/app/mspec/runner/mspec.rb +0 -361
- data/spec/framework_spec/app/mspec/runner/object.rb +0 -24
- data/spec/framework_spec/app/mspec/runner/shared.rb +0 -12
- data/spec/framework_spec/app/mspec/runner/tag.rb +0 -32
- data/spec/framework_spec/app/mspec/runner.rb +0 -15
- data/spec/framework_spec/app/mspec/utils/name_map.rb +0 -129
- data/spec/framework_spec/app/mspec/utils/options.rb +0 -441
- data/spec/framework_spec/app/mspec/utils/ruby_name.rb +0 -8
- data/spec/framework_spec/app/mspec/utils/script.rb +0 -220
- data/spec/framework_spec/app/mspec/utils/version.rb +0 -53
- data/spec/framework_spec/app/mspec/version.rb +0 -5
- data/spec/framework_spec/app/spec/blobsync_spec.rb +0 -155
- data/spec/framework_spec/app/spec/bulksync_spec.rb +0 -65
- data/spec/framework_spec/app/spec/fixtures/object_values.txt +0 -90
- data/spec/framework_spec/app/spec/pagination/fixtures/object_values.txt +0 -91
- data/spec/framework_spec/app/spec/rho_controller_spec.rb +0 -143
- data/spec/framework_spec/app/spec/rho_spec.rb +0 -69
- data/spec/framework_spec/app/spec/rhoerror_spec.rb +0 -40
- data/spec/framework_spec/app/spec/rhom_db_adapter_spec.rb +0 -27
- data/spec/framework_spec/app/spec/rhom_object_spec.rb +0 -660
- data/spec/framework_spec/app/spec/rhom_spec.rb +0 -60
- data/spec/framework_spec/app/spec/rhoruby_spec.rb +0 -31
- data/spec/framework_spec/app/spec/syncengine_spec.rb +0 -190
- data/spec/phone_spec/app/Spec/controller.rb +0 -69
- data/spec/phone_spec/app/Spec/index.erb +0 -17
- data/spec/phone_spec/app/Spec/spec_runner.rb +0 -22
@@ -0,0 +1,3957 @@
|
|
1
|
+
/*Copyright (C) 2008-2009 Timothy B. Terriberry (tterribe@xiph.org)
|
2
|
+
You can redistribute this library and/or modify it under the terms of the
|
3
|
+
GNU Lesser General Public License as published by the Free Software
|
4
|
+
Foundation; either version 2.1 of the License, or (at your option) any later
|
5
|
+
version.*/
|
6
|
+
#include <config.h>
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <limits.h>
|
9
|
+
#include <string.h>
|
10
|
+
#include <time.h>
|
11
|
+
#include "qrcode.h"
|
12
|
+
#include "qrdec.h"
|
13
|
+
#include "bch15_5.h"
|
14
|
+
#include "rs.h"
|
15
|
+
#include "isaac.h"
|
16
|
+
#include "util.h"
|
17
|
+
#include "binarize.h"
|
18
|
+
#include "image.h"
|
19
|
+
#include "error.h"
|
20
|
+
#include "svg.h"
|
21
|
+
|
22
|
+
typedef int qr_line[3];
|
23
|
+
|
24
|
+
typedef struct qr_finder_cluster qr_finder_cluster;
|
25
|
+
typedef struct qr_finder_edge_pt qr_finder_edge_pt;
|
26
|
+
typedef struct qr_finder_center qr_finder_center;
|
27
|
+
|
28
|
+
typedef struct qr_aff qr_aff;
|
29
|
+
typedef struct qr_hom qr_hom;
|
30
|
+
|
31
|
+
typedef struct qr_finder qr_finder;
|
32
|
+
|
33
|
+
typedef struct qr_hom_cell qr_hom_cell;
|
34
|
+
typedef struct qr_sampling_grid qr_sampling_grid;
|
35
|
+
typedef struct qr_pack_buf qr_pack_buf;
|
36
|
+
|
37
|
+
/*The number of bits in an int.
|
38
|
+
Note the cast to (int): this prevents this value from "promoting" whole
|
39
|
+
expressions to an (unsigned) size_t.*/
|
40
|
+
#define QR_INT_BITS ((int)sizeof(int)*CHAR_BIT)
|
41
|
+
#define QR_INT_LOGBITS (QR_ILOG(QR_INT_BITS))
|
42
|
+
|
43
|
+
/*A 14 bit resolution for a homography ensures that the ideal module size for a
|
44
|
+
version 40 code differs from that of a version 39 code by at least 2.*/
|
45
|
+
#define QR_HOM_BITS (14)
|
46
|
+
|
47
|
+
/*The number of bits of sub-module precision to use when searching for
|
48
|
+
alignment patterns.
|
49
|
+
Two bits allows an alignment pattern to be found even if the modules have
|
50
|
+
been eroded by up to 50% (due to blurring, etc.).
|
51
|
+
This must be at least one, since it affects the dynamic range of the
|
52
|
+
transforms, and we sample at half-module resolution to compute a bounding
|
53
|
+
quadrilateral for the code.*/
|
54
|
+
#define QR_ALIGN_SUBPREC (2)
|
55
|
+
|
56
|
+
|
57
|
+
/* collection of finder lines */
|
58
|
+
typedef struct qr_finder_lines {
|
59
|
+
qr_finder_line *lines;
|
60
|
+
int nlines, clines;
|
61
|
+
} qr_finder_lines;
|
62
|
+
|
63
|
+
|
64
|
+
struct qr_reader {
|
65
|
+
/*The GF(256) representation used in Reed-Solomon decoding.*/
|
66
|
+
rs_gf256 gf;
|
67
|
+
/*The random number generator used by RANSAC.*/
|
68
|
+
isaac_ctx isaac;
|
69
|
+
/* current finder state, horizontal and vertical lines */
|
70
|
+
qr_finder_lines finder_lines[2];
|
71
|
+
};
|
72
|
+
|
73
|
+
|
74
|
+
/*Initializes a client reader handle.*/
|
75
|
+
static void qr_reader_init (qr_reader *reader)
|
76
|
+
{
|
77
|
+
/*time_t now;
|
78
|
+
now=time(NULL);
|
79
|
+
isaac_init(&_reader->isaac,&now,sizeof(now));*/
|
80
|
+
isaac_init(&reader->isaac, NULL, 0);
|
81
|
+
rs_gf256_init(&reader->gf, QR_PPOLY);
|
82
|
+
}
|
83
|
+
|
84
|
+
/*Allocates a client reader handle.*/
|
85
|
+
qr_reader *_zbar_qr_create (void)
|
86
|
+
{
|
87
|
+
qr_reader *reader = (qr_reader*)calloc(1, sizeof(*reader));
|
88
|
+
qr_reader_init(reader);
|
89
|
+
return(reader);
|
90
|
+
}
|
91
|
+
|
92
|
+
/*Frees a client reader handle.*/
|
93
|
+
void _zbar_qr_destroy (qr_reader *reader)
|
94
|
+
{
|
95
|
+
zprintf(1, "max finder lines = %dx%d\n",
|
96
|
+
reader->finder_lines[0].clines,
|
97
|
+
reader->finder_lines[1].clines);
|
98
|
+
if(reader->finder_lines[0].lines)
|
99
|
+
free(reader->finder_lines[0].lines);
|
100
|
+
if(reader->finder_lines[1].lines)
|
101
|
+
free(reader->finder_lines[1].lines);
|
102
|
+
free(reader);
|
103
|
+
}
|
104
|
+
|
105
|
+
/* reset finder state between scans */
|
106
|
+
void _zbar_qr_reset (qr_reader *reader)
|
107
|
+
{
|
108
|
+
reader->finder_lines[0].nlines = 0;
|
109
|
+
reader->finder_lines[1].nlines = 0;
|
110
|
+
}
|
111
|
+
|
112
|
+
|
113
|
+
/*A cluster of lines crossing a finder pattern (all in the same direction).*/
|
114
|
+
struct qr_finder_cluster{
|
115
|
+
/*Pointers to the lines crossing the pattern.*/
|
116
|
+
qr_finder_line **lines;
|
117
|
+
/*The number of lines in the cluster.*/
|
118
|
+
int nlines;
|
119
|
+
};
|
120
|
+
|
121
|
+
|
122
|
+
/*A point on the edge of a finder pattern.
|
123
|
+
These are obtained from the endpoints of the lines crossing this particular
|
124
|
+
pattern.*/
|
125
|
+
struct qr_finder_edge_pt{
|
126
|
+
/*The location of the edge point.*/
|
127
|
+
qr_point pos;
|
128
|
+
/*A label classifying which edge this belongs to:
|
129
|
+
0: negative u edge (left)
|
130
|
+
1: positive u edge (right)
|
131
|
+
2: negative v edge (top)
|
132
|
+
3: positive v edge (bottom)*/
|
133
|
+
int edge;
|
134
|
+
/*The (signed) perpendicular distance of the edge point from a line parallel
|
135
|
+
to the edge passing through the finder center, in (u,v) coordinates.
|
136
|
+
This is also re-used by RANSAC to store inlier flags.*/
|
137
|
+
int extent;
|
138
|
+
};
|
139
|
+
|
140
|
+
|
141
|
+
/*The center of a finder pattern obtained from the crossing of one or more
|
142
|
+
clusters of horizontal finder lines with one or more clusters of vertical
|
143
|
+
finder lines.*/
|
144
|
+
struct qr_finder_center{
|
145
|
+
/*The estimated location of the finder center.*/
|
146
|
+
qr_point pos;
|
147
|
+
/*The list of edge points from the crossing lines.*/
|
148
|
+
qr_finder_edge_pt *edge_pts;
|
149
|
+
/*The number of edge points from the crossing lines.*/
|
150
|
+
int nedge_pts;
|
151
|
+
};
|
152
|
+
|
153
|
+
|
154
|
+
static int qr_finder_vline_cmp(const void *_a,const void *_b){
|
155
|
+
const qr_finder_line *a;
|
156
|
+
const qr_finder_line *b;
|
157
|
+
a=(const qr_finder_line *)_a;
|
158
|
+
b=(const qr_finder_line *)_b;
|
159
|
+
return ((a->pos[0]>b->pos[0])-(a->pos[0]<b->pos[0])<<1)+
|
160
|
+
(a->pos[1]>b->pos[1])-(a->pos[1]<b->pos[1]);
|
161
|
+
}
|
162
|
+
|
163
|
+
/*Clusters adjacent lines into groups that are large enough to be crossing a
|
164
|
+
finder pattern (relative to their length).
|
165
|
+
_clusters: The buffer in which to store the clusters found.
|
166
|
+
_neighbors: The buffer used to store the lists of lines in each cluster.
|
167
|
+
_lines: The list of lines to cluster.
|
168
|
+
Horizontal lines must be sorted in ascending order by Y
|
169
|
+
coordinate, with ties broken by X coordinate.
|
170
|
+
Vertical lines must be sorted in ascending order by X coordinate,
|
171
|
+
with ties broken by Y coordinate.
|
172
|
+
_nlines: The number of lines in the set of lines to cluster.
|
173
|
+
_v: 0 for horizontal lines, or 1 for vertical lines.
|
174
|
+
Return: The number of clusters.*/
|
175
|
+
static int qr_finder_cluster_lines(qr_finder_cluster *_clusters,
|
176
|
+
qr_finder_line **_neighbors,qr_finder_line *_lines,int _nlines,int _v){
|
177
|
+
unsigned char *mark;
|
178
|
+
qr_finder_line **neighbors;
|
179
|
+
int nneighbors;
|
180
|
+
int nclusters;
|
181
|
+
int i;
|
182
|
+
/*TODO: Kalman filters!*/
|
183
|
+
mark=(unsigned char *)calloc(_nlines,sizeof(*mark));
|
184
|
+
neighbors=_neighbors;
|
185
|
+
nclusters=0;
|
186
|
+
for(i=0;i<_nlines-1;i++)if(!mark[i]){
|
187
|
+
int len;
|
188
|
+
int j;
|
189
|
+
nneighbors=1;
|
190
|
+
neighbors[0]=_lines+i;
|
191
|
+
len=_lines[i].len;
|
192
|
+
for(j=i+1;j<_nlines;j++)if(!mark[j]){
|
193
|
+
const qr_finder_line *a;
|
194
|
+
const qr_finder_line *b;
|
195
|
+
int thresh;
|
196
|
+
a=neighbors[nneighbors-1];
|
197
|
+
b=_lines+j;
|
198
|
+
/*The clustering threshold is proportional to the size of the lines,
|
199
|
+
since minor noise in large areas can interrupt patterns more easily
|
200
|
+
at high resolutions.*/
|
201
|
+
thresh=a->len+7>>2;
|
202
|
+
if(abs(a->pos[1-_v]-b->pos[1-_v])>thresh)break;
|
203
|
+
if(abs(a->pos[_v]-b->pos[_v])>thresh)continue;
|
204
|
+
if(abs(a->pos[_v]+a->len-b->pos[_v]-b->len)>thresh)continue;
|
205
|
+
if(a->boffs>0&&b->boffs>0&&
|
206
|
+
abs(a->pos[_v]-a->boffs-b->pos[_v]+b->boffs)>thresh){
|
207
|
+
continue;
|
208
|
+
}
|
209
|
+
if(a->eoffs>0&&b->eoffs>0&&
|
210
|
+
abs(a->pos[_v]+a->len+a->eoffs-b->pos[_v]-b->len-b->eoffs)>thresh){
|
211
|
+
continue;
|
212
|
+
}
|
213
|
+
neighbors[nneighbors++]=_lines+j;
|
214
|
+
len+=b->len;
|
215
|
+
}
|
216
|
+
/*We require at least three lines to form a cluster, which eliminates a
|
217
|
+
large number of false positives, saving considerable decoding time.
|
218
|
+
This should still be sufficient for 1-pixel codes with no noise.*/
|
219
|
+
if(nneighbors<3)continue;
|
220
|
+
/*The expected number of lines crossing a finder pattern is equal to their
|
221
|
+
average length.
|
222
|
+
We accept the cluster if size is at least 1/3 their average length (this
|
223
|
+
is a very small threshold, but was needed for some test images).*/
|
224
|
+
len=((len<<1)+nneighbors)/(nneighbors<<1);
|
225
|
+
if(nneighbors*(5<<QR_FINDER_SUBPREC)>=len){
|
226
|
+
_clusters[nclusters].lines=neighbors;
|
227
|
+
_clusters[nclusters].nlines=nneighbors;
|
228
|
+
for(j=0;j<nneighbors;j++)mark[neighbors[j]-_lines]=1;
|
229
|
+
neighbors+=nneighbors;
|
230
|
+
nclusters++;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
free(mark);
|
234
|
+
return nclusters;
|
235
|
+
}
|
236
|
+
|
237
|
+
/*Adds the coordinates of the edge points from the lines contained in the
|
238
|
+
given list of clusters to the list of edge points for a finder center.
|
239
|
+
Only the edge point position is initialized.
|
240
|
+
The edge label and extent are set by qr_finder_edge_pts_aff_classify()
|
241
|
+
or qr_finder_edge_pts_hom_classify().
|
242
|
+
_edge_pts: The buffer in which to store the edge points.
|
243
|
+
_nedge_pts: The current number of edge points in the buffer.
|
244
|
+
_neighbors: The list of lines in the cluster.
|
245
|
+
_nneighbors: The number of lines in the list of lines in the cluster.
|
246
|
+
_v: 0 for horizontal lines and 1 for vertical lines.
|
247
|
+
Return: The new total number of edge points.*/
|
248
|
+
static int qr_finder_edge_pts_fill(qr_finder_edge_pt *_edge_pts,int _nedge_pts,
|
249
|
+
qr_finder_cluster **_neighbors,int _nneighbors,int _v){
|
250
|
+
int i;
|
251
|
+
for(i=0;i<_nneighbors;i++){
|
252
|
+
qr_finder_cluster *c;
|
253
|
+
int j;
|
254
|
+
c=_neighbors[i];
|
255
|
+
for(j=0;j<c->nlines;j++){
|
256
|
+
qr_finder_line *l;
|
257
|
+
l=c->lines[j];
|
258
|
+
if(l->boffs>0){
|
259
|
+
_edge_pts[_nedge_pts].pos[0]=l->pos[0];
|
260
|
+
_edge_pts[_nedge_pts].pos[1]=l->pos[1];
|
261
|
+
_edge_pts[_nedge_pts].pos[_v]-=l->boffs;
|
262
|
+
_nedge_pts++;
|
263
|
+
}
|
264
|
+
if(l->eoffs>0){
|
265
|
+
_edge_pts[_nedge_pts].pos[0]=l->pos[0];
|
266
|
+
_edge_pts[_nedge_pts].pos[1]=l->pos[1];
|
267
|
+
_edge_pts[_nedge_pts].pos[_v]+=l->len+l->eoffs;
|
268
|
+
_nedge_pts++;
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
272
|
+
return _nedge_pts;
|
273
|
+
}
|
274
|
+
|
275
|
+
static int qr_finder_center_cmp(const void *_a,const void *_b){
|
276
|
+
const qr_finder_center *a;
|
277
|
+
const qr_finder_center *b;
|
278
|
+
a=(const qr_finder_center *)_a;
|
279
|
+
b=(const qr_finder_center *)_b;
|
280
|
+
return ((b->nedge_pts>a->nedge_pts)-(b->nedge_pts<a->nedge_pts)<<2)+
|
281
|
+
((a->pos[1]>b->pos[1])-(a->pos[1]<b->pos[1])<<1)+
|
282
|
+
(a->pos[0]>b->pos[0])-(a->pos[0]<b->pos[0]);
|
283
|
+
}
|
284
|
+
|
285
|
+
/*Determine if a horizontal line crosses a vertical line.
|
286
|
+
_hline: The horizontal line.
|
287
|
+
_vline: The vertical line.
|
288
|
+
Return: A non-zero value if the lines cross, or zero if they do not.*/
|
289
|
+
static int qr_finder_lines_are_crossing(const qr_finder_line *_hline,
|
290
|
+
const qr_finder_line *_vline){
|
291
|
+
return
|
292
|
+
_hline->pos[0]<=_vline->pos[0]&&_vline->pos[0]<_hline->pos[0]+_hline->len&&
|
293
|
+
_vline->pos[1]<=_hline->pos[1]&&_hline->pos[1]<_vline->pos[1]+_vline->len;
|
294
|
+
}
|
295
|
+
|
296
|
+
/*Finds horizontal clusters that cross corresponding vertical clusters,
|
297
|
+
presumably corresponding to a finder center.
|
298
|
+
_center: The buffer in which to store putative finder centers.
|
299
|
+
_edge_pts: The buffer to use for the edge point lists for each finder
|
300
|
+
center.
|
301
|
+
_hclusters: The clusters of horizontal lines crossing finder patterns.
|
302
|
+
_nhclusters: The number of horizontal line clusters.
|
303
|
+
_vclusters: The clusters of vertical lines crossing finder patterns.
|
304
|
+
_nvclusters: The number of vertical line clusters.
|
305
|
+
Return: The number of putative finder centers.*/
|
306
|
+
static int qr_finder_find_crossings(qr_finder_center *_centers,
|
307
|
+
qr_finder_edge_pt *_edge_pts,qr_finder_cluster *_hclusters,int _nhclusters,
|
308
|
+
qr_finder_cluster *_vclusters,int _nvclusters){
|
309
|
+
qr_finder_cluster **hneighbors;
|
310
|
+
qr_finder_cluster **vneighbors;
|
311
|
+
unsigned char *hmark;
|
312
|
+
unsigned char *vmark;
|
313
|
+
int ncenters;
|
314
|
+
int i;
|
315
|
+
int j;
|
316
|
+
hneighbors=(qr_finder_cluster **)malloc(_nhclusters*sizeof(*hneighbors));
|
317
|
+
vneighbors=(qr_finder_cluster **)malloc(_nvclusters*sizeof(*vneighbors));
|
318
|
+
hmark=(unsigned char *)calloc(_nhclusters,sizeof(*hmark));
|
319
|
+
vmark=(unsigned char *)calloc(_nvclusters,sizeof(*vmark));
|
320
|
+
ncenters=0;
|
321
|
+
/*TODO: This may need some re-working.
|
322
|
+
We should be finding groups of clusters such that _all_ horizontal lines in
|
323
|
+
_all_ horizontal clusters in the group cross _all_ vertical lines in _all_
|
324
|
+
vertical clusters in the group.
|
325
|
+
This is equivalent to finding the maximum bipartite clique in the
|
326
|
+
connectivity graph, which requires linear progamming to solve efficiently.
|
327
|
+
In principle, that is easy to do, but a realistic implementation without
|
328
|
+
floating point is a lot of work (and computationally expensive).
|
329
|
+
Right now we are relying on a sufficient border around the finder patterns
|
330
|
+
to prevent false positives.*/
|
331
|
+
for(i=0;i<_nhclusters;i++)if(!hmark[i]){
|
332
|
+
qr_finder_line *a;
|
333
|
+
qr_finder_line *b;
|
334
|
+
int nvneighbors;
|
335
|
+
int nedge_pts;
|
336
|
+
int y;
|
337
|
+
a=_hclusters[i].lines[_hclusters[i].nlines>>1];
|
338
|
+
y=nvneighbors=0;
|
339
|
+
for(j=0;j<_nvclusters;j++)if(!vmark[j]){
|
340
|
+
b=_vclusters[j].lines[_vclusters[j].nlines>>1];
|
341
|
+
if(qr_finder_lines_are_crossing(a,b)){
|
342
|
+
vmark[j]=1;
|
343
|
+
y+=(b->pos[1]<<1)+b->len;
|
344
|
+
if(b->boffs>0&&b->eoffs>0)y+=b->eoffs-b->boffs;
|
345
|
+
vneighbors[nvneighbors++]=_vclusters+j;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
if(nvneighbors>0){
|
349
|
+
qr_finder_center *c;
|
350
|
+
int nhneighbors;
|
351
|
+
int x;
|
352
|
+
x=(a->pos[0]<<1)+a->len;
|
353
|
+
if(a->boffs>0&&a->eoffs>0)x+=a->eoffs-a->boffs;
|
354
|
+
hneighbors[0]=_hclusters+i;
|
355
|
+
nhneighbors=1;
|
356
|
+
j=nvneighbors>>1;
|
357
|
+
b=vneighbors[j]->lines[vneighbors[j]->nlines>>1];
|
358
|
+
for(j=i+1;j<_nhclusters;j++)if(!hmark[j]){
|
359
|
+
a=_hclusters[j].lines[_hclusters[j].nlines>>1];
|
360
|
+
if(qr_finder_lines_are_crossing(a,b)){
|
361
|
+
hmark[j]=1;
|
362
|
+
x+=(a->pos[0]<<1)+a->len;
|
363
|
+
if(a->boffs>0&&a->eoffs>0)x+=a->eoffs-a->boffs;
|
364
|
+
hneighbors[nhneighbors++]=_hclusters+j;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
c=_centers+ncenters++;
|
368
|
+
c->pos[0]=(x+nhneighbors)/(nhneighbors<<1);
|
369
|
+
c->pos[1]=(y+nvneighbors)/(nvneighbors<<1);
|
370
|
+
c->edge_pts=_edge_pts;
|
371
|
+
nedge_pts=qr_finder_edge_pts_fill(_edge_pts,0,
|
372
|
+
hneighbors,nhneighbors,0);
|
373
|
+
nedge_pts=qr_finder_edge_pts_fill(_edge_pts,nedge_pts,
|
374
|
+
vneighbors,nvneighbors,1);
|
375
|
+
c->nedge_pts=nedge_pts;
|
376
|
+
_edge_pts+=nedge_pts;
|
377
|
+
}
|
378
|
+
}
|
379
|
+
free(vmark);
|
380
|
+
free(hmark);
|
381
|
+
free(vneighbors);
|
382
|
+
free(hneighbors);
|
383
|
+
/*Sort the centers by decreasing numbers of edge points.*/
|
384
|
+
qsort(_centers,ncenters,sizeof(*_centers),qr_finder_center_cmp);
|
385
|
+
return ncenters;
|
386
|
+
}
|
387
|
+
|
388
|
+
/*Locates a set of putative finder centers in the image.
|
389
|
+
First we search for horizontal and vertical lines that have
|
390
|
+
(dark:light:dark:light:dark) runs with size ratios of roughly (1:1:3:1:1).
|
391
|
+
Then we cluster them into groups such that each subsequent pair of endpoints
|
392
|
+
is close to the line before it in the cluster.
|
393
|
+
This will locate many line clusters that don't cross a finder pattern, but
|
394
|
+
qr_finder_find_crossings() will filter most of them out.
|
395
|
+
Where horizontal and vertical clusters cross, a prospective finder center is
|
396
|
+
returned.
|
397
|
+
_centers: Returns a pointer to a freshly-allocated list of finder centers.
|
398
|
+
This must be freed by the caller.
|
399
|
+
_edge_pts: Returns a pointer to a freshly-allocated list of edge points
|
400
|
+
around those centers.
|
401
|
+
This must be freed by the caller.
|
402
|
+
_img: The binary image to search.
|
403
|
+
_width: The width of the image.
|
404
|
+
_height: The height of the image.
|
405
|
+
Return: The number of putative finder centers located.*/
|
406
|
+
static int qr_finder_centers_locate(qr_finder_center **_centers,
|
407
|
+
qr_finder_edge_pt **_edge_pts, qr_reader *reader,
|
408
|
+
int _width,int _height){
|
409
|
+
qr_finder_line *hlines = reader->finder_lines[0].lines;
|
410
|
+
int nhlines = reader->finder_lines[0].nlines;
|
411
|
+
qr_finder_line *vlines = reader->finder_lines[1].lines;
|
412
|
+
int nvlines = reader->finder_lines[1].nlines;
|
413
|
+
|
414
|
+
qr_finder_line **hneighbors;
|
415
|
+
qr_finder_cluster *hclusters;
|
416
|
+
int nhclusters;
|
417
|
+
qr_finder_line **vneighbors;
|
418
|
+
qr_finder_cluster *vclusters;
|
419
|
+
int nvclusters;
|
420
|
+
int ncenters;
|
421
|
+
|
422
|
+
/*Cluster the detected lines.*/
|
423
|
+
hneighbors=(qr_finder_line **)malloc(nhlines*sizeof(*hneighbors));
|
424
|
+
/*We require more than one line per cluster, so there are at most nhlines/2.*/
|
425
|
+
hclusters=(qr_finder_cluster *)malloc((nhlines>>1)*sizeof(*hclusters));
|
426
|
+
nhclusters=qr_finder_cluster_lines(hclusters,hneighbors,hlines,nhlines,0);
|
427
|
+
/*We need vertical lines to be sorted by X coordinate, with ties broken by Y
|
428
|
+
coordinate, for clustering purposes.
|
429
|
+
We scan the image in the opposite order for cache efficiency, so sort the
|
430
|
+
lines we found here.*/
|
431
|
+
qsort(vlines,nvlines,sizeof(*vlines),qr_finder_vline_cmp);
|
432
|
+
vneighbors=(qr_finder_line **)malloc(nvlines*sizeof(*vneighbors));
|
433
|
+
/*We require more than one line per cluster, so there are at most nvlines/2.*/
|
434
|
+
vclusters=(qr_finder_cluster *)malloc((nvlines>>1)*sizeof(*vclusters));
|
435
|
+
nvclusters=qr_finder_cluster_lines(vclusters,vneighbors,vlines,nvlines,1);
|
436
|
+
/*Find line crossings among the clusters.*/
|
437
|
+
if(nhclusters>=3&&nvclusters>=3){
|
438
|
+
qr_finder_edge_pt *edge_pts;
|
439
|
+
qr_finder_center *centers;
|
440
|
+
int nedge_pts;
|
441
|
+
int i;
|
442
|
+
nedge_pts=0;
|
443
|
+
for(i=0;i<nhclusters;i++)nedge_pts+=hclusters[i].nlines;
|
444
|
+
for(i=0;i<nvclusters;i++)nedge_pts+=vclusters[i].nlines;
|
445
|
+
nedge_pts<<=1;
|
446
|
+
edge_pts=(qr_finder_edge_pt *)malloc(nedge_pts*sizeof(*edge_pts));
|
447
|
+
centers=(qr_finder_center *)malloc(
|
448
|
+
QR_MINI(nhclusters,nvclusters)*sizeof(*centers));
|
449
|
+
ncenters=qr_finder_find_crossings(centers,edge_pts,
|
450
|
+
hclusters,nhclusters,vclusters,nvclusters);
|
451
|
+
*_centers=centers;
|
452
|
+
*_edge_pts=edge_pts;
|
453
|
+
}
|
454
|
+
else ncenters=0;
|
455
|
+
free(vclusters);
|
456
|
+
free(vneighbors);
|
457
|
+
free(hclusters);
|
458
|
+
free(hneighbors);
|
459
|
+
return ncenters;
|
460
|
+
}
|
461
|
+
|
462
|
+
|
463
|
+
|
464
|
+
static void qr_point_translate(qr_point _point,int _dx,int _dy){
|
465
|
+
_point[0]+=_dx;
|
466
|
+
_point[1]+=_dy;
|
467
|
+
}
|
468
|
+
|
469
|
+
static unsigned qr_point_distance2(const qr_point _p1,const qr_point _p2){
|
470
|
+
return (_p1[0]-_p2[0])*(_p1[0]-_p2[0])+(_p1[1]-_p2[1])*(_p1[1]-_p2[1]);
|
471
|
+
}
|
472
|
+
|
473
|
+
/*Returns the cross product of the three points, which is positive if they are
|
474
|
+
in CCW order (in a right-handed coordinate system), and 0 if they're
|
475
|
+
colinear.*/
|
476
|
+
static int qr_point_ccw(const qr_point _p0,
|
477
|
+
const qr_point _p1,const qr_point _p2){
|
478
|
+
return (_p1[0]-_p0[0])*(_p2[1]-_p0[1])-(_p1[1]-_p0[1])*(_p2[0]-_p0[0]);
|
479
|
+
}
|
480
|
+
|
481
|
+
|
482
|
+
|
483
|
+
/*Evaluates a line equation at a point.
|
484
|
+
_line: The line to evaluate.
|
485
|
+
_x: The X coordinate of the point.
|
486
|
+
_y: The y coordinate of the point.
|
487
|
+
Return: The value of the line equation _line[0]*_x+_line[1]*_y+_line[2].*/
|
488
|
+
static int qr_line_eval(qr_line _line,int _x,int _y){
|
489
|
+
return _line[0]*_x+_line[1]*_y+_line[2];
|
490
|
+
}
|
491
|
+
|
492
|
+
/*Computes a line passing through the given point using the specified second
|
493
|
+
order statistics.
|
494
|
+
Given a line defined by the equation
|
495
|
+
A*x+B*y+C = 0 ,
|
496
|
+
the least squares fit to n points (x_i,y_i) must satisfy the two equations
|
497
|
+
A^2 + (Syy - Sxx)/Sxy*A*B - B^2 = 0 ,
|
498
|
+
C = -(xbar*A+ybar*B) ,
|
499
|
+
where
|
500
|
+
xbar = sum(x_i)/n ,
|
501
|
+
ybar = sum(y_i)/n ,
|
502
|
+
Sxx = sum((x_i-xbar)**2) ,
|
503
|
+
Sxy = sum((x_i-xbar)*(y_i-ybar)) ,
|
504
|
+
Syy = sum((y_i-ybar)**2) .
|
505
|
+
The quadratic can be solved for the ratio (A/B) or (B/A):
|
506
|
+
A/B = (Syy + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Sxx)/(-2*Sxy) ,
|
507
|
+
B/A = (Sxx + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Syy)/(-2*Sxy) .
|
508
|
+
We pick the one that leads to the larger ratio to avoid destructive
|
509
|
+
cancellation (and e.g., 0/0 for horizontal or vertical lines).
|
510
|
+
The above solutions correspond to the actual minimum.
|
511
|
+
The other solution of the quadratic corresponds to a saddle point of the
|
512
|
+
least squares objective function.
|
513
|
+
_l: Returns the fitted line values A, B, and C.
|
514
|
+
_x0: The X coordinate of the point the line is supposed to pass through.
|
515
|
+
_y0: The Y coordinate of the point the line is supposed to pass through.
|
516
|
+
_sxx: The sum Sxx.
|
517
|
+
_sxy: The sum Sxy.
|
518
|
+
_syy: The sum Syy.
|
519
|
+
_res: The maximum number of bits occupied by the product of any two of
|
520
|
+
_l[0] or _l[1].
|
521
|
+
Smaller numbers give less angular resolution, but allow more overhead
|
522
|
+
room for computations.*/
|
523
|
+
static void qr_line_fit(qr_line _l,int _x0,int _y0,
|
524
|
+
int _sxx,int _sxy,int _syy,int _res){
|
525
|
+
int dshift;
|
526
|
+
int dround;
|
527
|
+
int u;
|
528
|
+
int v;
|
529
|
+
int w;
|
530
|
+
u=abs(_sxx-_syy);
|
531
|
+
v=-_sxy<<1;
|
532
|
+
w=qr_ihypot(u,v);
|
533
|
+
/*Computations in later stages can easily overflow with moderate sizes, so we
|
534
|
+
compute a shift factor to scale things down into a managable range.
|
535
|
+
We ensure that the product of any two of _l[0] and _l[1] fits within _res
|
536
|
+
bits, which allows computation of line intersections without overflow.*/
|
537
|
+
dshift=QR_MAXI(0,QR_MAXI(qr_ilog(u),qr_ilog(abs(v)))+1-(_res+1>>1));
|
538
|
+
dround=(1<<dshift)>>1;
|
539
|
+
if(_sxx>_syy){
|
540
|
+
_l[0]=v+dround>>dshift;
|
541
|
+
_l[1]=u+w+dround>>dshift;
|
542
|
+
}
|
543
|
+
else{
|
544
|
+
_l[0]=u+w+dround>>dshift;
|
545
|
+
_l[1]=v+dround>>dshift;
|
546
|
+
}
|
547
|
+
_l[2]=-(_x0*_l[0]+_y0*_l[1]);
|
548
|
+
}
|
549
|
+
|
550
|
+
/*Perform a least-squares line fit to a list of points.
|
551
|
+
At least two points are required.*/
|
552
|
+
static void qr_line_fit_points(qr_line _l,qr_point *_p,int _np,int _res){
|
553
|
+
int sx;
|
554
|
+
int sy;
|
555
|
+
int xmin;
|
556
|
+
int xmax;
|
557
|
+
int ymin;
|
558
|
+
int ymax;
|
559
|
+
int xbar;
|
560
|
+
int ybar;
|
561
|
+
int dx;
|
562
|
+
int dy;
|
563
|
+
int sxx;
|
564
|
+
int sxy;
|
565
|
+
int syy;
|
566
|
+
int sshift;
|
567
|
+
int sround;
|
568
|
+
int i;
|
569
|
+
sx=sy=0;
|
570
|
+
ymax=xmax=INT_MIN;
|
571
|
+
ymin=xmin=INT_MAX;
|
572
|
+
for(i=0;i<_np;i++){
|
573
|
+
sx+=_p[i][0];
|
574
|
+
xmin=QR_MINI(xmin,_p[i][0]);
|
575
|
+
xmax=QR_MAXI(xmax,_p[i][0]);
|
576
|
+
sy+=_p[i][1];
|
577
|
+
ymin=QR_MINI(ymin,_p[i][1]);
|
578
|
+
ymax=QR_MAXI(ymax,_p[i][1]);
|
579
|
+
}
|
580
|
+
xbar=(sx+(_np>>1))/_np;
|
581
|
+
ybar=(sy+(_np>>1))/_np;
|
582
|
+
sshift=QR_MAXI(0,qr_ilog(_np*QR_MAXI(QR_MAXI(xmax-xbar,xbar-xmin),
|
583
|
+
QR_MAXI(ymax-ybar,ybar-ymin)))-(QR_INT_BITS-1>>1));
|
584
|
+
sround=(1<<sshift)>>1;
|
585
|
+
sxx=sxy=syy=0;
|
586
|
+
for(i=0;i<_np;i++){
|
587
|
+
dx=_p[i][0]-xbar+sround>>sshift;
|
588
|
+
dy=_p[i][1]-ybar+sround>>sshift;
|
589
|
+
sxx+=dx*dx;
|
590
|
+
sxy+=dx*dy;
|
591
|
+
syy+=dy*dy;
|
592
|
+
}
|
593
|
+
qr_line_fit(_l,xbar,ybar,sxx,sxy,syy,_res);
|
594
|
+
}
|
595
|
+
|
596
|
+
static void qr_line_orient(qr_line _l,int _x,int _y){
|
597
|
+
if(qr_line_eval(_l,_x,_y)<0){
|
598
|
+
_l[0]=-_l[0];
|
599
|
+
_l[1]=-_l[1];
|
600
|
+
_l[2]=-_l[2];
|
601
|
+
}
|
602
|
+
}
|
603
|
+
|
604
|
+
static int qr_line_isect(qr_point _p,const qr_line _l0,const qr_line _l1){
|
605
|
+
int d;
|
606
|
+
int x;
|
607
|
+
int y;
|
608
|
+
d=_l0[0]*_l1[1]-_l0[1]*_l1[0];
|
609
|
+
if(d==0)return -1;
|
610
|
+
x=_l0[1]*_l1[2]-_l1[1]*_l0[2];
|
611
|
+
y=_l1[0]*_l0[2]-_l0[0]*_l1[2];
|
612
|
+
if(d<0){
|
613
|
+
x=-x;
|
614
|
+
y=-y;
|
615
|
+
d=-d;
|
616
|
+
}
|
617
|
+
_p[0]=QR_DIVROUND(x,d);
|
618
|
+
_p[1]=QR_DIVROUND(y,d);
|
619
|
+
return 0;
|
620
|
+
}
|
621
|
+
|
622
|
+
|
623
|
+
|
624
|
+
/*An affine homography.
|
625
|
+
This maps from the image (at subpel resolution) to a square domain with
|
626
|
+
power-of-two sides (of res bits) and back.*/
|
627
|
+
struct qr_aff{
|
628
|
+
int fwd[2][2];
|
629
|
+
int inv[2][2];
|
630
|
+
int x0;
|
631
|
+
int y0;
|
632
|
+
int res;
|
633
|
+
};
|
634
|
+
|
635
|
+
|
636
|
+
static void qr_aff_init(qr_aff *_aff,
|
637
|
+
const qr_point _p0,const qr_point _p1,const qr_point _p2,int _res){
|
638
|
+
int det;
|
639
|
+
int dx1;
|
640
|
+
int dy1;
|
641
|
+
int dx2;
|
642
|
+
int dy2;
|
643
|
+
/*det is ensured to be positive by our caller.*/
|
644
|
+
det=qr_point_ccw(_p0,_p1,_p2);
|
645
|
+
dx1=_p1[0]-_p0[0];
|
646
|
+
dx2=_p2[0]-_p0[0];
|
647
|
+
dy1=_p1[1]-_p0[1];
|
648
|
+
dy2=_p2[1]-_p0[1];
|
649
|
+
_aff->fwd[0][0]=dx1;
|
650
|
+
_aff->fwd[0][1]=dx2;
|
651
|
+
_aff->fwd[1][0]=dy1;
|
652
|
+
_aff->fwd[1][1]=dy2;
|
653
|
+
_aff->inv[0][0]=QR_DIVROUND(dy2<<_res,det);
|
654
|
+
_aff->inv[0][1]=QR_DIVROUND(-dx2<<_res,det);
|
655
|
+
_aff->inv[1][0]=QR_DIVROUND(-dy1<<_res,det);
|
656
|
+
_aff->inv[1][1]=QR_DIVROUND(dx1<<_res,det);
|
657
|
+
_aff->x0=_p0[0];
|
658
|
+
_aff->y0=_p0[1];
|
659
|
+
_aff->res=_res;
|
660
|
+
}
|
661
|
+
|
662
|
+
/*Map from the image (at subpel resolution) into the square domain.*/
|
663
|
+
static void qr_aff_unproject(qr_point _q,const qr_aff *_aff,
|
664
|
+
int _x,int _y){
|
665
|
+
_q[0]=_aff->inv[0][0]*(_x-_aff->x0)+_aff->inv[0][1]*(_y-_aff->y0);
|
666
|
+
_q[1]=_aff->inv[1][0]*(_x-_aff->x0)+_aff->inv[1][1]*(_y-_aff->y0);
|
667
|
+
}
|
668
|
+
|
669
|
+
/*Map from the square domain into the image (at subpel resolution).*/
|
670
|
+
static void qr_aff_project(qr_point _p,const qr_aff *_aff,
|
671
|
+
int _u,int _v){
|
672
|
+
_p[0]=(_aff->fwd[0][0]*_u+_aff->fwd[0][1]*_v+(1<<_aff->res-1)>>_aff->res)
|
673
|
+
+_aff->x0;
|
674
|
+
_p[1]=(_aff->fwd[1][0]*_u+_aff->fwd[1][1]*_v+(1<<_aff->res-1)>>_aff->res)
|
675
|
+
+_aff->y0;
|
676
|
+
}
|
677
|
+
|
678
|
+
|
679
|
+
|
680
|
+
/*A full homography.
|
681
|
+
Like the affine homography, this maps from the image (at subpel resolution)
|
682
|
+
to a square domain with power-of-two sides (of res bits) and back.*/
|
683
|
+
struct qr_hom{
|
684
|
+
int fwd[3][2];
|
685
|
+
int inv[3][2];
|
686
|
+
int fwd22;
|
687
|
+
int inv22;
|
688
|
+
int x0;
|
689
|
+
int y0;
|
690
|
+
int res;
|
691
|
+
};
|
692
|
+
|
693
|
+
|
694
|
+
static void qr_hom_init(qr_hom *_hom,int _x0,int _y0,
|
695
|
+
int _x1,int _y1,int _x2,int _y2,int _x3,int _y3,int _res){
|
696
|
+
int dx10;
|
697
|
+
int dx20;
|
698
|
+
int dx30;
|
699
|
+
int dx31;
|
700
|
+
int dx32;
|
701
|
+
int dy10;
|
702
|
+
int dy20;
|
703
|
+
int dy30;
|
704
|
+
int dy31;
|
705
|
+
int dy32;
|
706
|
+
int a20;
|
707
|
+
int a21;
|
708
|
+
int a22;
|
709
|
+
int b0;
|
710
|
+
int b1;
|
711
|
+
int b2;
|
712
|
+
int s1;
|
713
|
+
int s2;
|
714
|
+
int r1;
|
715
|
+
int r2;
|
716
|
+
dx10=_x1-_x0;
|
717
|
+
dx20=_x2-_x0;
|
718
|
+
dx30=_x3-_x0;
|
719
|
+
dx31=_x3-_x1;
|
720
|
+
dx32=_x3-_x2;
|
721
|
+
dy10=_y1-_y0;
|
722
|
+
dy20=_y2-_y0;
|
723
|
+
dy30=_y3-_y0;
|
724
|
+
dy31=_y3-_y1;
|
725
|
+
dy32=_y3-_y2;
|
726
|
+
a20=dx32*dy10-dx10*dy32;
|
727
|
+
a21=dx20*dy31-dx31*dy20;
|
728
|
+
a22=dx32*dy31-dx31*dy32;
|
729
|
+
/*Figure out if we need to downscale anything.*/
|
730
|
+
b0=qr_ilog(QR_MAXI(abs(dx10),abs(dy10)))+qr_ilog(abs(a20+a22));
|
731
|
+
b1=qr_ilog(QR_MAXI(abs(dx20),abs(dy20)))+qr_ilog(abs(a21+a22));
|
732
|
+
b2=qr_ilog(QR_MAXI(QR_MAXI(abs(a20),abs(a21)),abs(a22)));
|
733
|
+
s1=QR_MAXI(0,_res+QR_MAXI(QR_MAXI(b0,b1),b2)-(QR_INT_BITS-2));
|
734
|
+
r1=(1<<s1)>>1;
|
735
|
+
/*Compute the final coefficients of the forward transform.
|
736
|
+
The 32x32->64 bit multiplies are really needed for accuracy with large
|
737
|
+
versions.*/
|
738
|
+
_hom->fwd[0][0]=QR_FIXMUL(dx10,a20+a22,r1,s1);
|
739
|
+
_hom->fwd[0][1]=QR_FIXMUL(dx20,a21+a22,r1,s1);
|
740
|
+
_hom->x0=_x0;
|
741
|
+
_hom->fwd[1][0]=QR_FIXMUL(dy10,a20+a22,r1,s1);
|
742
|
+
_hom->fwd[1][1]=QR_FIXMUL(dy20,a21+a22,r1,s1);
|
743
|
+
_hom->y0=_y0;
|
744
|
+
_hom->fwd[2][0]=a20+r1>>s1;
|
745
|
+
_hom->fwd[2][1]=a21+r1>>s1;
|
746
|
+
_hom->fwd22=s1>_res?a22+(r1>>_res)>>s1-_res:a22<<_res-s1;
|
747
|
+
/*Now compute the inverse transform.*/
|
748
|
+
b0=qr_ilog(QR_MAXI(QR_MAXI(abs(dx10),abs(dx20)),abs(dx30)))+
|
749
|
+
qr_ilog(QR_MAXI(abs(_hom->fwd[0][0]),abs(_hom->fwd[1][0])));
|
750
|
+
b1=qr_ilog(QR_MAXI(QR_MAXI(abs(dy10),abs(dy20)),abs(dy30)))+
|
751
|
+
qr_ilog(QR_MAXI(abs(_hom->fwd[0][1]),abs(_hom->fwd[1][1])));
|
752
|
+
b2=qr_ilog(abs(a22))-s1;
|
753
|
+
s2=QR_MAXI(0,QR_MAXI(b0,b1)+b2-(QR_INT_BITS-3));
|
754
|
+
r2=(1<<s2)>>1;
|
755
|
+
s1+=s2;
|
756
|
+
r1<<=s2;
|
757
|
+
/*The 32x32->64 bit multiplies are really needed for accuracy with large
|
758
|
+
versions.*/
|
759
|
+
_hom->inv[0][0]=QR_FIXMUL(_hom->fwd[1][1],a22,r1,s1);
|
760
|
+
_hom->inv[0][1]=QR_FIXMUL(-_hom->fwd[0][1],a22,r1,s1);
|
761
|
+
_hom->inv[1][0]=QR_FIXMUL(-_hom->fwd[1][0],a22,r1,s1);
|
762
|
+
_hom->inv[1][1]=QR_FIXMUL(_hom->fwd[0][0],a22,r1,s1);
|
763
|
+
_hom->inv[2][0]=QR_FIXMUL(_hom->fwd[1][0],_hom->fwd[2][1],
|
764
|
+
-QR_EXTMUL(_hom->fwd[1][1],_hom->fwd[2][0],r2),s2);
|
765
|
+
_hom->inv[2][1]=QR_FIXMUL(_hom->fwd[0][1],_hom->fwd[2][0],
|
766
|
+
-QR_EXTMUL(_hom->fwd[0][0],_hom->fwd[2][1],r2),s2);
|
767
|
+
_hom->inv22=QR_FIXMUL(_hom->fwd[0][0],_hom->fwd[1][1],
|
768
|
+
-QR_EXTMUL(_hom->fwd[0][1],_hom->fwd[1][0],r2),s2);
|
769
|
+
_hom->res=_res;
|
770
|
+
}
|
771
|
+
|
772
|
+
|
773
|
+
/*Map from the image (at subpel resolution) into the square domain.
|
774
|
+
Returns a negative value if the point went to infinity.*/
|
775
|
+
static int qr_hom_unproject(qr_point _q,const qr_hom *_hom,int _x,int _y){
|
776
|
+
int x;
|
777
|
+
int y;
|
778
|
+
int w;
|
779
|
+
_x-=_hom->x0;
|
780
|
+
_y-=_hom->y0;
|
781
|
+
x=_hom->inv[0][0]*_x+_hom->inv[0][1]*_y;
|
782
|
+
y=_hom->inv[1][0]*_x+_hom->inv[1][1]*_y;
|
783
|
+
w=_hom->inv[2][0]*_x+_hom->inv[2][1]*_y
|
784
|
+
+_hom->inv22+(1<<_hom->res-1)>>_hom->res;
|
785
|
+
if(w==0){
|
786
|
+
_q[0]=x<0?INT_MIN:INT_MAX;
|
787
|
+
_q[1]=y<0?INT_MIN:INT_MAX;
|
788
|
+
return -1;
|
789
|
+
}
|
790
|
+
else{
|
791
|
+
if(w<0){
|
792
|
+
x=-x;
|
793
|
+
y=-y;
|
794
|
+
w=-w;
|
795
|
+
}
|
796
|
+
_q[0]=QR_DIVROUND(x,w);
|
797
|
+
_q[1]=QR_DIVROUND(y,w);
|
798
|
+
}
|
799
|
+
return 0;
|
800
|
+
}
|
801
|
+
|
802
|
+
/*Finish a partial projection, converting from homogeneous coordinates to the
|
803
|
+
normal 2-D representation.
|
804
|
+
In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
|
805
|
+
and _w incrementally, but we cannot avoid the divisions, done here.*/
|
806
|
+
static void qr_hom_fproject(qr_point _p,const qr_hom *_hom,
|
807
|
+
int _x,int _y,int _w){
|
808
|
+
if(_w==0){
|
809
|
+
_p[0]=_x<0?INT_MIN:INT_MAX;
|
810
|
+
_p[1]=_y<0?INT_MIN:INT_MAX;
|
811
|
+
}
|
812
|
+
else{
|
813
|
+
if(_w<0){
|
814
|
+
_x=-_x;
|
815
|
+
_y=-_y;
|
816
|
+
_w=-_w;
|
817
|
+
}
|
818
|
+
_p[0]=QR_DIVROUND(_x,_w)+_hom->x0;
|
819
|
+
_p[1]=QR_DIVROUND(_y,_w)+_hom->y0;
|
820
|
+
}
|
821
|
+
}
|
822
|
+
|
823
|
+
#if defined(QR_DEBUG)
|
824
|
+
/*Map from the square domain into the image (at subpel resolution).
|
825
|
+
Currently only used directly by debug code.*/
|
826
|
+
static void qr_hom_project(qr_point _p,const qr_hom *_hom,
|
827
|
+
int _u,int _v){
|
828
|
+
qr_hom_fproject(_p,_hom,
|
829
|
+
_hom->fwd[0][0]*_u+_hom->fwd[0][1]*_v,
|
830
|
+
_hom->fwd[1][0]*_u+_hom->fwd[1][1]*_v,
|
831
|
+
_hom->fwd[2][0]*_u+_hom->fwd[2][1]*_v+_hom->fwd22);
|
832
|
+
}
|
833
|
+
#endif
|
834
|
+
|
835
|
+
|
836
|
+
|
837
|
+
/*All the information we've collected about a finder pattern in the current
|
838
|
+
configuration.*/
|
839
|
+
struct qr_finder{
|
840
|
+
/*The module size along each axis (in the square domain).*/
|
841
|
+
int size[2];
|
842
|
+
/*The version estimated from the module size along each axis.*/
|
843
|
+
int eversion[2];
|
844
|
+
/*The list of classified edge points for each edge.*/
|
845
|
+
qr_finder_edge_pt *edge_pts[4];
|
846
|
+
/*The number of edge points classified as belonging to each edge.*/
|
847
|
+
int nedge_pts[4];
|
848
|
+
/*The number of inliers found after running RANSAC on each edge.*/
|
849
|
+
int ninliers[4];
|
850
|
+
/*The center of the finder pattern (in the square domain).*/
|
851
|
+
qr_point o;
|
852
|
+
/*The finder center information from the original image.*/
|
853
|
+
qr_finder_center *c;
|
854
|
+
};
|
855
|
+
|
856
|
+
|
857
|
+
static int qr_cmp_edge_pt(const void *_a,const void *_b){
|
858
|
+
const qr_finder_edge_pt *a;
|
859
|
+
const qr_finder_edge_pt *b;
|
860
|
+
a=(const qr_finder_edge_pt *)_a;
|
861
|
+
b=(const qr_finder_edge_pt *)_b;
|
862
|
+
return ((a->edge>b->edge)-(a->edge<b->edge)<<1)+
|
863
|
+
(a->extent>b->extent)-(a->extent<b->extent);
|
864
|
+
}
|
865
|
+
|
866
|
+
/*Computes the index of the edge each edge point belongs to, and its (signed)
|
867
|
+
distance along the corresponding axis from the center of the finder pattern
|
868
|
+
(in the square domain).
|
869
|
+
The resulting list of edge points is sorted by edge index, with ties broken
|
870
|
+
by extent.*/
|
871
|
+
static void qr_finder_edge_pts_aff_classify(qr_finder *_f,const qr_aff *_aff){
|
872
|
+
qr_finder_center *c;
|
873
|
+
int i;
|
874
|
+
int e;
|
875
|
+
c=_f->c;
|
876
|
+
for(e=0;e<4;e++)_f->nedge_pts[e]=0;
|
877
|
+
for(i=0;i<c->nedge_pts;i++){
|
878
|
+
qr_point q;
|
879
|
+
int d;
|
880
|
+
qr_aff_unproject(q,_aff,c->edge_pts[i].pos[0],c->edge_pts[i].pos[1]);
|
881
|
+
qr_point_translate(q,-_f->o[0],-_f->o[1]);
|
882
|
+
d=abs(q[1])>abs(q[0]);
|
883
|
+
e=d<<1|(q[d]>=0);
|
884
|
+
_f->nedge_pts[e]++;
|
885
|
+
c->edge_pts[i].edge=e;
|
886
|
+
c->edge_pts[i].extent=q[d];
|
887
|
+
}
|
888
|
+
qsort(c->edge_pts,c->nedge_pts,sizeof(*c->edge_pts),qr_cmp_edge_pt);
|
889
|
+
_f->edge_pts[0]=c->edge_pts;
|
890
|
+
for(e=1;e<4;e++)_f->edge_pts[e]=_f->edge_pts[e-1]+_f->nedge_pts[e-1];
|
891
|
+
}
|
892
|
+
|
893
|
+
/*Computes the index of the edge each edge point belongs to, and its (signed)
|
894
|
+
distance along the corresponding axis from the center of the finder pattern
|
895
|
+
(in the square domain).
|
896
|
+
The resulting list of edge points is sorted by edge index, with ties broken
|
897
|
+
by extent.*/
|
898
|
+
static void qr_finder_edge_pts_hom_classify(qr_finder *_f,const qr_hom *_hom){
|
899
|
+
qr_finder_center *c;
|
900
|
+
int i;
|
901
|
+
int e;
|
902
|
+
c=_f->c;
|
903
|
+
for(e=0;e<4;e++)_f->nedge_pts[e]=0;
|
904
|
+
for(i=0;i<c->nedge_pts;i++){
|
905
|
+
qr_point q;
|
906
|
+
int d;
|
907
|
+
if(qr_hom_unproject(q,_hom,
|
908
|
+
c->edge_pts[i].pos[0],c->edge_pts[i].pos[1])>=0){
|
909
|
+
qr_point_translate(q,-_f->o[0],-_f->o[1]);
|
910
|
+
d=abs(q[1])>abs(q[0]);
|
911
|
+
e=d<<1|(q[d]>=0);
|
912
|
+
_f->nedge_pts[e]++;
|
913
|
+
c->edge_pts[i].edge=e;
|
914
|
+
c->edge_pts[i].extent=q[d];
|
915
|
+
}
|
916
|
+
else{
|
917
|
+
c->edge_pts[i].edge=4;
|
918
|
+
c->edge_pts[i].extent=q[0];
|
919
|
+
}
|
920
|
+
}
|
921
|
+
qsort(c->edge_pts,c->nedge_pts,sizeof(*c->edge_pts),qr_cmp_edge_pt);
|
922
|
+
_f->edge_pts[0]=c->edge_pts;
|
923
|
+
for(e=1;e<4;e++)_f->edge_pts[e]=_f->edge_pts[e-1]+_f->nedge_pts[e-1];
|
924
|
+
}
|
925
|
+
|
926
|
+
/*TODO: Perhaps these thresholds should be on the module size instead?
|
927
|
+
Unfortunately, I'd need real-world images of codes with larger versions to
|
928
|
+
see if these thresholds are still effective, but such versions aren't used
|
929
|
+
often.*/
|
930
|
+
|
931
|
+
/*The amount that the estimated version numbers are allowed to differ from the
|
932
|
+
real version number and still be considered valid.*/
|
933
|
+
#define QR_SMALL_VERSION_SLACK (1)
|
934
|
+
/*Since cell phone cameras can have severe radial distortion, the estimated
|
935
|
+
version for larger versions can be off by larger amounts.*/
|
936
|
+
#define QR_LARGE_VERSION_SLACK (3)
|
937
|
+
|
938
|
+
/*Estimates the size of a module after classifying the edge points.
|
939
|
+
_width: The distance between UL and UR in the square domain.
|
940
|
+
_height: The distance between UL and DL in the square domain.*/
|
941
|
+
static int qr_finder_estimate_module_size_and_version(qr_finder *_f,
|
942
|
+
int _width,int _height){
|
943
|
+
qr_point offs;
|
944
|
+
int sums[4];
|
945
|
+
int nsums[4];
|
946
|
+
int usize;
|
947
|
+
int nusize;
|
948
|
+
int vsize;
|
949
|
+
int nvsize;
|
950
|
+
int uversion;
|
951
|
+
int vversion;
|
952
|
+
int e;
|
953
|
+
offs[0]=offs[1]=0;
|
954
|
+
for(e=0;e<4;e++)if(_f->nedge_pts[e]>0){
|
955
|
+
qr_finder_edge_pt *edge_pts;
|
956
|
+
int sum;
|
957
|
+
int mean;
|
958
|
+
int n;
|
959
|
+
int i;
|
960
|
+
/*Average the samples for this edge, dropping the top and bottom 25%.*/
|
961
|
+
edge_pts=_f->edge_pts[e];
|
962
|
+
n=_f->nedge_pts[e];
|
963
|
+
sum=0;
|
964
|
+
for(i=(n>>2);i<n-(n>>2);i++)sum+=edge_pts[i].extent;
|
965
|
+
n=n-((n>>2)<<1);
|
966
|
+
mean=QR_DIVROUND(sum,n);
|
967
|
+
offs[e>>1]+=mean;
|
968
|
+
sums[e]=sum;
|
969
|
+
nsums[e]=n;
|
970
|
+
}
|
971
|
+
else nsums[e]=sums[e]=0;
|
972
|
+
/*If we have samples on both sides of an axis, refine our idea of where the
|
973
|
+
unprojected finder center is located.*/
|
974
|
+
if(_f->nedge_pts[0]>0&&_f->nedge_pts[1]>0){
|
975
|
+
_f->o[0]-=offs[0]>>1;
|
976
|
+
sums[0]-=offs[0]*nsums[0]>>1;
|
977
|
+
sums[1]-=offs[0]*nsums[1]>>1;
|
978
|
+
}
|
979
|
+
if(_f->nedge_pts[2]>0&&_f->nedge_pts[3]>0){
|
980
|
+
_f->o[1]-=offs[1]>>1;
|
981
|
+
sums[2]-=offs[1]*nsums[2]>>1;
|
982
|
+
sums[3]-=offs[1]*nsums[3]>>1;
|
983
|
+
}
|
984
|
+
/*We must have _some_ samples along each axis... if we don't, our transform
|
985
|
+
must be pretty severely distorting the original square (e.g., with
|
986
|
+
coordinates so large as to cause overflow).*/
|
987
|
+
nusize=nsums[0]+nsums[1];
|
988
|
+
if(nusize<=0)return -1;
|
989
|
+
/*The module size is 1/3 the average edge extent.*/
|
990
|
+
nusize*=3;
|
991
|
+
usize=sums[1]-sums[0];
|
992
|
+
usize=((usize<<1)+nusize)/(nusize<<1);
|
993
|
+
if(usize<=0)return -1;
|
994
|
+
/*Now estimate the version directly from the module size and the distance
|
995
|
+
between the finder patterns.
|
996
|
+
This is done independently using the extents along each axis.
|
997
|
+
If either falls significantly outside the valid range (1 to 40), reject the
|
998
|
+
configuration.*/
|
999
|
+
uversion=(_width-8*usize)/(usize<<2);
|
1000
|
+
if(uversion<1||uversion>40+QR_LARGE_VERSION_SLACK)return -1;
|
1001
|
+
/*Now do the same for the other axis.*/
|
1002
|
+
nvsize=nsums[2]+nsums[3];
|
1003
|
+
if(nvsize<=0)return -1;
|
1004
|
+
nvsize*=3;
|
1005
|
+
vsize=sums[3]-sums[2];
|
1006
|
+
vsize=((vsize<<1)+nvsize)/(nvsize<<1);
|
1007
|
+
if(vsize<=0)return -1;
|
1008
|
+
vversion=(_height-8*vsize)/(vsize<<2);
|
1009
|
+
if(vversion<1||vversion>40+QR_LARGE_VERSION_SLACK)return -1;
|
1010
|
+
/*If the estimated version using extents along one axis is significantly
|
1011
|
+
different than the estimated version along the other axis, then the axes
|
1012
|
+
have significantly different scalings (relative to the grid).
|
1013
|
+
This can happen, e.g., when we have multiple adjacent QR codes, and we've
|
1014
|
+
picked two finder patterns from one and the third finder pattern from
|
1015
|
+
another, e.g.:
|
1016
|
+
X---DL UL---X
|
1017
|
+
|.... |....
|
1018
|
+
X.... UR....
|
1019
|
+
Such a configuration might even pass any other geometric checks if we
|
1020
|
+
didn't reject it here.*/
|
1021
|
+
if(abs(uversion-vversion)>QR_LARGE_VERSION_SLACK)return -1;
|
1022
|
+
_f->size[0]=usize;
|
1023
|
+
_f->size[1]=vsize;
|
1024
|
+
/*We intentionally do not compute an average version from the sizes along
|
1025
|
+
both axes.
|
1026
|
+
In the presence of projective distortion, one of them will be much more
|
1027
|
+
accurate than the other.*/
|
1028
|
+
_f->eversion[0]=uversion;
|
1029
|
+
_f->eversion[1]=vversion;
|
1030
|
+
return 0;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
/*Eliminate outliers from the classified edge points with RANSAC.*/
|
1034
|
+
static void qr_finder_ransac(qr_finder *_f,const qr_aff *_hom,
|
1035
|
+
isaac_ctx *_isaac,int _e){
|
1036
|
+
qr_finder_edge_pt *edge_pts;
|
1037
|
+
int best_ninliers;
|
1038
|
+
int n;
|
1039
|
+
edge_pts=_f->edge_pts[_e];
|
1040
|
+
n=_f->nedge_pts[_e];
|
1041
|
+
best_ninliers=0;
|
1042
|
+
if(n>1){
|
1043
|
+
int max_iters;
|
1044
|
+
int i;
|
1045
|
+
int j;
|
1046
|
+
/*17 iterations is enough to guarantee an outlier-free sample with more
|
1047
|
+
than 99% probability given as many as 50% outliers.*/
|
1048
|
+
max_iters=17;
|
1049
|
+
for(i=0;i<max_iters;i++){
|
1050
|
+
qr_point q0;
|
1051
|
+
qr_point q1;
|
1052
|
+
int ninliers;
|
1053
|
+
int thresh;
|
1054
|
+
int p0i;
|
1055
|
+
int p1i;
|
1056
|
+
int *p0;
|
1057
|
+
int *p1;
|
1058
|
+
int j;
|
1059
|
+
/*Pick two random points on this edge.*/
|
1060
|
+
p0i=isaac_next_uint(_isaac,n);
|
1061
|
+
p1i=isaac_next_uint(_isaac,n-1);
|
1062
|
+
if(p1i>=p0i)p1i++;
|
1063
|
+
p0=edge_pts[p0i].pos;
|
1064
|
+
p1=edge_pts[p1i].pos;
|
1065
|
+
/*If the corresponding line is not within 45 degrees of the proper
|
1066
|
+
orientation in the square domain, reject it outright.
|
1067
|
+
This can happen, e.g., when highly skewed orientations cause points to
|
1068
|
+
be misclassified into the wrong edge.
|
1069
|
+
The irony is that using such points might produce a line which _does_
|
1070
|
+
pass the corresponding validity checks.*/
|
1071
|
+
qr_aff_unproject(q0,_hom,p0[0],p0[1]);
|
1072
|
+
qr_aff_unproject(q1,_hom,p1[0],p1[1]);
|
1073
|
+
qr_point_translate(q0,-_f->o[0],-_f->o[1]);
|
1074
|
+
qr_point_translate(q1,-_f->o[0],-_f->o[1]);
|
1075
|
+
if(abs(q0[_e>>1]-q1[_e>>1])>abs(q0[1-(_e>>1)]-q1[1-(_e>>1)]))continue;
|
1076
|
+
/*Identify the other edge points which are inliers.
|
1077
|
+
The squared distance should be distributed as a \Chi^2 distribution
|
1078
|
+
with one degree of freedom, which means for a 95% confidence the
|
1079
|
+
point should lie within a factor 3.8414588 ~= 4 times the expected
|
1080
|
+
variance of the point locations.
|
1081
|
+
We grossly approximate the standard deviation as 1 pixel in one
|
1082
|
+
direction, and 0.5 pixels in the other (because we average two
|
1083
|
+
coordinates).*/
|
1084
|
+
thresh=qr_isqrt(qr_point_distance2(p0,p1)<<2*QR_FINDER_SUBPREC+1);
|
1085
|
+
ninliers=0;
|
1086
|
+
for(j=0;j<n;j++){
|
1087
|
+
if(abs(qr_point_ccw(p0,p1,edge_pts[j].pos))<=thresh){
|
1088
|
+
edge_pts[j].extent|=1;
|
1089
|
+
ninliers++;
|
1090
|
+
}
|
1091
|
+
else edge_pts[j].extent&=~1;
|
1092
|
+
}
|
1093
|
+
if(ninliers>best_ninliers){
|
1094
|
+
for(j=0;j<n;j++)edge_pts[j].extent<<=1;
|
1095
|
+
best_ninliers=ninliers;
|
1096
|
+
/*The actual number of iterations required is
|
1097
|
+
log(1-\alpha)/log(1-r*r),
|
1098
|
+
where \alpha is the required probability of taking a sample with
|
1099
|
+
no outliers (e.g., 0.99) and r is the estimated ratio of inliers
|
1100
|
+
(e.g. ninliers/n).
|
1101
|
+
This is just a rough (but conservative) approximation, but it
|
1102
|
+
should be good enough to stop the iteration early when we find
|
1103
|
+
a good set of inliers.*/
|
1104
|
+
if(ninliers>n>>1)max_iters=(67*n-63*ninliers-1)/(n<<1);
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
/*Now collect all the inliers at the beginning of the list.*/
|
1108
|
+
for(i=j=0;j<best_ninliers;i++)if(edge_pts[i].extent&2){
|
1109
|
+
if(j<i){
|
1110
|
+
qr_finder_edge_pt tmp;
|
1111
|
+
*&tmp=*(edge_pts+i);
|
1112
|
+
*(edge_pts+j)=*(edge_pts+i);
|
1113
|
+
*(edge_pts+i)=*&tmp;
|
1114
|
+
}
|
1115
|
+
j++;
|
1116
|
+
}
|
1117
|
+
}
|
1118
|
+
_f->ninliers[_e]=best_ninliers;
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
/*Perform a least-squares line fit to an edge of a finder pattern using the
|
1122
|
+
inliers found by RANSAC.*/
|
1123
|
+
static int qr_line_fit_finder_edge(qr_line _l,
|
1124
|
+
const qr_finder *_f,int _e,int _res){
|
1125
|
+
qr_finder_edge_pt *edge_pts;
|
1126
|
+
qr_point *pts;
|
1127
|
+
int npts;
|
1128
|
+
int i;
|
1129
|
+
npts=_f->ninliers[_e];
|
1130
|
+
if(npts<2)return -1;
|
1131
|
+
/*We could write a custom version of qr_line_fit_points that accesses
|
1132
|
+
edge_pts directly, but this saves on code size and doesn't measurably slow
|
1133
|
+
things down.*/
|
1134
|
+
pts=(qr_point *)malloc(npts*sizeof(*pts));
|
1135
|
+
edge_pts=_f->edge_pts[_e];
|
1136
|
+
for(i=0;i<npts;i++){
|
1137
|
+
pts[i][0]=edge_pts[i].pos[0];
|
1138
|
+
pts[i][1]=edge_pts[i].pos[1];
|
1139
|
+
}
|
1140
|
+
qr_line_fit_points(_l,pts,npts,_res);
|
1141
|
+
/*Make sure the center of the finder pattern lies in the positive halfspace
|
1142
|
+
of the line.*/
|
1143
|
+
qr_line_orient(_l,_f->c->pos[0],_f->c->pos[1]);
|
1144
|
+
free(pts);
|
1145
|
+
return 0;
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
/*Perform a least-squares line fit to a pair of common finder edges using the
|
1149
|
+
inliers found by RANSAC.
|
1150
|
+
Unlike a normal edge fit, we guarantee that this one succeeds by creating at
|
1151
|
+
least one point on each edge using the estimated module size if it has no
|
1152
|
+
inliers.*/
|
1153
|
+
static void qr_line_fit_finder_pair(qr_line _l,const qr_aff *_aff,
|
1154
|
+
const qr_finder *_f0,const qr_finder *_f1,int _e){
|
1155
|
+
qr_point *pts;
|
1156
|
+
int npts;
|
1157
|
+
qr_finder_edge_pt *edge_pts;
|
1158
|
+
qr_point q;
|
1159
|
+
int n0;
|
1160
|
+
int n1;
|
1161
|
+
int i;
|
1162
|
+
n0=_f0->ninliers[_e];
|
1163
|
+
n1=_f1->ninliers[_e];
|
1164
|
+
/*We could write a custom version of qr_line_fit_points that accesses
|
1165
|
+
edge_pts directly, but this saves on code size and doesn't measurably slow
|
1166
|
+
things down.*/
|
1167
|
+
npts=QR_MAXI(n0,1)+QR_MAXI(n1,1);
|
1168
|
+
pts=(qr_point *)malloc(npts*sizeof(*pts));
|
1169
|
+
if(n0>0){
|
1170
|
+
edge_pts=_f0->edge_pts[_e];
|
1171
|
+
for(i=0;i<n0;i++){
|
1172
|
+
pts[i][0]=edge_pts[i].pos[0];
|
1173
|
+
pts[i][1]=edge_pts[i].pos[1];
|
1174
|
+
}
|
1175
|
+
}
|
1176
|
+
else{
|
1177
|
+
q[0]=_f0->o[0];
|
1178
|
+
q[1]=_f0->o[1];
|
1179
|
+
q[_e>>1]+=_f0->size[_e>>1]*(2*(_e&1)-1);
|
1180
|
+
qr_aff_project(pts[0],_aff,q[0],q[1]);
|
1181
|
+
n0++;
|
1182
|
+
}
|
1183
|
+
if(n1>0){
|
1184
|
+
edge_pts=_f1->edge_pts[_e];
|
1185
|
+
for(i=0;i<n1;i++){
|
1186
|
+
pts[n0+i][0]=edge_pts[i].pos[0];
|
1187
|
+
pts[n0+i][1]=edge_pts[i].pos[1];
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
else{
|
1191
|
+
q[0]=_f1->o[0];
|
1192
|
+
q[1]=_f1->o[1];
|
1193
|
+
q[_e>>1]+=_f1->size[_e>>1]*(2*(_e&1)-1);
|
1194
|
+
qr_aff_project(pts[n0],_aff,q[0],q[1]);
|
1195
|
+
n1++;
|
1196
|
+
}
|
1197
|
+
qr_line_fit_points(_l,pts,npts,_aff->res);
|
1198
|
+
/*Make sure at least one finder center lies in the positive halfspace.*/
|
1199
|
+
qr_line_orient(_l,_f0->c->pos[0],_f0->c->pos[1]);
|
1200
|
+
free(pts);
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
static int qr_finder_quick_crossing_check(const unsigned char *_img,
|
1204
|
+
int _width,int _height,int _x0,int _y0,int _x1,int _y1,int _v){
|
1205
|
+
/*The points must be inside the image, and have a !_v:_v:!_v pattern.
|
1206
|
+
We don't scan the whole line initially, but quickly reject if the endpoints
|
1207
|
+
aren't !_v, or the midpoint isn't _v.
|
1208
|
+
If either end point is out of the image, or we don't encounter a _v pixel,
|
1209
|
+
we return a negative value, indicating the region should be considered
|
1210
|
+
empty.
|
1211
|
+
Otherwise, we return a positive value to indicate it is non-empty.*/
|
1212
|
+
if(_x0<0||_x0>=_width||_y0<0||_y0>=_height||
|
1213
|
+
_x1<0||_x1>=_width||_y1<0||_y1>=_height){
|
1214
|
+
return -1;
|
1215
|
+
}
|
1216
|
+
if(!_img[_y0*_width+_x0]!=_v||!_img[_y1*_width+_x1]!=_v)return 1;
|
1217
|
+
if(!_img[(_y0+_y1>>1)*_width+(_x0+_x1>>1)]==_v)return -1;
|
1218
|
+
return 0;
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
/*Locate the midpoint of a _v segment along a !_v:_v:!_v line from (_x0,_y0) to
|
1222
|
+
(_x1,_y1).
|
1223
|
+
All coordinates, which are NOT in subpel resolution, must lie inside the
|
1224
|
+
image, and the endpoints are already assumed to have the value !_v.
|
1225
|
+
The returned value is in subpel resolution.*/
|
1226
|
+
static int qr_finder_locate_crossing(const unsigned char *_img,
|
1227
|
+
int _width,int _height,int _x0,int _y0,int _x1,int _y1,int _v,qr_point _p){
|
1228
|
+
qr_point x0;
|
1229
|
+
qr_point x1;
|
1230
|
+
qr_point dx;
|
1231
|
+
int step[2];
|
1232
|
+
int steep;
|
1233
|
+
int err;
|
1234
|
+
int derr;
|
1235
|
+
/*Use Bresenham's algorithm to trace along the line and find the exact
|
1236
|
+
transitions from !_v to _v and back.*/
|
1237
|
+
x0[0]=_x0;
|
1238
|
+
x0[1]=_y0;
|
1239
|
+
x1[0]=_x1;
|
1240
|
+
x1[1]=_y1;
|
1241
|
+
dx[0]=abs(_x1-_x0);
|
1242
|
+
dx[1]=abs(_y1-_y0);
|
1243
|
+
steep=dx[1]>dx[0];
|
1244
|
+
err=0;
|
1245
|
+
derr=dx[1-steep];
|
1246
|
+
step[0]=((_x0<_x1)<<1)-1;
|
1247
|
+
step[1]=((_y0<_y1)<<1)-1;
|
1248
|
+
/*Find the first crossing from !_v to _v.*/
|
1249
|
+
for(;;){
|
1250
|
+
/*If we make it all the way to the other side, there's no crossing.*/
|
1251
|
+
if(x0[steep]==x1[steep])return -1;
|
1252
|
+
x0[steep]+=step[steep];
|
1253
|
+
err+=derr;
|
1254
|
+
if(err<<1>dx[steep]){
|
1255
|
+
x0[1-steep]+=step[1-steep];
|
1256
|
+
err-=dx[steep];
|
1257
|
+
}
|
1258
|
+
if(!_img[x0[1]*_width+x0[0]]!=_v)break;
|
1259
|
+
}
|
1260
|
+
/*Find the last crossing from _v to !_v.*/
|
1261
|
+
err=0;
|
1262
|
+
for(;;){
|
1263
|
+
if(x0[steep]==x1[steep])break;
|
1264
|
+
x1[steep]-=step[steep];
|
1265
|
+
err+=derr;
|
1266
|
+
if(err<<1>dx[steep]){
|
1267
|
+
x1[1-steep]-=step[1-steep];
|
1268
|
+
err-=dx[steep];
|
1269
|
+
}
|
1270
|
+
if(!_img[x1[1]*_width+x1[0]]!=_v)break;
|
1271
|
+
}
|
1272
|
+
/*Return the midpoint of the _v segment.*/
|
1273
|
+
_p[0]=(x0[0]+x1[0]+1<<QR_FINDER_SUBPREC)>>1;
|
1274
|
+
_p[1]=(x0[1]+x1[1]+1<<QR_FINDER_SUBPREC)>>1;
|
1275
|
+
return 0;
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
static int qr_aff_line_step(const qr_aff *_aff,qr_line _l,
|
1279
|
+
int _v,int _du,int *_dv){
|
1280
|
+
int shift;
|
1281
|
+
int round;
|
1282
|
+
int dv;
|
1283
|
+
int n;
|
1284
|
+
int d;
|
1285
|
+
n=_aff->fwd[0][_v]*_l[0]+_aff->fwd[1][_v]*_l[1];
|
1286
|
+
d=_aff->fwd[0][1-_v]*_l[0]+_aff->fwd[1][1-_v]*_l[1];
|
1287
|
+
if(d<0){
|
1288
|
+
n=-n;
|
1289
|
+
d=-d;
|
1290
|
+
}
|
1291
|
+
shift=QR_MAXI(0,qr_ilog(_du)+qr_ilog(abs(n))+3-QR_INT_BITS);
|
1292
|
+
round=(1<<shift)>>1;
|
1293
|
+
n=n+round>>shift;
|
1294
|
+
d=d+round>>shift;
|
1295
|
+
/*The line should not be outside 45 degrees of horizontal/vertical.
|
1296
|
+
TODO: We impose this restriction to help ensure the loop below terminates,
|
1297
|
+
but it should not technically be required.
|
1298
|
+
It also, however, ensures we avoid division by zero.*/
|
1299
|
+
if(abs(n)>=d)return -1;
|
1300
|
+
n=-_du*n;
|
1301
|
+
dv=QR_DIVROUND(n,d);
|
1302
|
+
if(abs(dv)>=_du)return -1;
|
1303
|
+
*_dv=dv;
|
1304
|
+
return 0;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
/*Computes the Hamming distance between two bit patterns (the number of bits
|
1308
|
+
that differ).
|
1309
|
+
May stop counting after _maxdiff differences.*/
|
1310
|
+
static int qr_hamming_dist(unsigned _y1,unsigned _y2,int _maxdiff){
|
1311
|
+
unsigned y;
|
1312
|
+
int ret;
|
1313
|
+
y=_y1^_y2;
|
1314
|
+
for(ret=0;ret<_maxdiff&&y;ret++)y&=y-1;
|
1315
|
+
return ret;
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
/*Retrieve a bit (guaranteed to be 0 or 1) from the image, given coordinates in
|
1319
|
+
subpel resolution which have not been bounds checked.*/
|
1320
|
+
static int qr_img_get_bit(const unsigned char *_img,int _width,int _height,
|
1321
|
+
int _x,int _y){
|
1322
|
+
_x>>=QR_FINDER_SUBPREC;
|
1323
|
+
_y>>=QR_FINDER_SUBPREC;
|
1324
|
+
return _img[QR_CLAMPI(0,_y,_height-1)*_width+QR_CLAMPI(0,_x,_width-1)]!=0;
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
#if defined(QR_DEBUG)
|
1328
|
+
#include "image.h"
|
1329
|
+
|
1330
|
+
static void qr_finder_dump_aff_undistorted(qr_finder *_ul,qr_finder *_ur,
|
1331
|
+
qr_finder *_dl,qr_aff *_aff,const unsigned char *_img,int _width,int _height){
|
1332
|
+
unsigned char *gimg;
|
1333
|
+
FILE *fout;
|
1334
|
+
int lpsz;
|
1335
|
+
int pixel_size;
|
1336
|
+
int dim;
|
1337
|
+
int min;
|
1338
|
+
int max;
|
1339
|
+
int u;
|
1340
|
+
int y;
|
1341
|
+
int i;
|
1342
|
+
int j;
|
1343
|
+
lpsz=qr_ilog(_ur->size[0]+_ur->size[1]+_dl->size[0]+_dl->size[1])-6;
|
1344
|
+
pixel_size=1<<lpsz;
|
1345
|
+
dim=(1<<_aff->res-lpsz)+128;
|
1346
|
+
gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
|
1347
|
+
for(i=0;i<dim;i++)for(j=0;j<dim;j++){
|
1348
|
+
qr_point p;
|
1349
|
+
qr_aff_project(p,_aff,(j-64)<<lpsz,(i-64)<<lpsz);
|
1350
|
+
gimg[i*dim+j]=_img[
|
1351
|
+
QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
|
1352
|
+
QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
|
1353
|
+
}
|
1354
|
+
{
|
1355
|
+
min=(_ur->o[0]-7*_ur->size[0]>>lpsz)+64;
|
1356
|
+
if(min<0)min=0;
|
1357
|
+
max=(_ur->o[0]+7*_ur->size[0]>>lpsz)+64;
|
1358
|
+
if(max>dim)max=dim;
|
1359
|
+
for(y=-7;y<=7;y++){
|
1360
|
+
i=(_ur->o[1]+y*_ur->size[1]>>lpsz)+64;
|
1361
|
+
if(i<0||i>=dim)continue;
|
1362
|
+
for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
|
1363
|
+
}
|
1364
|
+
min=(_ur->o[1]-7*_ur->size[1]>>lpsz)+64;
|
1365
|
+
if(min<0)min=0;
|
1366
|
+
max=(_ur->o[1]+7*_ur->size[1]>>lpsz)+64;
|
1367
|
+
if(max>dim)max=dim;
|
1368
|
+
for(u=-7;u<=7;u++){
|
1369
|
+
j=(_ur->o[0]+u*_ur->size[0]>>lpsz)+64;
|
1370
|
+
if(j<0||j>=dim)continue;
|
1371
|
+
for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
|
1372
|
+
}
|
1373
|
+
}
|
1374
|
+
{
|
1375
|
+
min=(_dl->o[0]-7*_dl->size[0]>>lpsz)+64;
|
1376
|
+
if(min<0)min=0;
|
1377
|
+
max=(_dl->o[0]+7*_dl->size[0]>>lpsz)+64;
|
1378
|
+
if(max>dim)max=dim;
|
1379
|
+
for(y=-7;y<=7;y++){
|
1380
|
+
i=(_dl->o[1]+y*_dl->size[1]>>lpsz)+64;
|
1381
|
+
if(i<0||i>=dim)continue;
|
1382
|
+
for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
|
1383
|
+
}
|
1384
|
+
min=(_dl->o[1]-7*_dl->size[1]>>lpsz)+64;
|
1385
|
+
if(min<0)min=0;
|
1386
|
+
max=(_dl->o[1]+7*_dl->size[1]>>lpsz)+64;
|
1387
|
+
if(max>dim)max=dim;
|
1388
|
+
for(u=-7;u<=7;u++){
|
1389
|
+
j=(_dl->o[0]+u*_dl->size[0]>>lpsz)+64;
|
1390
|
+
if(j<0||j>=dim)continue;
|
1391
|
+
for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
|
1392
|
+
}
|
1393
|
+
}
|
1394
|
+
fout=fopen("undistorted_aff.png","wb");
|
1395
|
+
image_write_png(gimg,dim,dim,fout);
|
1396
|
+
fclose(fout);
|
1397
|
+
free(gimg);
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
static void qr_finder_dump_hom_undistorted(qr_finder *_ul,qr_finder *_ur,
|
1401
|
+
qr_finder *_dl,qr_hom *_hom,const unsigned char *_img,int _width,int _height){
|
1402
|
+
unsigned char *gimg;
|
1403
|
+
FILE *fout;
|
1404
|
+
int lpsz;
|
1405
|
+
int pixel_size;
|
1406
|
+
int dim;
|
1407
|
+
int min;
|
1408
|
+
int max;
|
1409
|
+
int u;
|
1410
|
+
int v;
|
1411
|
+
int i;
|
1412
|
+
int j;
|
1413
|
+
lpsz=qr_ilog(_ur->size[0]+_ur->size[1]+_dl->size[0]+_dl->size[1])-6;
|
1414
|
+
pixel_size=1<<lpsz;
|
1415
|
+
dim=(1<<_hom->res-lpsz)+256;
|
1416
|
+
gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
|
1417
|
+
for(i=0;i<dim;i++)for(j=0;j<dim;j++){
|
1418
|
+
qr_point p;
|
1419
|
+
qr_hom_project(p,_hom,(j-128)<<lpsz,(i-128)<<lpsz);
|
1420
|
+
gimg[i*dim+j]=_img[
|
1421
|
+
QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
|
1422
|
+
QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
|
1423
|
+
}
|
1424
|
+
{
|
1425
|
+
min=(_ur->o[0]-7*_ur->size[0]>>lpsz)+128;
|
1426
|
+
if(min<0)min=0;
|
1427
|
+
max=(_ur->o[0]+7*_ur->size[0]>>lpsz)+128;
|
1428
|
+
if(max>dim)max=dim;
|
1429
|
+
for(v=-7;v<=7;v++){
|
1430
|
+
i=(_ur->o[1]+v*_ur->size[1]>>lpsz)+128;
|
1431
|
+
if(i<0||i>=dim)continue;
|
1432
|
+
for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
|
1433
|
+
}
|
1434
|
+
min=(_ur->o[1]-7*_ur->size[1]>>lpsz)+128;
|
1435
|
+
if(min<0)min=0;
|
1436
|
+
max=(_ur->o[1]+7*_ur->size[1]>>lpsz)+128;
|
1437
|
+
if(max>dim)max=dim;
|
1438
|
+
for(u=-7;u<=7;u++){
|
1439
|
+
j=(_ur->o[0]+u*_ur->size[0]>>lpsz)+128;
|
1440
|
+
if(j<0||j>=dim)continue;
|
1441
|
+
for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
|
1442
|
+
}
|
1443
|
+
}
|
1444
|
+
{
|
1445
|
+
min=(_dl->o[0]-7*_dl->size[0]>>lpsz)+128;
|
1446
|
+
if(min<0)min=0;
|
1447
|
+
max=(_dl->o[0]+7*_dl->size[0]>>lpsz)+128;
|
1448
|
+
if(max>dim)max=dim;
|
1449
|
+
for(v=-7;v<=7;v++){
|
1450
|
+
i=(_dl->o[1]+v*_dl->size[1]>>lpsz)+128;
|
1451
|
+
if(i<0||i>=dim)continue;
|
1452
|
+
for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
|
1453
|
+
}
|
1454
|
+
min=(_dl->o[1]-7*_dl->size[1]>>lpsz)+128;
|
1455
|
+
if(min<0)min=0;
|
1456
|
+
max=(_dl->o[1]+7*_dl->size[1]>>lpsz)+128;
|
1457
|
+
if(max>dim)max=dim;
|
1458
|
+
for(u=-7;u<=7;u++){
|
1459
|
+
j=(_dl->o[0]+u*_dl->size[0]>>lpsz)+128;
|
1460
|
+
if(j<0||j>=dim)continue;
|
1461
|
+
for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
fout=fopen("undistorted_hom.png","wb");
|
1465
|
+
image_write_png(gimg,dim,dim,fout);
|
1466
|
+
fclose(fout);
|
1467
|
+
free(gimg);
|
1468
|
+
}
|
1469
|
+
#endif
|
1470
|
+
|
1471
|
+
|
1472
|
+
|
1473
|
+
/*A homography from one region of the grid back to the image.
|
1474
|
+
Unlike a qr_hom, this does not include an inverse transform and maps directly
|
1475
|
+
from the grid points, not a square with power-of-two sides.*/
|
1476
|
+
struct qr_hom_cell{
|
1477
|
+
int fwd[3][3];
|
1478
|
+
int x0;
|
1479
|
+
int y0;
|
1480
|
+
int u0;
|
1481
|
+
int v0;
|
1482
|
+
};
|
1483
|
+
|
1484
|
+
|
1485
|
+
static void qr_hom_cell_init(qr_hom_cell *_cell,int _u0,int _v0,
|
1486
|
+
int _u1,int _v1,int _u2,int _v2,int _u3,int _v3,int _x0,int _y0,
|
1487
|
+
int _x1,int _y1,int _x2,int _y2,int _x3,int _y3){
|
1488
|
+
int du10;
|
1489
|
+
int du20;
|
1490
|
+
int du30;
|
1491
|
+
int du31;
|
1492
|
+
int du32;
|
1493
|
+
int dv10;
|
1494
|
+
int dv20;
|
1495
|
+
int dv30;
|
1496
|
+
int dv31;
|
1497
|
+
int dv32;
|
1498
|
+
int dx10;
|
1499
|
+
int dx20;
|
1500
|
+
int dx30;
|
1501
|
+
int dx31;
|
1502
|
+
int dx32;
|
1503
|
+
int dy10;
|
1504
|
+
int dy20;
|
1505
|
+
int dy30;
|
1506
|
+
int dy31;
|
1507
|
+
int dy32;
|
1508
|
+
int a00;
|
1509
|
+
int a01;
|
1510
|
+
int a02;
|
1511
|
+
int a10;
|
1512
|
+
int a11;
|
1513
|
+
int a12;
|
1514
|
+
int a20;
|
1515
|
+
int a21;
|
1516
|
+
int a22;
|
1517
|
+
int i00;
|
1518
|
+
int i01;
|
1519
|
+
int i10;
|
1520
|
+
int i11;
|
1521
|
+
int i20;
|
1522
|
+
int i21;
|
1523
|
+
int i22;
|
1524
|
+
int b0;
|
1525
|
+
int b1;
|
1526
|
+
int b2;
|
1527
|
+
int shift;
|
1528
|
+
int round;
|
1529
|
+
int x;
|
1530
|
+
int y;
|
1531
|
+
int w;
|
1532
|
+
/*First, correct for the arrangement of the source points.
|
1533
|
+
We take advantage of the fact that we know the source points have a very
|
1534
|
+
limited dynamic range (so there will never be overflow) and a small amount
|
1535
|
+
of projective distortion.*/
|
1536
|
+
du10=_u1-_u0;
|
1537
|
+
du20=_u2-_u0;
|
1538
|
+
du30=_u3-_u0;
|
1539
|
+
du31=_u3-_u1;
|
1540
|
+
du32=_u3-_u2;
|
1541
|
+
dv10=_v1-_v0;
|
1542
|
+
dv20=_v2-_v0;
|
1543
|
+
dv30=_v3-_v0;
|
1544
|
+
dv31=_v3-_v1;
|
1545
|
+
dv32=_v3-_v2;
|
1546
|
+
/*Compute the coefficients of the forward transform from the unit square to
|
1547
|
+
the source point configuration.*/
|
1548
|
+
a20=du32*dv10-du10*dv32;
|
1549
|
+
a21=du20*dv31-du31*dv20;
|
1550
|
+
if(a20||a21)a22=du32*dv31-du31*dv32;
|
1551
|
+
/*If the source grid points aren't in a non-affine arrangement, there's no
|
1552
|
+
reason to scale everything by du32*dv31-du31*dv32.
|
1553
|
+
Not doing so allows a much larger dynamic range, and is the only way we can
|
1554
|
+
initialize a base cell that covers the whole grid.*/
|
1555
|
+
else a22=1;
|
1556
|
+
a00=du10*(a20+a22);
|
1557
|
+
a01=du20*(a21+a22);
|
1558
|
+
a10=dv10*(a20+a22);
|
1559
|
+
a11=dv20*(a21+a22);
|
1560
|
+
/*Now compute the inverse transform.*/
|
1561
|
+
i00=a11*a22;
|
1562
|
+
i01=-a01*a22;
|
1563
|
+
i10=-a10*a22;
|
1564
|
+
i11=a00*a22;
|
1565
|
+
i20=a10*a21-a11*a20;
|
1566
|
+
i21=a01*a20-a00*a21;
|
1567
|
+
i22=a00*a11-a01*a10;
|
1568
|
+
/*Invert the coefficients.
|
1569
|
+
Since i22 is the largest, we divide it by all the others.
|
1570
|
+
The quotient is often exact (e.g., when the source points contain no
|
1571
|
+
projective distortion), and is never zero.
|
1572
|
+
Hence we can use zero to signal "infinity" when the divisor is zero.*/
|
1573
|
+
if(i00)i00=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i00)),i00);
|
1574
|
+
if(i01)i01=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i01)),i01);
|
1575
|
+
if(i10)i10=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i10)),i10);
|
1576
|
+
if(i11)i11=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i11)),i11);
|
1577
|
+
if(i20)i20=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i20)),i20);
|
1578
|
+
if(i21)i21=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i21)),i21);
|
1579
|
+
/*Now compute the map from the unit square into the image.*/
|
1580
|
+
dx10=_x1-_x0;
|
1581
|
+
dx20=_x2-_x0;
|
1582
|
+
dx30=_x3-_x0;
|
1583
|
+
dx31=_x3-_x1;
|
1584
|
+
dx32=_x3-_x2;
|
1585
|
+
dy10=_y1-_y0;
|
1586
|
+
dy20=_y2-_y0;
|
1587
|
+
dy30=_y3-_y0;
|
1588
|
+
dy31=_y3-_y1;
|
1589
|
+
dy32=_y3-_y2;
|
1590
|
+
a20=dx32*dy10-dx10*dy32;
|
1591
|
+
a21=dx20*dy31-dx31*dy20;
|
1592
|
+
a22=dx32*dy31-dx31*dy32;
|
1593
|
+
/*Figure out if we need to downscale anything.*/
|
1594
|
+
b0=qr_ilog(QR_MAXI(abs(dx10),abs(dy10)))+qr_ilog(abs(a20+a22));
|
1595
|
+
b1=qr_ilog(QR_MAXI(abs(dx20),abs(dy20)))+qr_ilog(abs(a21+a22));
|
1596
|
+
b2=qr_ilog(QR_MAXI(QR_MAXI(abs(a20),abs(a21)),abs(a22)));
|
1597
|
+
shift=QR_MAXI(0,QR_MAXI(QR_MAXI(b0,b1),b2)-(QR_INT_BITS-3-QR_ALIGN_SUBPREC));
|
1598
|
+
round=(1<<shift)>>1;
|
1599
|
+
/*Compute the final coefficients of the forward transform.*/
|
1600
|
+
a00=QR_FIXMUL(dx10,a20+a22,round,shift);
|
1601
|
+
a01=QR_FIXMUL(dx20,a21+a22,round,shift);
|
1602
|
+
a10=QR_FIXMUL(dy10,a20+a22,round,shift);
|
1603
|
+
a11=QR_FIXMUL(dy20,a21+a22,round,shift);
|
1604
|
+
/*And compose the two transforms.
|
1605
|
+
Since we inverted the coefficients above, we divide by them here instead
|
1606
|
+
of multiplying.
|
1607
|
+
This lets us take advantage of the full dynamic range.
|
1608
|
+
Note a zero divisor is really "infinity", and thus the quotient should also
|
1609
|
+
be zero.*/
|
1610
|
+
_cell->fwd[0][0]=(i00?QR_DIVROUND(a00,i00):0)+(i10?QR_DIVROUND(a01,i10):0);
|
1611
|
+
_cell->fwd[0][1]=(i01?QR_DIVROUND(a00,i01):0)+(i11?QR_DIVROUND(a01,i11):0);
|
1612
|
+
_cell->fwd[1][0]=(i00?QR_DIVROUND(a10,i00):0)+(i10?QR_DIVROUND(a11,i10):0);
|
1613
|
+
_cell->fwd[1][1]=(i01?QR_DIVROUND(a10,i01):0)+(i11?QR_DIVROUND(a11,i11):0);
|
1614
|
+
_cell->fwd[2][0]=(i00?QR_DIVROUND(a20,i00):0)+(i10?QR_DIVROUND(a21,i10):0)
|
1615
|
+
+(i20?QR_DIVROUND(a22,i20):0)+round>>shift;
|
1616
|
+
_cell->fwd[2][1]=(i01?QR_DIVROUND(a20,i01):0)+(i11?QR_DIVROUND(a21,i11):0)
|
1617
|
+
+(i21?QR_DIVROUND(a22,i21):0)+round>>shift;
|
1618
|
+
_cell->fwd[2][2]=a22+round>>shift;
|
1619
|
+
/*Mathematically, a02 and a12 are exactly zero.
|
1620
|
+
However, that concentrates all of the rounding error in the (_u3,_v3)
|
1621
|
+
corner; we compute offsets which distribute it over the whole range.*/
|
1622
|
+
x=_cell->fwd[0][0]*du10+_cell->fwd[0][1]*dv10;
|
1623
|
+
y=_cell->fwd[1][0]*du10+_cell->fwd[1][1]*dv10;
|
1624
|
+
w=_cell->fwd[2][0]*du10+_cell->fwd[2][1]*dv10+_cell->fwd[2][2];
|
1625
|
+
a02=dx10*w-x;
|
1626
|
+
a12=dy10*w-y;
|
1627
|
+
x=_cell->fwd[0][0]*du20+_cell->fwd[0][1]*dv20;
|
1628
|
+
y=_cell->fwd[1][0]*du20+_cell->fwd[1][1]*dv20;
|
1629
|
+
w=_cell->fwd[2][0]*du20+_cell->fwd[2][1]*dv20+_cell->fwd[2][2];
|
1630
|
+
a02+=dx20*w-x;
|
1631
|
+
a12+=dy20*w-y;
|
1632
|
+
x=_cell->fwd[0][0]*du30+_cell->fwd[0][1]*dv30;
|
1633
|
+
y=_cell->fwd[1][0]*du30+_cell->fwd[1][1]*dv30;
|
1634
|
+
w=_cell->fwd[2][0]*du30+_cell->fwd[2][1]*dv30+_cell->fwd[2][2];
|
1635
|
+
a02+=dx30*w-x;
|
1636
|
+
a12+=dy30*w-y;
|
1637
|
+
_cell->fwd[0][2]=a02+2>>2;
|
1638
|
+
_cell->fwd[1][2]=a12+2>>2;
|
1639
|
+
_cell->x0=_x0;
|
1640
|
+
_cell->y0=_y0;
|
1641
|
+
_cell->u0=_u0;
|
1642
|
+
_cell->v0=_v0;
|
1643
|
+
}
|
1644
|
+
|
1645
|
+
/*Finish a partial projection, converting from homogeneous coordinates to the
|
1646
|
+
normal 2-D representation.
|
1647
|
+
In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
|
1648
|
+
and _w incrementally, but we cannot avoid the divisions, done here.*/
|
1649
|
+
static void qr_hom_cell_fproject(qr_point _p,const qr_hom_cell *_cell,
|
1650
|
+
int _x,int _y,int _w){
|
1651
|
+
if(_w==0){
|
1652
|
+
_p[0]=_x<0?INT_MIN:INT_MAX;
|
1653
|
+
_p[1]=_y<0?INT_MIN:INT_MAX;
|
1654
|
+
}
|
1655
|
+
else{
|
1656
|
+
if(_w<0){
|
1657
|
+
_x=-_x;
|
1658
|
+
_y=-_y;
|
1659
|
+
_w=-_w;
|
1660
|
+
}
|
1661
|
+
_p[0]=QR_DIVROUND(_x,_w)+_cell->x0;
|
1662
|
+
_p[1]=QR_DIVROUND(_y,_w)+_cell->y0;
|
1663
|
+
}
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
static void qr_hom_cell_project(qr_point _p,const qr_hom_cell *_cell,
|
1667
|
+
int _u,int _v,int _res){
|
1668
|
+
_u-=_cell->u0<<_res;
|
1669
|
+
_v-=_cell->v0<<_res;
|
1670
|
+
qr_hom_cell_fproject(_p,_cell,
|
1671
|
+
_cell->fwd[0][0]*_u+_cell->fwd[0][1]*_v+(_cell->fwd[0][2]<<_res),
|
1672
|
+
_cell->fwd[1][0]*_u+_cell->fwd[1][1]*_v+(_cell->fwd[1][2]<<_res),
|
1673
|
+
_cell->fwd[2][0]*_u+_cell->fwd[2][1]*_v+(_cell->fwd[2][2]<<_res));
|
1674
|
+
}
|
1675
|
+
|
1676
|
+
|
1677
|
+
|
1678
|
+
/*Retrieves the bits corresponding to the alignment pattern template centered
|
1679
|
+
at the given location in the original image (at subpel precision).*/
|
1680
|
+
static unsigned qr_alignment_pattern_fetch(qr_point _p[5][5],int _x0,int _y0,
|
1681
|
+
const unsigned char *_img,int _width,int _height){
|
1682
|
+
unsigned v;
|
1683
|
+
int i;
|
1684
|
+
int j;
|
1685
|
+
int k;
|
1686
|
+
int dx;
|
1687
|
+
int dy;
|
1688
|
+
dx=_x0-_p[2][2][0];
|
1689
|
+
dy=_y0-_p[2][2][1];
|
1690
|
+
v=0;
|
1691
|
+
for(k=i=0;i<5;i++)for(j=0;j<5;j++,k++){
|
1692
|
+
v|=qr_img_get_bit(_img,_width,_height,_p[i][j][0]+dx,_p[i][j][1]+dy)<<k;
|
1693
|
+
}
|
1694
|
+
return v;
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
/*Searches for an alignment pattern near the given location.*/
|
1698
|
+
static int qr_alignment_pattern_search(qr_point _p,const qr_hom_cell *_cell,
|
1699
|
+
int _u,int _v,int _r,const unsigned char *_img,int _width,int _height){
|
1700
|
+
qr_point c[4];
|
1701
|
+
int nc[4];
|
1702
|
+
qr_point p[5][5];
|
1703
|
+
qr_point pc;
|
1704
|
+
unsigned best_match;
|
1705
|
+
int best_dist;
|
1706
|
+
int bestx;
|
1707
|
+
int besty;
|
1708
|
+
unsigned match;
|
1709
|
+
int dist;
|
1710
|
+
int u;
|
1711
|
+
int v;
|
1712
|
+
int x0;
|
1713
|
+
int y0;
|
1714
|
+
int w0;
|
1715
|
+
int x;
|
1716
|
+
int y;
|
1717
|
+
int w;
|
1718
|
+
int dxdu;
|
1719
|
+
int dydu;
|
1720
|
+
int dwdu;
|
1721
|
+
int dxdv;
|
1722
|
+
int dydv;
|
1723
|
+
int dwdv;
|
1724
|
+
int dx;
|
1725
|
+
int dy;
|
1726
|
+
int i;
|
1727
|
+
int j;
|
1728
|
+
/*Build up a basic template using _cell to control shape and scale.
|
1729
|
+
We project the points in the template back to the image just once, since if
|
1730
|
+
the alignment pattern has moved, we don't really know why.
|
1731
|
+
If it's because of radial distortion, or the code wasn't flat, or something
|
1732
|
+
else, there's no reason to expect that a re-projection around each
|
1733
|
+
subsequent search point would be any closer to the actual shape than our
|
1734
|
+
first projection.
|
1735
|
+
Therefore we simply slide this template around, as is.*/
|
1736
|
+
u=(_u-2)-_cell->u0;
|
1737
|
+
v=(_v-2)-_cell->v0;
|
1738
|
+
x0=_cell->fwd[0][0]*u+_cell->fwd[0][1]*v+_cell->fwd[0][2];
|
1739
|
+
y0=_cell->fwd[1][0]*u+_cell->fwd[1][1]*v+_cell->fwd[1][2];
|
1740
|
+
w0=_cell->fwd[2][0]*u+_cell->fwd[2][1]*v+_cell->fwd[2][2];
|
1741
|
+
dxdu=_cell->fwd[0][0];
|
1742
|
+
dydu=_cell->fwd[1][0];
|
1743
|
+
dwdu=_cell->fwd[2][0];
|
1744
|
+
dxdv=_cell->fwd[0][1];
|
1745
|
+
dydv=_cell->fwd[1][1];
|
1746
|
+
dwdv=_cell->fwd[2][1];
|
1747
|
+
for(i=0;i<5;i++){
|
1748
|
+
x=x0;
|
1749
|
+
y=y0;
|
1750
|
+
w=w0;
|
1751
|
+
for(j=0;j<5;j++){
|
1752
|
+
qr_hom_cell_fproject(p[i][j],_cell,x,y,w);
|
1753
|
+
x+=dxdu;
|
1754
|
+
y+=dydu;
|
1755
|
+
w+=dwdu;
|
1756
|
+
}
|
1757
|
+
x0+=dxdv;
|
1758
|
+
y0+=dydv;
|
1759
|
+
w0+=dwdv;
|
1760
|
+
}
|
1761
|
+
bestx=p[2][2][0];
|
1762
|
+
besty=p[2][2][1];
|
1763
|
+
best_match=qr_alignment_pattern_fetch(p,bestx,besty,_img,_width,_height);
|
1764
|
+
best_dist=qr_hamming_dist(best_match,0x1F8D63F,25);
|
1765
|
+
if(best_dist>0){
|
1766
|
+
u=_u-_cell->u0;
|
1767
|
+
v=_v-_cell->v0;
|
1768
|
+
x=_cell->fwd[0][0]*u+_cell->fwd[0][1]*v+_cell->fwd[0][2]<<QR_ALIGN_SUBPREC;
|
1769
|
+
y=_cell->fwd[1][0]*u+_cell->fwd[1][1]*v+_cell->fwd[1][2]<<QR_ALIGN_SUBPREC;
|
1770
|
+
w=_cell->fwd[2][0]*u+_cell->fwd[2][1]*v+_cell->fwd[2][2]<<QR_ALIGN_SUBPREC;
|
1771
|
+
/*Search an area at most _r modules around the target location, in
|
1772
|
+
concentric squares..*/
|
1773
|
+
for(i=1;i<_r<<QR_ALIGN_SUBPREC;i++){
|
1774
|
+
int side_len;
|
1775
|
+
side_len=(i<<1)-1;
|
1776
|
+
x-=dxdu+dxdv;
|
1777
|
+
y-=dydu+dydv;
|
1778
|
+
w-=dwdu+dwdv;
|
1779
|
+
for(j=0;j<4*side_len;j++){
|
1780
|
+
int dir;
|
1781
|
+
qr_hom_cell_fproject(pc,_cell,x,y,w);
|
1782
|
+
match=qr_alignment_pattern_fetch(p,pc[0],pc[1],_img,_width,_height);
|
1783
|
+
dist=qr_hamming_dist(match,0x1F8D63F,best_dist+1);
|
1784
|
+
if(dist<best_dist){
|
1785
|
+
best_match=match;
|
1786
|
+
best_dist=dist;
|
1787
|
+
bestx=pc[0];
|
1788
|
+
besty=pc[1];
|
1789
|
+
}
|
1790
|
+
if(j<2*side_len){
|
1791
|
+
dir=j>=side_len;
|
1792
|
+
x+=_cell->fwd[0][dir];
|
1793
|
+
y+=_cell->fwd[1][dir];
|
1794
|
+
w+=_cell->fwd[2][dir];
|
1795
|
+
}
|
1796
|
+
else{
|
1797
|
+
dir=j>=3*side_len;
|
1798
|
+
x-=_cell->fwd[0][dir];
|
1799
|
+
y-=_cell->fwd[1][dir];
|
1800
|
+
w-=_cell->fwd[2][dir];
|
1801
|
+
}
|
1802
|
+
if(!best_dist)break;
|
1803
|
+
}
|
1804
|
+
if(!best_dist)break;
|
1805
|
+
}
|
1806
|
+
}
|
1807
|
+
/*If the best result we got was sufficiently bad, reject the match.
|
1808
|
+
If we're wrong and we include it, we can grossly distort the nearby
|
1809
|
+
region, whereas using the initial starting point should at least be
|
1810
|
+
consistent with the geometry we already have.*/
|
1811
|
+
if(best_dist>6){
|
1812
|
+
_p[0]=p[2][2][0];
|
1813
|
+
_p[1]=p[2][2][1];
|
1814
|
+
return -1;
|
1815
|
+
}
|
1816
|
+
/*Now try to get a more accurate location of the pattern center.*/
|
1817
|
+
dx=bestx-p[2][2][0];
|
1818
|
+
dy=besty-p[2][2][1];
|
1819
|
+
memset(nc,0,sizeof(nc));
|
1820
|
+
memset(c,0,sizeof(c));
|
1821
|
+
/*We consider 8 lines across the finder pattern in turn.
|
1822
|
+
If we actually found a symmetric pattern along that line, search for its
|
1823
|
+
exact center in the image.
|
1824
|
+
There are plenty more lines we could use if these don't work, but if we've
|
1825
|
+
found anything remotely close to an alignment pattern, we should be able
|
1826
|
+
to use most of these.*/
|
1827
|
+
for(i=0;i<8;i++){
|
1828
|
+
static const unsigned MASK_TESTS[8][2]={
|
1829
|
+
{0x1040041,0x1000001},{0x0041040,0x0001000},
|
1830
|
+
{0x0110110,0x0100010},{0x0011100,0x0001000},
|
1831
|
+
{0x0420084,0x0400004},{0x0021080,0x0001000},
|
1832
|
+
{0x0006C00,0x0004400},{0x0003800,0x0001000},
|
1833
|
+
};
|
1834
|
+
static const unsigned char MASK_COORDS[8][2]={
|
1835
|
+
{0,0},{1,1},{4,0},{3,1},{2,0},{2,1},{0,2},{1,2}
|
1836
|
+
};
|
1837
|
+
if((best_match&MASK_TESTS[i][0])==MASK_TESTS[i][1]){
|
1838
|
+
int x0;
|
1839
|
+
int y0;
|
1840
|
+
int x1;
|
1841
|
+
int y1;
|
1842
|
+
x0=p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][0]+dx>>QR_FINDER_SUBPREC;
|
1843
|
+
if(x0<0||x0>=_width)continue;
|
1844
|
+
y0=p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][1]+dy>>QR_FINDER_SUBPREC;
|
1845
|
+
if(y0<0||y0>=_height)continue;
|
1846
|
+
x1=p[4-MASK_COORDS[i][1]][4-MASK_COORDS[i][0]][0]+dx>>QR_FINDER_SUBPREC;
|
1847
|
+
if(x1<0||x1>=_width)continue;
|
1848
|
+
y1=p[4-MASK_COORDS[i][1]][4-MASK_COORDS[i][0]][1]+dy>>QR_FINDER_SUBPREC;
|
1849
|
+
if(y1<0||y1>=_height)continue;
|
1850
|
+
if(!qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,i&1,pc)){
|
1851
|
+
int w;
|
1852
|
+
int cx;
|
1853
|
+
int cy;
|
1854
|
+
cx=pc[0]-bestx;
|
1855
|
+
cy=pc[1]-besty;
|
1856
|
+
if(i&1){
|
1857
|
+
/*Weight crossings around the center dot more highly, as they are
|
1858
|
+
generally more reliable.*/
|
1859
|
+
w=3;
|
1860
|
+
cx+=cx<<1;
|
1861
|
+
cy+=cy<<1;
|
1862
|
+
}
|
1863
|
+
else w=1;
|
1864
|
+
nc[i>>1]+=w;
|
1865
|
+
c[i>>1][0]+=cx;
|
1866
|
+
c[i>>1][1]+=cy;
|
1867
|
+
}
|
1868
|
+
}
|
1869
|
+
}
|
1870
|
+
/*Sum offsets from lines in orthogonal directions.*/
|
1871
|
+
for(i=0;i<2;i++){
|
1872
|
+
int a;
|
1873
|
+
int b;
|
1874
|
+
a=nc[i<<1];
|
1875
|
+
b=nc[i<<1|1];
|
1876
|
+
if(a&&b){
|
1877
|
+
int w;
|
1878
|
+
w=QR_MAXI(a,b);
|
1879
|
+
c[i<<1][0]=QR_DIVROUND(w*(b*c[i<<1][0]+a*c[i<<1|1][0]),a*b);
|
1880
|
+
c[i<<1][1]=QR_DIVROUND(w*(b*c[i<<1][1]+a*c[i<<1|1][1]),a*b);
|
1881
|
+
nc[i<<1]=w<<1;
|
1882
|
+
}
|
1883
|
+
else{
|
1884
|
+
c[i<<1][0]+=c[i<<1|1][0];
|
1885
|
+
c[i<<1][1]+=c[i<<1|1][1];
|
1886
|
+
nc[i<<1]+=b;
|
1887
|
+
}
|
1888
|
+
}
|
1889
|
+
/*Average offsets from pairs of orthogonal lines.*/
|
1890
|
+
c[0][0]+=c[2][0];
|
1891
|
+
c[0][1]+=c[2][1];
|
1892
|
+
nc[0]+=nc[2];
|
1893
|
+
/*If we actually found any such lines, apply the adjustment.*/
|
1894
|
+
if(nc[0]){
|
1895
|
+
dx=QR_DIVROUND(c[0][0],nc[0]);
|
1896
|
+
dy=QR_DIVROUND(c[0][1],nc[0]);
|
1897
|
+
/*But only if it doesn't make things worse.*/
|
1898
|
+
match=qr_alignment_pattern_fetch(p,bestx+dx,besty+dy,_img,_width,_height);
|
1899
|
+
dist=qr_hamming_dist(match,0x1F8D63F,best_dist+1);
|
1900
|
+
if(dist<=best_dist){
|
1901
|
+
bestx+=dx;
|
1902
|
+
besty+=dy;
|
1903
|
+
}
|
1904
|
+
}
|
1905
|
+
_p[0]=bestx;
|
1906
|
+
_p[1]=besty;
|
1907
|
+
return 0;
|
1908
|
+
}
|
1909
|
+
|
1910
|
+
static int qr_hom_fit(qr_hom *_hom,qr_finder *_ul,qr_finder *_ur,
|
1911
|
+
qr_finder *_dl,qr_point _p[4],const qr_aff *_aff,isaac_ctx *_isaac,
|
1912
|
+
const unsigned char *_img,int _width,int _height){
|
1913
|
+
qr_point *b;
|
1914
|
+
int nb;
|
1915
|
+
int cb;
|
1916
|
+
qr_point *r;
|
1917
|
+
int nr;
|
1918
|
+
int cr;
|
1919
|
+
qr_line l[4];
|
1920
|
+
qr_point q;
|
1921
|
+
qr_point p;
|
1922
|
+
int ox;
|
1923
|
+
int oy;
|
1924
|
+
int ru;
|
1925
|
+
int rv;
|
1926
|
+
int dru;
|
1927
|
+
int drv;
|
1928
|
+
int bu;
|
1929
|
+
int bv;
|
1930
|
+
int dbu;
|
1931
|
+
int dbv;
|
1932
|
+
int rx;
|
1933
|
+
int ry;
|
1934
|
+
int drxi;
|
1935
|
+
int dryi;
|
1936
|
+
int drxj;
|
1937
|
+
int dryj;
|
1938
|
+
int rdone;
|
1939
|
+
int nrempty;
|
1940
|
+
int rlastfit;
|
1941
|
+
int bx;
|
1942
|
+
int by;
|
1943
|
+
int dbxi;
|
1944
|
+
int dbyi;
|
1945
|
+
int dbxj;
|
1946
|
+
int dbyj;
|
1947
|
+
int bdone;
|
1948
|
+
int nbempty;
|
1949
|
+
int blastfit;
|
1950
|
+
int shift;
|
1951
|
+
int round;
|
1952
|
+
int version4;
|
1953
|
+
int brx;
|
1954
|
+
int bry;
|
1955
|
+
int i;
|
1956
|
+
/*We attempt to correct large-scale perspective distortion by fitting lines
|
1957
|
+
to the edge of the code area.
|
1958
|
+
We could also look for an alignment pattern now, but that wouldn't work for
|
1959
|
+
version 1 codes, which have no alignment pattern.
|
1960
|
+
Even if the code is supposed to have one, there's go guarantee we'd find it
|
1961
|
+
intact.*/
|
1962
|
+
/*Fitting lines is easy for the edges on which we have two finder patterns.
|
1963
|
+
After the fit, UL is guaranteed to be on the proper side, but if either of
|
1964
|
+
the other two finder patterns aren't, something is wrong.*/
|
1965
|
+
qr_finder_ransac(_ul,_aff,_isaac,0);
|
1966
|
+
qr_finder_ransac(_dl,_aff,_isaac,0);
|
1967
|
+
qr_line_fit_finder_pair(l[0],_aff,_ul,_dl,0);
|
1968
|
+
if(qr_line_eval(l[0],_dl->c->pos[0],_dl->c->pos[1])<0||
|
1969
|
+
qr_line_eval(l[0],_ur->c->pos[0],_ur->c->pos[1])<0){
|
1970
|
+
return -1;
|
1971
|
+
}
|
1972
|
+
qr_finder_ransac(_ul,_aff,_isaac,2);
|
1973
|
+
qr_finder_ransac(_ur,_aff,_isaac,2);
|
1974
|
+
qr_line_fit_finder_pair(l[2],_aff,_ul,_ur,2);
|
1975
|
+
if(qr_line_eval(l[2],_dl->c->pos[0],_dl->c->pos[1])<0||
|
1976
|
+
qr_line_eval(l[2],_ur->c->pos[0],_ur->c->pos[1])<0){
|
1977
|
+
return -1;
|
1978
|
+
}
|
1979
|
+
/*The edges which only have one finder pattern are more difficult.
|
1980
|
+
We start by fitting a line to the edge of the one finder pattern we do
|
1981
|
+
have.
|
1982
|
+
This can fail due to an insufficient number of sample points, and even if
|
1983
|
+
it succeeds can be fairly inaccurate, because all of the points are
|
1984
|
+
clustered in one corner of the QR code.
|
1985
|
+
If it fails, we just use an axis-aligned line in the affine coordinate
|
1986
|
+
system.
|
1987
|
+
Then we walk along the edge of the entire code, looking for
|
1988
|
+
light:dark:light patterns perpendicular to the edge.
|
1989
|
+
Wherever we find one, we take the center of the dark portion as an
|
1990
|
+
additional sample point.
|
1991
|
+
At the end, we re-fit the line using all such sample points found.*/
|
1992
|
+
drv=_ur->size[1]>>1;
|
1993
|
+
qr_finder_ransac(_ur,_aff,_isaac,1);
|
1994
|
+
if(qr_line_fit_finder_edge(l[1],_ur,1,_aff->res)>=0){
|
1995
|
+
if(qr_line_eval(l[1],_ul->c->pos[0],_ul->c->pos[1])<0||
|
1996
|
+
qr_line_eval(l[1],_dl->c->pos[0],_dl->c->pos[1])<0){
|
1997
|
+
return -1;
|
1998
|
+
}
|
1999
|
+
/*Figure out the change in ru for a given change in rv when stepping along
|
2000
|
+
the fitted line.*/
|
2001
|
+
if(qr_aff_line_step(_aff,l[1],1,drv,&dru)<0)return -1;
|
2002
|
+
}
|
2003
|
+
else dru=0;
|
2004
|
+
ru=_ur->o[0]+3*_ur->size[0]-2*dru;
|
2005
|
+
rv=_ur->o[1]-2*drv;
|
2006
|
+
dbu=_dl->size[0]>>1;
|
2007
|
+
qr_finder_ransac(_dl,_aff,_isaac,3);
|
2008
|
+
if(qr_line_fit_finder_edge(l[3],_dl,3,_aff->res)>=0){
|
2009
|
+
if(qr_line_eval(l[3],_ul->c->pos[0],_ul->c->pos[1])<0||
|
2010
|
+
qr_line_eval(l[3],_ur->c->pos[0],_ur->c->pos[1])<0){
|
2011
|
+
return -1;
|
2012
|
+
}
|
2013
|
+
/*Figure out the change in bv for a given change in bu when stepping along
|
2014
|
+
the fitted line.*/
|
2015
|
+
if(qr_aff_line_step(_aff,l[3],0,dbu,&dbv)<0)return -1;
|
2016
|
+
}
|
2017
|
+
else dbv=0;
|
2018
|
+
bu=_dl->o[0]-2*dbu;
|
2019
|
+
bv=_dl->o[1]+3*_dl->size[1]-2*dbv;
|
2020
|
+
/*Set up the initial point lists.*/
|
2021
|
+
nr=rlastfit=_ur->ninliers[1];
|
2022
|
+
cr=nr+(_dl->o[1]-rv+drv-1)/drv;
|
2023
|
+
r=(qr_point *)malloc(cr*sizeof(*r));
|
2024
|
+
for(i=0;i<_ur->ninliers[1];i++){
|
2025
|
+
memcpy(r[i],_ur->edge_pts[1][i].pos,sizeof(r[i]));
|
2026
|
+
}
|
2027
|
+
nb=blastfit=_dl->ninliers[3];
|
2028
|
+
cb=nb+(_ur->o[0]-bu+dbu-1)/dbu;
|
2029
|
+
b=(qr_point *)malloc(cb*sizeof(*b));
|
2030
|
+
for(i=0;i<_dl->ninliers[3];i++){
|
2031
|
+
memcpy(b[i],_dl->edge_pts[3][i].pos,sizeof(b[i]));
|
2032
|
+
}
|
2033
|
+
/*Set up the step parameters for the affine projection.*/
|
2034
|
+
ox=(_aff->x0<<_aff->res)+(1<<_aff->res-1);
|
2035
|
+
oy=(_aff->y0<<_aff->res)+(1<<_aff->res-1);
|
2036
|
+
rx=_aff->fwd[0][0]*ru+_aff->fwd[0][1]*rv+ox;
|
2037
|
+
ry=_aff->fwd[1][0]*ru+_aff->fwd[1][1]*rv+oy;
|
2038
|
+
drxi=_aff->fwd[0][0]*dru+_aff->fwd[0][1]*drv;
|
2039
|
+
dryi=_aff->fwd[1][0]*dru+_aff->fwd[1][1]*drv;
|
2040
|
+
drxj=_aff->fwd[0][0]*_ur->size[0];
|
2041
|
+
dryj=_aff->fwd[1][0]*_ur->size[0];
|
2042
|
+
bx=_aff->fwd[0][0]*bu+_aff->fwd[0][1]*bv+ox;
|
2043
|
+
by=_aff->fwd[1][0]*bu+_aff->fwd[1][1]*bv+oy;
|
2044
|
+
dbxi=_aff->fwd[0][0]*dbu+_aff->fwd[0][1]*dbv;
|
2045
|
+
dbyi=_aff->fwd[1][0]*dbu+_aff->fwd[1][1]*dbv;
|
2046
|
+
dbxj=_aff->fwd[0][1]*_dl->size[1];
|
2047
|
+
dbyj=_aff->fwd[1][1]*_dl->size[1];
|
2048
|
+
/*Now step along the lines, looking for new sample points.*/
|
2049
|
+
nrempty=nbempty=0;
|
2050
|
+
for(;;){
|
2051
|
+
int ret;
|
2052
|
+
int x0;
|
2053
|
+
int y0;
|
2054
|
+
int x1;
|
2055
|
+
int y1;
|
2056
|
+
/*If we take too many steps without encountering a non-zero pixel, assume
|
2057
|
+
we have wandered off the edge and stop looking before we hit the other
|
2058
|
+
side of the quiet region.
|
2059
|
+
Otherwise, stop when the lines cross (if they do so inside the affine
|
2060
|
+
region) or come close to crossing (outside the affine region).
|
2061
|
+
TODO: We don't have any way of detecting when we've wandered into the
|
2062
|
+
code interior; we could stop if the outside sample ever shows up dark,
|
2063
|
+
but this could happen because of noise in the quiet region, too.*/
|
2064
|
+
rdone=rv>=QR_MINI(bv,_dl->o[1]+bv>>1)||nrempty>14;
|
2065
|
+
bdone=bu>=QR_MINI(ru,_ur->o[0]+ru>>1)||nbempty>14;
|
2066
|
+
if(!rdone&&(bdone||rv<bu)){
|
2067
|
+
x0=rx+drxj>>_aff->res+QR_FINDER_SUBPREC;
|
2068
|
+
y0=ry+dryj>>_aff->res+QR_FINDER_SUBPREC;
|
2069
|
+
x1=rx-drxj>>_aff->res+QR_FINDER_SUBPREC;
|
2070
|
+
y1=ry-dryj>>_aff->res+QR_FINDER_SUBPREC;
|
2071
|
+
if(nr>=cr){
|
2072
|
+
cr=cr<<1|1;
|
2073
|
+
r=(qr_point *)realloc(r,cr*sizeof(*r));
|
2074
|
+
}
|
2075
|
+
ret=qr_finder_quick_crossing_check(_img,_width,_height,x0,y0,x1,y1,1);
|
2076
|
+
if(!ret){
|
2077
|
+
ret=qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,1,r[nr]);
|
2078
|
+
}
|
2079
|
+
if(ret>=0){
|
2080
|
+
if(!ret){
|
2081
|
+
qr_aff_unproject(q,_aff,r[nr][0],r[nr][1]);
|
2082
|
+
/*Move the current point halfway towards the crossing.
|
2083
|
+
We don't move the whole way to give us some robustness to noise.*/
|
2084
|
+
ru=ru+q[0]>>1;
|
2085
|
+
/*But ensure that rv monotonically increases.*/
|
2086
|
+
if(q[1]+drv>rv)rv=rv+q[1]>>1;
|
2087
|
+
rx=_aff->fwd[0][0]*ru+_aff->fwd[0][1]*rv+ox;
|
2088
|
+
ry=_aff->fwd[1][0]*ru+_aff->fwd[1][1]*rv+oy;
|
2089
|
+
nr++;
|
2090
|
+
/*Re-fit the line to update the step direction periodically.*/
|
2091
|
+
if(nr>QR_MAXI(1,rlastfit+(rlastfit>>2))){
|
2092
|
+
qr_line_fit_points(l[1],r,nr,_aff->res);
|
2093
|
+
if(qr_aff_line_step(_aff,l[1],1,drv,&dru)>=0){
|
2094
|
+
drxi=_aff->fwd[0][0]*dru+_aff->fwd[0][1]*drv;
|
2095
|
+
dryi=_aff->fwd[1][0]*dru+_aff->fwd[1][1]*drv;
|
2096
|
+
}
|
2097
|
+
rlastfit=nr;
|
2098
|
+
}
|
2099
|
+
}
|
2100
|
+
else nrempty=0;
|
2101
|
+
}
|
2102
|
+
else nrempty++;
|
2103
|
+
ru+=dru;
|
2104
|
+
/*Our final defense: if we overflow, stop.*/
|
2105
|
+
if(rv+drv>rv)rv+=drv;
|
2106
|
+
else nrempty=INT_MAX;
|
2107
|
+
rx+=drxi;
|
2108
|
+
ry+=dryi;
|
2109
|
+
}
|
2110
|
+
else if(!bdone){
|
2111
|
+
x0=bx+dbxj>>_aff->res+QR_FINDER_SUBPREC;
|
2112
|
+
y0=by+dbyj>>_aff->res+QR_FINDER_SUBPREC;
|
2113
|
+
x1=bx-dbxj>>_aff->res+QR_FINDER_SUBPREC;
|
2114
|
+
y1=by-dbyj>>_aff->res+QR_FINDER_SUBPREC;
|
2115
|
+
if(nb>=cb){
|
2116
|
+
cb=cb<<1|1;
|
2117
|
+
b=(qr_point *)realloc(b,cb*sizeof(*b));
|
2118
|
+
}
|
2119
|
+
ret=qr_finder_quick_crossing_check(_img,_width,_height,x0,y0,x1,y1,1);
|
2120
|
+
if(!ret){
|
2121
|
+
ret=qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,1,b[nb]);
|
2122
|
+
}
|
2123
|
+
if(ret>=0){
|
2124
|
+
if(!ret){
|
2125
|
+
qr_aff_unproject(q,_aff,b[nb][0],b[nb][1]);
|
2126
|
+
/*Move the current point halfway towards the crossing.
|
2127
|
+
We don't move the whole way to give us some robustness to noise.*/
|
2128
|
+
/*But ensure that bu monotonically increases.*/
|
2129
|
+
if(q[0]+dbu>bu)bu=bu+q[0]>>1;
|
2130
|
+
bv=bv+q[1]>>1;
|
2131
|
+
bx=_aff->fwd[0][0]*bu+_aff->fwd[0][1]*bv+ox;
|
2132
|
+
by=_aff->fwd[1][0]*bu+_aff->fwd[1][1]*bv+oy;
|
2133
|
+
nb++;
|
2134
|
+
/*Re-fit the line to update the step direction periodically.*/
|
2135
|
+
if(nb>QR_MAXI(1,blastfit+(blastfit>>2))){
|
2136
|
+
qr_line_fit_points(l[3],b,nb,_aff->res);
|
2137
|
+
if(qr_aff_line_step(_aff,l[3],0,dbu,&dbv)>=0){
|
2138
|
+
dbxi=_aff->fwd[0][0]*dbu+_aff->fwd[0][1]*dbv;
|
2139
|
+
dbyi=_aff->fwd[1][0]*dbu+_aff->fwd[1][1]*dbv;
|
2140
|
+
}
|
2141
|
+
blastfit=nb;
|
2142
|
+
}
|
2143
|
+
}
|
2144
|
+
nbempty=0;
|
2145
|
+
}
|
2146
|
+
else nbempty++;
|
2147
|
+
/*Our final defense: if we overflow, stop.*/
|
2148
|
+
if(bu+dbu>bu)bu+=dbu;
|
2149
|
+
else nbempty=INT_MAX;
|
2150
|
+
bv+=dbv;
|
2151
|
+
bx+=dbxi;
|
2152
|
+
by+=dbyi;
|
2153
|
+
}
|
2154
|
+
else break;
|
2155
|
+
}
|
2156
|
+
/*Fit the new lines.
|
2157
|
+
If we _still_ don't have enough sample points, then just use an
|
2158
|
+
axis-aligned line from the affine coordinate system (e.g., one parallel
|
2159
|
+
to the opposite edge in the image).*/
|
2160
|
+
if(nr>1)qr_line_fit_points(l[1],r,nr,_aff->res);
|
2161
|
+
else{
|
2162
|
+
qr_aff_project(p,_aff,_ur->o[0]+3*_ur->size[0],_ur->o[1]);
|
2163
|
+
shift=QR_MAXI(0,
|
2164
|
+
qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),abs(_aff->fwd[1][1])))
|
2165
|
+
-(_aff->res+1>>1));
|
2166
|
+
round=(1<<shift)>>1;
|
2167
|
+
l[1][0]=_aff->fwd[1][1]+round>>shift;
|
2168
|
+
l[1][1]=-_aff->fwd[0][1]+round>>shift;
|
2169
|
+
l[1][2]=-(l[1][0]*p[0]+l[1][1]*p[1]);
|
2170
|
+
}
|
2171
|
+
free(r);
|
2172
|
+
if(nb>1)qr_line_fit_points(l[3],b,nb,_aff->res);
|
2173
|
+
else{
|
2174
|
+
qr_aff_project(p,_aff,_dl->o[0],_dl->o[1]+3*_dl->size[1]);
|
2175
|
+
shift=QR_MAXI(0,
|
2176
|
+
qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),abs(_aff->fwd[1][1])))
|
2177
|
+
-(_aff->res+1>>1));
|
2178
|
+
round=(1<<shift)>>1;
|
2179
|
+
l[3][0]=_aff->fwd[1][0]+round>>shift;
|
2180
|
+
l[3][1]=-_aff->fwd[0][0]+round>>shift;
|
2181
|
+
l[3][2]=-(l[1][0]*p[0]+l[1][1]*p[1]);
|
2182
|
+
}
|
2183
|
+
free(b);
|
2184
|
+
for(i=0;i<4;i++){
|
2185
|
+
if(qr_line_isect(_p[i],l[i&1],l[2+(i>>1)])<0)return -1;
|
2186
|
+
/*It's plausible for points to be somewhat outside the image, but too far
|
2187
|
+
and too much of the pattern will be gone for it to be decodable.*/
|
2188
|
+
if(_p[i][0]<-_width<<QR_FINDER_SUBPREC||
|
2189
|
+
_p[i][0]>=_width<<QR_FINDER_SUBPREC+1||
|
2190
|
+
_p[i][1]<-_height<<QR_FINDER_SUBPREC||
|
2191
|
+
_p[i][1]>=_height<<QR_FINDER_SUBPREC+1){
|
2192
|
+
return -1;
|
2193
|
+
}
|
2194
|
+
}
|
2195
|
+
/*By default, use the edge intersection point for the bottom-right corner.*/
|
2196
|
+
brx=_p[3][0];
|
2197
|
+
bry=_p[3][1];
|
2198
|
+
/*However, if our average version estimate is greater than 1, NOW we try to
|
2199
|
+
search for an alignment pattern.
|
2200
|
+
We get a much better success rate by doing this after our initial attempt
|
2201
|
+
to promote the transform to a homography than before.
|
2202
|
+
You might also think it would be more reliable to use the interior finder
|
2203
|
+
pattern edges, since the outer ones may be obscured or damaged, and it
|
2204
|
+
would save us a reprojection below, since they would form a nice square
|
2205
|
+
with the location of the alignment pattern, but this turns out to be a bad
|
2206
|
+
idea.
|
2207
|
+
Non-linear distortion is usually maximal on the outside edge, and thus
|
2208
|
+
estimating the grid position from points on the interior means we might
|
2209
|
+
get mis-aligned by the time we reach the edge.*/
|
2210
|
+
version4=_ul->eversion[0]+_ul->eversion[1]+_ur->eversion[0]+_dl->eversion[1];
|
2211
|
+
if(version4>4){
|
2212
|
+
qr_hom_cell cell;
|
2213
|
+
qr_point p3;
|
2214
|
+
int dim;
|
2215
|
+
dim=17+version4;
|
2216
|
+
qr_hom_cell_init(&cell,0,0,dim-1,0,0,dim-1,dim-1,dim-1,
|
2217
|
+
_p[0][0],_p[0][1],_p[1][0],_p[1][1],
|
2218
|
+
_p[2][0],_p[2][1],_p[3][0],_p[3][1]);
|
2219
|
+
if(qr_alignment_pattern_search(p3,&cell,dim-7,dim-7,4,
|
2220
|
+
_img,_width,_height)>=0){
|
2221
|
+
int c21;
|
2222
|
+
int dx21;
|
2223
|
+
int dy21;
|
2224
|
+
int mask;
|
2225
|
+
int w;
|
2226
|
+
/*There's no real need to update the bounding box corner, and in fact we
|
2227
|
+
actively perform worse if we do.
|
2228
|
+
Clearly it was good enough for us to find this alignment pattern, so
|
2229
|
+
it should be good enough to use for grid initialization.
|
2230
|
+
The point of doing the search was to get more accurate version
|
2231
|
+
estimates and a better chance of decoding the version and format info.
|
2232
|
+
This is particularly important for small versions that have no encoded
|
2233
|
+
version info, since any mismatch in version renders the code
|
2234
|
+
undecodable.*/
|
2235
|
+
/*We do, however, need four points in a square to initialize our
|
2236
|
+
homography, so project the point from the alignment center to the
|
2237
|
+
corner of the code area.*/
|
2238
|
+
c21=_p[2][0]*_p[1][1]-_p[2][1]*_p[1][0];
|
2239
|
+
dx21=_p[2][0]-_p[1][0];
|
2240
|
+
dy21=_p[2][1]-_p[1][1];
|
2241
|
+
w=(dim-7)*c21
|
2242
|
+
+(dim-13)*(_p[0][0]*dy21-_p[0][1]*dx21)+6*(p3[0]*dy21-p3[1]*dx21);
|
2243
|
+
mask=QR_SIGNMASK(w);
|
2244
|
+
w=abs(w);
|
2245
|
+
brx=(int)QR_DIVROUND(QR_EXTMUL((dim-7)*_p[0][0],p3[0]*dy21,
|
2246
|
+
QR_EXTMUL((dim-13)*p3[0],c21-_p[0][1]*dx21,
|
2247
|
+
QR_EXTMUL(6*_p[0][0],c21-p3[1]*dx21,0)))+mask^mask,w);
|
2248
|
+
bry=(int)QR_DIVROUND(QR_EXTMUL((dim-7)*_p[0][1],-p3[1]*dx21,
|
2249
|
+
QR_EXTMUL((dim-13)*p3[1],c21+_p[0][0]*dy21,
|
2250
|
+
QR_EXTMUL(6*_p[0][1],c21+p3[0]*dy21,0)))+mask^mask,w);
|
2251
|
+
}
|
2252
|
+
}
|
2253
|
+
/*Now we have four points that map to a square: initialize the projection.*/
|
2254
|
+
qr_hom_init(_hom,_p[0][0],_p[0][1],_p[1][0],_p[1][1],
|
2255
|
+
_p[2][0],_p[2][1],brx,bry,QR_HOM_BITS);
|
2256
|
+
return 0;
|
2257
|
+
}
|
2258
|
+
|
2259
|
+
|
2260
|
+
|
2261
|
+
/*The BCH(18,6,3) codes are only used for version information, which must lie
|
2262
|
+
between 7 and 40 (inclusive).*/
|
2263
|
+
static const unsigned BCH18_6_CODES[34]={
|
2264
|
+
0x07C94,
|
2265
|
+
0x085BC,0x09A99,0x0A4D3,0x0BBF6,0x0C762,0x0D847,0x0E60D,0x0F928,
|
2266
|
+
0x10B78,0x1145D,0x12A17,0x13532,0x149A6,0x15683,0x168C9,0x177EC,
|
2267
|
+
0x18EC4,0x191E1,0x1AFAB,0x1B08E,0x1CC1A,0x1D33F,0x1ED75,0x1F250,
|
2268
|
+
0x209D5,0x216F0,0x228BA,0x2379F,0x24B0B,0x2542E,0x26A64,0x27541,
|
2269
|
+
0x28C69
|
2270
|
+
};
|
2271
|
+
|
2272
|
+
/*Corrects a BCH(18,6,3) code word.
|
2273
|
+
_y: Contains the code word to be checked on input, and the corrected value on
|
2274
|
+
output.
|
2275
|
+
Return: The number of errors.
|
2276
|
+
If more than 3 errors are detected, returns a negative value and
|
2277
|
+
performs no correction.*/
|
2278
|
+
static int bch18_6_correct(unsigned *_y){
|
2279
|
+
unsigned x;
|
2280
|
+
unsigned y;
|
2281
|
+
int nerrs;
|
2282
|
+
y=*_y;
|
2283
|
+
/*Check the easy case first: see if the data bits were uncorrupted.*/
|
2284
|
+
x=y>>12;
|
2285
|
+
if(x>=7&&x<=40){
|
2286
|
+
nerrs=qr_hamming_dist(y,BCH18_6_CODES[x-7],4);
|
2287
|
+
if(nerrs<4){
|
2288
|
+
*_y=BCH18_6_CODES[x-7];
|
2289
|
+
return nerrs;
|
2290
|
+
}
|
2291
|
+
}
|
2292
|
+
/*Exhaustive search is faster than field operations in GF(19).*/
|
2293
|
+
for(x=0;x<34;x++)if(x+7!=y>>12){
|
2294
|
+
nerrs=qr_hamming_dist(y,BCH18_6_CODES[x],4);
|
2295
|
+
if(nerrs<4){
|
2296
|
+
*_y=BCH18_6_CODES[x];
|
2297
|
+
return nerrs;
|
2298
|
+
}
|
2299
|
+
}
|
2300
|
+
return -1;
|
2301
|
+
}
|
2302
|
+
|
2303
|
+
#if 0
|
2304
|
+
static unsigned bch18_6_encode(unsigned _x){
|
2305
|
+
return (-(_x&1)&0x01F25)^(-(_x>>1&1)&0x0216F)^(-(_x>>2&1)&0x042DE)^
|
2306
|
+
(-(_x>>3&1)&0x085BC)^(-(_x>>4&1)&0x10B78)^(-(_x>>5&1)&0x209D5);
|
2307
|
+
}
|
2308
|
+
#endif
|
2309
|
+
|
2310
|
+
/*Reads the version bits near a finder module and decodes the version number.*/
|
2311
|
+
static int qr_finder_version_decode(qr_finder *_f,const qr_hom *_hom,
|
2312
|
+
const unsigned char *_img,int _width,int _height,int _dir){
|
2313
|
+
qr_point q;
|
2314
|
+
unsigned v;
|
2315
|
+
int x0;
|
2316
|
+
int y0;
|
2317
|
+
int w0;
|
2318
|
+
int dxi;
|
2319
|
+
int dyi;
|
2320
|
+
int dwi;
|
2321
|
+
int dxj;
|
2322
|
+
int dyj;
|
2323
|
+
int dwj;
|
2324
|
+
int ret;
|
2325
|
+
int i;
|
2326
|
+
int j;
|
2327
|
+
int k;
|
2328
|
+
v=0;
|
2329
|
+
q[_dir]=_f->o[_dir]-7*_f->size[_dir];
|
2330
|
+
q[1-_dir]=_f->o[1-_dir]-3*_f->size[1-_dir];
|
2331
|
+
x0=_hom->fwd[0][0]*q[0]+_hom->fwd[0][1]*q[1];
|
2332
|
+
y0=_hom->fwd[1][0]*q[0]+_hom->fwd[1][1]*q[1];
|
2333
|
+
w0=_hom->fwd[2][0]*q[0]+_hom->fwd[2][1]*q[1]+_hom->fwd22;
|
2334
|
+
dxi=_hom->fwd[0][1-_dir]*_f->size[1-_dir];
|
2335
|
+
dyi=_hom->fwd[1][1-_dir]*_f->size[1-_dir];
|
2336
|
+
dwi=_hom->fwd[2][1-_dir]*_f->size[1-_dir];
|
2337
|
+
dxj=_hom->fwd[0][_dir]*_f->size[_dir];
|
2338
|
+
dyj=_hom->fwd[1][_dir]*_f->size[_dir];
|
2339
|
+
dwj=_hom->fwd[2][_dir]*_f->size[_dir];
|
2340
|
+
for(k=i=0;i<6;i++){
|
2341
|
+
int x;
|
2342
|
+
int y;
|
2343
|
+
int w;
|
2344
|
+
x=x0;
|
2345
|
+
y=y0;
|
2346
|
+
w=w0;
|
2347
|
+
for(j=0;j<3;j++,k++){
|
2348
|
+
qr_point p;
|
2349
|
+
qr_hom_fproject(p,_hom,x,y,w);
|
2350
|
+
v|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
|
2351
|
+
x+=dxj;
|
2352
|
+
y+=dyj;
|
2353
|
+
w+=dwj;
|
2354
|
+
}
|
2355
|
+
x0+=dxi;
|
2356
|
+
y0+=dyi;
|
2357
|
+
w0+=dwi;
|
2358
|
+
}
|
2359
|
+
ret=bch18_6_correct(&v);
|
2360
|
+
/*TODO: I'd certainly hope the order the version bits is accessed in is
|
2361
|
+
well-defined, but I seem to have images for two different codes with the
|
2362
|
+
same version using two different orders?
|
2363
|
+
Maybe the other one is a model 1 code?
|
2364
|
+
Even if I parse the version here, I can't decode the rest of the code.
|
2365
|
+
If this is really needed, we should just re-order the bits.*/
|
2366
|
+
#if 0
|
2367
|
+
if(ret<0){
|
2368
|
+
/*17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
2369
|
+
0 3 6 9 12 15 1 4 7 10 13 16 2 5 8 11 14 17
|
2370
|
+
17 13 9 5 1 -3 10 6 2 -2 -6-10 3 -1 -5 -9-13-17*/
|
2371
|
+
v=0;
|
2372
|
+
for(k=i=0;i<3;i++){
|
2373
|
+
p[_dir]=_f->o[_dir]+_f->size[_dir]*(-5-i);
|
2374
|
+
for(j=0;j<6;j++,k++){
|
2375
|
+
qr_point q;
|
2376
|
+
p[1-_dir]=_f->o[1-_dir]+_f->size[1-_dir]*(2-j);
|
2377
|
+
qr_hom_project(q,_hom,p[0],p[1]);
|
2378
|
+
v|=qr_img_get_bit(_img,_width,_height,q[0],q[1])<<k;
|
2379
|
+
}
|
2380
|
+
}
|
2381
|
+
ret=bch18_6_correct(&v);
|
2382
|
+
}
|
2383
|
+
#endif
|
2384
|
+
return ret>=0?(int)(v>>12):ret;
|
2385
|
+
}
|
2386
|
+
|
2387
|
+
/*Reads the format info bits near the finder modules and decodes them.*/
|
2388
|
+
static int qr_finder_fmt_info_decode(qr_finder *_ul,qr_finder *_ur,
|
2389
|
+
qr_finder *_dl,const qr_hom *_hom,
|
2390
|
+
const unsigned char *_img,int _width,int _height){
|
2391
|
+
qr_point p;
|
2392
|
+
unsigned lo[2];
|
2393
|
+
unsigned hi[2];
|
2394
|
+
int u;
|
2395
|
+
int v;
|
2396
|
+
int x;
|
2397
|
+
int y;
|
2398
|
+
int w;
|
2399
|
+
int dx;
|
2400
|
+
int dy;
|
2401
|
+
int dw;
|
2402
|
+
int fmt_info[4];
|
2403
|
+
int count[4];
|
2404
|
+
int nerrs[4];
|
2405
|
+
int nfmt_info;
|
2406
|
+
int besti;
|
2407
|
+
int imax;
|
2408
|
+
int di;
|
2409
|
+
int i;
|
2410
|
+
int k;
|
2411
|
+
/*Read the bits around the UL corner.*/
|
2412
|
+
lo[0]=0;
|
2413
|
+
u=_ul->o[0]+5*_ul->size[0];
|
2414
|
+
v=_ul->o[1]-3*_ul->size[1];
|
2415
|
+
x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
|
2416
|
+
y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
|
2417
|
+
w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
|
2418
|
+
dx=_hom->fwd[0][1]*_ul->size[1];
|
2419
|
+
dy=_hom->fwd[1][1]*_ul->size[1];
|
2420
|
+
dw=_hom->fwd[2][1]*_ul->size[1];
|
2421
|
+
for(k=i=0;;i++){
|
2422
|
+
/*Skip the timing pattern row.*/
|
2423
|
+
if(i!=6){
|
2424
|
+
qr_hom_fproject(p,_hom,x,y,w);
|
2425
|
+
lo[0]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k++;
|
2426
|
+
/*Don't advance q in the last iteration... we'll start the next loop from
|
2427
|
+
the current position.*/
|
2428
|
+
if(i>=8)break;
|
2429
|
+
}
|
2430
|
+
x+=dx;
|
2431
|
+
y+=dy;
|
2432
|
+
w+=dw;
|
2433
|
+
}
|
2434
|
+
hi[0]=0;
|
2435
|
+
dx=-_hom->fwd[0][0]*_ul->size[0];
|
2436
|
+
dy=-_hom->fwd[1][0]*_ul->size[0];
|
2437
|
+
dw=-_hom->fwd[2][0]*_ul->size[0];
|
2438
|
+
while(i-->0){
|
2439
|
+
x+=dx;
|
2440
|
+
y+=dy;
|
2441
|
+
w+=dw;
|
2442
|
+
/*Skip the timing pattern column.*/
|
2443
|
+
if(i!=6){
|
2444
|
+
qr_hom_fproject(p,_hom,x,y,w);
|
2445
|
+
hi[0]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k++;
|
2446
|
+
}
|
2447
|
+
}
|
2448
|
+
/*Read the bits next to the UR corner.*/
|
2449
|
+
lo[1]=0;
|
2450
|
+
u=_ur->o[0]+3*_ur->size[0];
|
2451
|
+
v=_ur->o[1]+5*_ur->size[1];
|
2452
|
+
x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
|
2453
|
+
y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
|
2454
|
+
w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
|
2455
|
+
dx=-_hom->fwd[0][0]*_ur->size[0];
|
2456
|
+
dy=-_hom->fwd[1][0]*_ur->size[0];
|
2457
|
+
dw=-_hom->fwd[2][0]*_ur->size[0];
|
2458
|
+
for(k=0;k<8;k++){
|
2459
|
+
qr_hom_fproject(p,_hom,x,y,w);
|
2460
|
+
lo[1]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
|
2461
|
+
x+=dx;
|
2462
|
+
y+=dy;
|
2463
|
+
w+=dw;
|
2464
|
+
}
|
2465
|
+
/*Read the bits next to the DL corner.*/
|
2466
|
+
hi[1]=0;
|
2467
|
+
u=_dl->o[0]+5*_dl->size[0];
|
2468
|
+
v=_dl->o[1]-3*_dl->size[1];
|
2469
|
+
x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
|
2470
|
+
y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
|
2471
|
+
w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
|
2472
|
+
dx=_hom->fwd[0][1]*_dl->size[1];
|
2473
|
+
dy=_hom->fwd[1][1]*_dl->size[1];
|
2474
|
+
dw=_hom->fwd[2][1]*_dl->size[1];
|
2475
|
+
for(k=8;k<15;k++){
|
2476
|
+
qr_hom_fproject(p,_hom,x,y,w);
|
2477
|
+
hi[1]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
|
2478
|
+
x+=dx;
|
2479
|
+
y+=dy;
|
2480
|
+
w+=dw;
|
2481
|
+
}
|
2482
|
+
/*For the 8th bit we have 3 samples... use the majority value.
|
2483
|
+
TODO: The DL bit appears to be wrong as much as right? Guess it's not
|
2484
|
+
really a third copy after all, but doesn't appear to be used for data.
|
2485
|
+
i=((lo[0]>>7&1)+(lo[1]>>7&1)+(hi[1]>>7&1)>>1)<<7;
|
2486
|
+
lo[0]=lo[0]&~0x80|i;
|
2487
|
+
lo[1]=lo[1]&~0x80|i;
|
2488
|
+
hi[1]&=~0x80;*/
|
2489
|
+
/*For the remaining bits we have two samples... try them in all
|
2490
|
+
combinations and pick the most popular valid code, breaking ties using
|
2491
|
+
the number of bit errors.*/
|
2492
|
+
imax=2<<(hi[0]!=hi[1]);
|
2493
|
+
di=1+(lo[0]==lo[1]);
|
2494
|
+
nfmt_info=0;
|
2495
|
+
for(i=0;i<imax;i+=di){
|
2496
|
+
unsigned v;
|
2497
|
+
int ret;
|
2498
|
+
int j;
|
2499
|
+
v=(lo[i&1]|hi[i>>1])^0x5412;
|
2500
|
+
ret=bch15_5_correct(&v);
|
2501
|
+
v>>=10;
|
2502
|
+
if(ret<0)ret=4;
|
2503
|
+
for(j=0;;j++){
|
2504
|
+
if(j>=nfmt_info){
|
2505
|
+
fmt_info[j]=v;
|
2506
|
+
count[j]=1;
|
2507
|
+
nerrs[j]=ret;
|
2508
|
+
nfmt_info++;
|
2509
|
+
break;
|
2510
|
+
}
|
2511
|
+
if(fmt_info[j]==(int)v){
|
2512
|
+
count[j]++;
|
2513
|
+
if(ret<nerrs[j])nerrs[j]=ret;
|
2514
|
+
break;
|
2515
|
+
}
|
2516
|
+
}
|
2517
|
+
}
|
2518
|
+
besti=0;
|
2519
|
+
for(i=1;i<nfmt_info;i++){
|
2520
|
+
if(nerrs[besti]>3&&nerrs[i]<=3||
|
2521
|
+
count[i]>count[besti]||count[i]==count[besti]&&nerrs[i]<nerrs[besti]){
|
2522
|
+
besti=i;
|
2523
|
+
}
|
2524
|
+
}
|
2525
|
+
return nerrs[besti]<4?fmt_info[besti]:-1;
|
2526
|
+
}
|
2527
|
+
|
2528
|
+
|
2529
|
+
|
2530
|
+
/*The grid used to sample the image bits.
|
2531
|
+
The grid is divided into separate cells bounded by finder patterns and/or
|
2532
|
+
alignment patterns, and a separate map back to the original image is
|
2533
|
+
constructed for each cell.
|
2534
|
+
All of these structural elements, as well as the timing patterns, version
|
2535
|
+
info, and format info, are marked in fpmask so they can easily be skipped
|
2536
|
+
during decode.*/
|
2537
|
+
struct qr_sampling_grid{
|
2538
|
+
qr_hom_cell *cells[6];
|
2539
|
+
unsigned *fpmask;
|
2540
|
+
int cell_limits[6];
|
2541
|
+
int ncells;
|
2542
|
+
};
|
2543
|
+
|
2544
|
+
|
2545
|
+
/*Mark a given region as belonging to the function pattern.*/
|
2546
|
+
static void qr_sampling_grid_fp_mask_rect(qr_sampling_grid *_grid,int _dim,
|
2547
|
+
int _u,int _v,int _w,int _h){
|
2548
|
+
int i;
|
2549
|
+
int j;
|
2550
|
+
int stride;
|
2551
|
+
stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
|
2552
|
+
/*Note that we store bits column-wise, since that's how they're read out of
|
2553
|
+
the grid.*/
|
2554
|
+
for(j=_u;j<_u+_w;j++)for(i=_v;i<_v+_h;i++){
|
2555
|
+
_grid->fpmask[j*stride+(i>>QR_INT_LOGBITS)]|=1<<(i&QR_INT_BITS-1);
|
2556
|
+
}
|
2557
|
+
}
|
2558
|
+
|
2559
|
+
/*Determine if a given grid location is inside the function pattern.*/
|
2560
|
+
static int qr_sampling_grid_is_in_fp(const qr_sampling_grid *_grid,int _dim,
|
2561
|
+
int _u,int _v){
|
2562
|
+
return _grid->fpmask[_u*(_dim+QR_INT_BITS-1>>QR_INT_LOGBITS)
|
2563
|
+
+(_v>>QR_INT_LOGBITS)]>>(_v&QR_INT_BITS-1)&1;
|
2564
|
+
}
|
2565
|
+
|
2566
|
+
/*The spacing between alignment patterns after the second for versions >= 7.
|
2567
|
+
We could compact this more, but the code to access it would eliminate the
|
2568
|
+
gains.*/
|
2569
|
+
static const unsigned char QR_ALIGNMENT_SPACING[34]={
|
2570
|
+
16,18,20,22,24,26,28,
|
2571
|
+
20,22,24,24,26,28,28,
|
2572
|
+
22,24,24,26,26,28,28,
|
2573
|
+
24,24,26,26,26,28,28,
|
2574
|
+
24,26,26,26,28,28
|
2575
|
+
};
|
2576
|
+
|
2577
|
+
static inline void qr_svg_points(const char *cls,
|
2578
|
+
qr_point *p,
|
2579
|
+
int n)
|
2580
|
+
{
|
2581
|
+
int i;
|
2582
|
+
svg_path_start(cls, 1, 0, 0);
|
2583
|
+
for(i = 0; i < n; i++, p++)
|
2584
|
+
svg_path_moveto(SVG_ABS, p[0][0], p[0][1]);
|
2585
|
+
svg_path_end();
|
2586
|
+
}
|
2587
|
+
|
2588
|
+
/*Initialize the sampling grid for each region of the code.
|
2589
|
+
_version: The (decoded) version number.
|
2590
|
+
_ul_pos: The location of the UL finder pattern.
|
2591
|
+
_ur_pos: The location of the UR finder pattern.
|
2592
|
+
_dl_pos: The location of the DL finder pattern.
|
2593
|
+
_p: On input, contains estimated positions of the four corner modules.
|
2594
|
+
On output, contains a bounding quadrilateral for the code.
|
2595
|
+
_img: The binary input image.
|
2596
|
+
_width: The width of the input image.
|
2597
|
+
_height: The height of the input image.
|
2598
|
+
Return: 0 on success, or a negative value on error.*/
|
2599
|
+
static void qr_sampling_grid_init(qr_sampling_grid *_grid,int _version,
|
2600
|
+
const qr_point _ul_pos,const qr_point _ur_pos,const qr_point _dl_pos,
|
2601
|
+
qr_point _p[4],const unsigned char *_img,int _width,int _height){
|
2602
|
+
qr_hom_cell base_cell;
|
2603
|
+
int align_pos[7];
|
2604
|
+
int dim;
|
2605
|
+
int nalign;
|
2606
|
+
int i;
|
2607
|
+
dim=17+(_version<<2);
|
2608
|
+
nalign=(_version/7)+2;
|
2609
|
+
/*Create a base cell to bootstrap the alignment pattern search.*/
|
2610
|
+
qr_hom_cell_init(&base_cell,0,0,dim-1,0,0,dim-1,dim-1,dim-1,
|
2611
|
+
_p[0][0],_p[0][1],_p[1][0],_p[1][1],_p[2][0],_p[2][1],_p[3][0],_p[3][1]);
|
2612
|
+
/*Allocate the array of cells.*/
|
2613
|
+
_grid->ncells=nalign-1;
|
2614
|
+
_grid->cells[0]=(qr_hom_cell *)malloc(
|
2615
|
+
(nalign-1)*(nalign-1)*sizeof(*_grid->cells[0]));
|
2616
|
+
for(i=1;i<_grid->ncells;i++)_grid->cells[i]=_grid->cells[i-1]+_grid->ncells;
|
2617
|
+
/*Initialize the function pattern mask.*/
|
2618
|
+
_grid->fpmask=(unsigned *)calloc(dim,
|
2619
|
+
(dim+QR_INT_BITS-1>>QR_INT_LOGBITS)*sizeof(*_grid->fpmask));
|
2620
|
+
/*Mask out the finder patterns (and separators and format info bits).*/
|
2621
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,0,0,9,9);
|
2622
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,0,dim-8,9,8);
|
2623
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,dim-8,0,8,9);
|
2624
|
+
/*Mask out the version number bits.*/
|
2625
|
+
if(_version>6){
|
2626
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,0,dim-11,6,3);
|
2627
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,dim-11,0,3,6);
|
2628
|
+
}
|
2629
|
+
/*Mask out the timing patterns.*/
|
2630
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,9,6,dim-17,1);
|
2631
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,6,9,1,dim-17);
|
2632
|
+
/*If we have no alignment patterns (e.g., this is a version 1 code), just use
|
2633
|
+
the base cell and hope it's good enough.*/
|
2634
|
+
if(_version<2)memcpy(_grid->cells[0],&base_cell,sizeof(base_cell));
|
2635
|
+
else{
|
2636
|
+
qr_point *q;
|
2637
|
+
qr_point *p;
|
2638
|
+
int j;
|
2639
|
+
int k;
|
2640
|
+
q=(qr_point *)malloc(nalign*nalign*sizeof(*q));
|
2641
|
+
p=(qr_point *)malloc(nalign*nalign*sizeof(*p));
|
2642
|
+
/*Initialize the alignment pattern position list.*/
|
2643
|
+
align_pos[0]=6;
|
2644
|
+
align_pos[nalign-1]=dim-7;
|
2645
|
+
if(_version>6){
|
2646
|
+
int d;
|
2647
|
+
d=QR_ALIGNMENT_SPACING[_version-7];
|
2648
|
+
for(i=nalign-1;i-->1;)align_pos[i]=align_pos[i+1]-d;
|
2649
|
+
}
|
2650
|
+
/*Three of the corners use a finder pattern instead of a separate
|
2651
|
+
alignment pattern.*/
|
2652
|
+
q[0][0]=3;
|
2653
|
+
q[0][1]=3;
|
2654
|
+
p[0][0]=_ul_pos[0];
|
2655
|
+
p[0][1]=_ul_pos[1];
|
2656
|
+
q[nalign-1][0]=dim-4;
|
2657
|
+
q[nalign-1][1]=3;
|
2658
|
+
p[nalign-1][0]=_ur_pos[0];
|
2659
|
+
p[nalign-1][1]=_ur_pos[1];
|
2660
|
+
q[(nalign-1)*nalign][0]=3;
|
2661
|
+
q[(nalign-1)*nalign][1]=dim-4;
|
2662
|
+
p[(nalign-1)*nalign][0]=_dl_pos[0];
|
2663
|
+
p[(nalign-1)*nalign][1]=_dl_pos[1];
|
2664
|
+
/*Scan for alignment patterns using a diagonal sweep.*/
|
2665
|
+
for(k=1;k<2*nalign-1;k++){
|
2666
|
+
int jmin;
|
2667
|
+
int jmax;
|
2668
|
+
jmax=QR_MINI(k,nalign-1)-(k==nalign-1);
|
2669
|
+
jmin=QR_MAXI(0,k-(nalign-1))+(k==nalign-1);
|
2670
|
+
for(j=jmin;j<=jmax;j++){
|
2671
|
+
qr_hom_cell *cell;
|
2672
|
+
int u;
|
2673
|
+
int v;
|
2674
|
+
int k;
|
2675
|
+
i=jmax-(j-jmin);
|
2676
|
+
k=i*nalign+j;
|
2677
|
+
u=align_pos[j];
|
2678
|
+
v=align_pos[i];
|
2679
|
+
q[k][0]=u;
|
2680
|
+
q[k][1]=v;
|
2681
|
+
/*Mask out the alignment pattern.*/
|
2682
|
+
qr_sampling_grid_fp_mask_rect(_grid,dim,u-2,v-2,5,5);
|
2683
|
+
/*Pick a cell to use to govern the alignment pattern search.*/
|
2684
|
+
if(i>1&&j>1){
|
2685
|
+
qr_point p0;
|
2686
|
+
qr_point p1;
|
2687
|
+
qr_point p2;
|
2688
|
+
/*Each predictor is basically a straight-line extrapolation from two
|
2689
|
+
neighboring alignment patterns (except possibly near the opposing
|
2690
|
+
finder patterns).*/
|
2691
|
+
qr_hom_cell_project(p0,_grid->cells[i-2]+j-1,u,v,0);
|
2692
|
+
qr_hom_cell_project(p1,_grid->cells[i-2]+j-2,u,v,0);
|
2693
|
+
qr_hom_cell_project(p2,_grid->cells[i-1]+j-2,u,v,0);
|
2694
|
+
/*Take the median of the predictions as the search center.*/
|
2695
|
+
QR_SORT2I(p0[0],p1[0]);
|
2696
|
+
QR_SORT2I(p0[1],p1[1]);
|
2697
|
+
QR_SORT2I(p1[0],p2[0]);
|
2698
|
+
QR_SORT2I(p1[1],p2[1]);
|
2699
|
+
QR_SORT2I(p0[0],p1[0]);
|
2700
|
+
QR_SORT2I(p0[1],p1[1]);
|
2701
|
+
/*We need a cell that has the target point at a known (u,v) location.
|
2702
|
+
Since our cells don't have inverses, just construct one from our
|
2703
|
+
neighboring points.*/
|
2704
|
+
cell=_grid->cells[i-1]+j-1;
|
2705
|
+
qr_hom_cell_init(cell,
|
2706
|
+
q[k-nalign-1][0],q[k-nalign-1][1],q[k-nalign][0],q[k-nalign][1],
|
2707
|
+
q[k-1][0],q[k-1][1],q[k][0],q[k][1],
|
2708
|
+
p[k-nalign-1][0],p[k-nalign-1][1],p[k-nalign][0],p[k-nalign][1],
|
2709
|
+
p[k-1][0],p[k-1][1],p1[0],p1[1]);
|
2710
|
+
}
|
2711
|
+
else if(i>1&&j>0)cell=_grid->cells[i-2]+j-1;
|
2712
|
+
else if(i>0&&j>1)cell=_grid->cells[i-1]+j-2;
|
2713
|
+
else cell=&base_cell;
|
2714
|
+
/*Use a very small search radius.
|
2715
|
+
A large displacement here usually means a false positive (e.g., when
|
2716
|
+
the real alignment pattern is damaged or missing), which can
|
2717
|
+
severely distort the projection.*/
|
2718
|
+
qr_alignment_pattern_search(p[k],cell,u,v,2,_img,_width,_height);
|
2719
|
+
if(i>0&&j>0){
|
2720
|
+
qr_hom_cell_init(_grid->cells[i-1]+j-1,
|
2721
|
+
q[k-nalign-1][0],q[k-nalign-1][1],q[k-nalign][0],q[k-nalign][1],
|
2722
|
+
q[k-1][0],q[k-1][1],q[k][0],q[k][1],
|
2723
|
+
p[k-nalign-1][0],p[k-nalign-1][1],p[k-nalign][0],p[k-nalign][1],
|
2724
|
+
p[k-1][0],p[k-1][1],p[k][0],p[k][1]);
|
2725
|
+
}
|
2726
|
+
}
|
2727
|
+
}
|
2728
|
+
qr_svg_points("align", p, nalign * nalign);
|
2729
|
+
free(q);
|
2730
|
+
free(p);
|
2731
|
+
}
|
2732
|
+
/*Set the limits over which each cell is used.*/
|
2733
|
+
memcpy(_grid->cell_limits,align_pos+1,
|
2734
|
+
(_grid->ncells-1)*sizeof(*_grid->cell_limits));
|
2735
|
+
_grid->cell_limits[_grid->ncells-1]=dim;
|
2736
|
+
/*Produce a bounding square for the code (to mark finder centers with).
|
2737
|
+
Because of non-linear distortion, this might not actually bound the code,
|
2738
|
+
but it should be good enough.
|
2739
|
+
I don't think it's worth computing a convex hull or anything silly like
|
2740
|
+
that.*/
|
2741
|
+
qr_hom_cell_project(_p[0],_grid->cells[0]+0,-1,-1,1);
|
2742
|
+
qr_hom_cell_project(_p[1],_grid->cells[0]+_grid->ncells-1,(dim<<1)-1,-1,1);
|
2743
|
+
qr_hom_cell_project(_p[2],_grid->cells[_grid->ncells-1]+0,-1,(dim<<1)-1,1);
|
2744
|
+
qr_hom_cell_project(_p[3],_grid->cells[_grid->ncells-1]+_grid->ncells-1,
|
2745
|
+
(dim<<1)-1,(dim<<1)-1,1);
|
2746
|
+
/*Clamp the points somewhere near the image (this is really just in case a
|
2747
|
+
corner is near the plane at infinity).*/
|
2748
|
+
for(i=0;i<4;i++){
|
2749
|
+
_p[i][0]=QR_CLAMPI(-_width<<QR_FINDER_SUBPREC,_p[i][0],
|
2750
|
+
_width<<QR_FINDER_SUBPREC+1);
|
2751
|
+
_p[i][1]=QR_CLAMPI(-_height<<QR_FINDER_SUBPREC,_p[i][1],
|
2752
|
+
_height<<QR_FINDER_SUBPREC+1);
|
2753
|
+
}
|
2754
|
+
/*TODO: Make fine adjustments using the timing patterns.
|
2755
|
+
Possible strategy: scan the timing pattern at QR_ALIGN_SUBPREC (or finer)
|
2756
|
+
resolution, use dynamic programming to match midpoints between
|
2757
|
+
transitions to the ideal grid locations.*/
|
2758
|
+
}
|
2759
|
+
|
2760
|
+
static void qr_sampling_grid_clear(qr_sampling_grid *_grid){
|
2761
|
+
free(_grid->fpmask);
|
2762
|
+
free(_grid->cells[0]);
|
2763
|
+
}
|
2764
|
+
|
2765
|
+
|
2766
|
+
|
2767
|
+
#if defined(QR_DEBUG)
|
2768
|
+
static void qr_sampling_grid_dump(qr_sampling_grid *_grid,int _version,
|
2769
|
+
const unsigned char *_img,int _width,int _height){
|
2770
|
+
unsigned char *gimg;
|
2771
|
+
FILE *fout;
|
2772
|
+
int dim;
|
2773
|
+
int u;
|
2774
|
+
int v;
|
2775
|
+
int x;
|
2776
|
+
int y;
|
2777
|
+
int w;
|
2778
|
+
int i;
|
2779
|
+
int j;
|
2780
|
+
int r;
|
2781
|
+
int s;
|
2782
|
+
dim=17+(_version<<2)+8<<QR_ALIGN_SUBPREC;
|
2783
|
+
gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
|
2784
|
+
for(i=0;i<dim;i++)for(j=0;j<dim;j++){
|
2785
|
+
qr_hom_cell *cell;
|
2786
|
+
if(i>=(4<<QR_ALIGN_SUBPREC)&&i<=dim-(5<<QR_ALIGN_SUBPREC)&&
|
2787
|
+
j>=(4<<QR_ALIGN_SUBPREC)&&j<=dim-(5<<QR_ALIGN_SUBPREC)&&
|
2788
|
+
((!(i&(1<<QR_ALIGN_SUBPREC)-1))^(!(j&(1<<QR_ALIGN_SUBPREC)-1)))){
|
2789
|
+
gimg[i*dim+j]=0x7F;
|
2790
|
+
}
|
2791
|
+
else{
|
2792
|
+
qr_point p;
|
2793
|
+
u=(j>>QR_ALIGN_SUBPREC)-4;
|
2794
|
+
v=(i>>QR_ALIGN_SUBPREC)-4;
|
2795
|
+
for(r=0;r<_grid->ncells-1;r++)if(u<_grid->cell_limits[r])break;
|
2796
|
+
for(s=0;s<_grid->ncells-1;s++)if(v<_grid->cell_limits[s])break;
|
2797
|
+
cell=_grid->cells[s]+r;
|
2798
|
+
u=j-(cell->u0+4<<QR_ALIGN_SUBPREC);
|
2799
|
+
v=i-(cell->v0+4<<QR_ALIGN_SUBPREC);
|
2800
|
+
x=cell->fwd[0][0]*u+cell->fwd[0][1]*v+(cell->fwd[0][2]<<QR_ALIGN_SUBPREC);
|
2801
|
+
y=cell->fwd[1][0]*u+cell->fwd[1][1]*v+(cell->fwd[1][2]<<QR_ALIGN_SUBPREC);
|
2802
|
+
w=cell->fwd[2][0]*u+cell->fwd[2][1]*v+(cell->fwd[2][2]<<QR_ALIGN_SUBPREC);
|
2803
|
+
qr_hom_cell_fproject(p,cell,x,y,w);
|
2804
|
+
gimg[i*dim+j]=_img[
|
2805
|
+
QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
|
2806
|
+
QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
|
2807
|
+
}
|
2808
|
+
}
|
2809
|
+
for(v=0;v<17+(_version<<2);v++)for(u=0;u<17+(_version<<2);u++){
|
2810
|
+
if(qr_sampling_grid_is_in_fp(_grid,17+(_version<<2),u,v)){
|
2811
|
+
j=u+4<<QR_ALIGN_SUBPREC;
|
2812
|
+
i=v+4<<QR_ALIGN_SUBPREC;
|
2813
|
+
gimg[(i-1)*dim+j-1]=0x7F;
|
2814
|
+
gimg[(i-1)*dim+j]=0x7F;
|
2815
|
+
gimg[(i-1)*dim+j+1]=0x7F;
|
2816
|
+
gimg[i*dim+j-1]=0x7F;
|
2817
|
+
gimg[i*dim+j+1]=0x7F;
|
2818
|
+
gimg[(i+1)*dim+j-1]=0x7F;
|
2819
|
+
gimg[(i+1)*dim+j]=0x7F;
|
2820
|
+
gimg[(i+1)*dim+j+1]=0x7F;
|
2821
|
+
}
|
2822
|
+
}
|
2823
|
+
fout=fopen("grid.png","wb");
|
2824
|
+
image_write_png(gimg,dim,dim,fout);
|
2825
|
+
fclose(fout);
|
2826
|
+
free(gimg);
|
2827
|
+
}
|
2828
|
+
#endif
|
2829
|
+
|
2830
|
+
/*Generate the data mask corresponding to the given mask pattern.*/
|
2831
|
+
static void qr_data_mask_fill(unsigned *_mask,int _dim,int _pattern){
|
2832
|
+
int stride;
|
2833
|
+
int i;
|
2834
|
+
int j;
|
2835
|
+
stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
|
2836
|
+
/*Note that we store bits column-wise, since that's how they're read out of
|
2837
|
+
the grid.*/
|
2838
|
+
switch(_pattern){
|
2839
|
+
/*10101010 i+j+1&1
|
2840
|
+
01010101
|
2841
|
+
10101010
|
2842
|
+
01010101*/
|
2843
|
+
case 0:{
|
2844
|
+
int m;
|
2845
|
+
m=0x55;
|
2846
|
+
for(j=0;j<_dim;j++){
|
2847
|
+
memset(_mask+j*stride,m,stride*sizeof(*_mask));
|
2848
|
+
m^=0xFF;
|
2849
|
+
}
|
2850
|
+
}break;
|
2851
|
+
/*11111111 i+1&1
|
2852
|
+
00000000
|
2853
|
+
11111111
|
2854
|
+
00000000*/
|
2855
|
+
case 1:memset(_mask,0x55,_dim*stride*sizeof(*_mask));break;
|
2856
|
+
/*10010010 (j+1)%3&1
|
2857
|
+
10010010
|
2858
|
+
10010010
|
2859
|
+
10010010*/
|
2860
|
+
case 2:{
|
2861
|
+
unsigned m;
|
2862
|
+
m=0xFF;
|
2863
|
+
for(j=0;j<_dim;j++){
|
2864
|
+
memset(_mask+j*stride,m&0xFF,stride*sizeof(*_mask));
|
2865
|
+
m=m<<8|m>>16;
|
2866
|
+
}
|
2867
|
+
}break;
|
2868
|
+
/*10010010 (i+j+1)%3&1
|
2869
|
+
00100100
|
2870
|
+
01001001
|
2871
|
+
10010010*/
|
2872
|
+
case 3:{
|
2873
|
+
unsigned mi;
|
2874
|
+
unsigned mj;
|
2875
|
+
mj=0;
|
2876
|
+
for(i=0;i<(QR_INT_BITS+2)/3;i++)mj|=1<<3*i;
|
2877
|
+
for(j=0;j<_dim;j++){
|
2878
|
+
mi=mj;
|
2879
|
+
for(i=0;i<stride;i++){
|
2880
|
+
_mask[j*stride+i]=mi;
|
2881
|
+
mi=mi>>QR_INT_BITS%3|mi<<3-QR_INT_BITS%3;
|
2882
|
+
}
|
2883
|
+
mj=mj>>1|mj<<2;
|
2884
|
+
}
|
2885
|
+
}break;
|
2886
|
+
/*11100011 (i>>1)+(j/3)+1&1
|
2887
|
+
11100011
|
2888
|
+
00011100
|
2889
|
+
00011100*/
|
2890
|
+
case 4:{
|
2891
|
+
unsigned m;
|
2892
|
+
m=7;
|
2893
|
+
for(j=0;j<_dim;j++){
|
2894
|
+
memset(_mask+j*stride,(0xCC^-(m&1))&0xFF,stride*sizeof(*_mask));
|
2895
|
+
m=m>>1|m<<5;
|
2896
|
+
}
|
2897
|
+
}break;
|
2898
|
+
/*11111111 !((i*j)%6)
|
2899
|
+
10000010
|
2900
|
+
10010010
|
2901
|
+
10101010*/
|
2902
|
+
case 5:{
|
2903
|
+
for(j=0;j<_dim;j++){
|
2904
|
+
unsigned m;
|
2905
|
+
m=0;
|
2906
|
+
for(i=0;i<6;i++)m|=!((i*j)%6)<<i;
|
2907
|
+
for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
|
2908
|
+
for(i=0;i<stride;i++){
|
2909
|
+
_mask[j*stride+i]=m;
|
2910
|
+
m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
|
2911
|
+
}
|
2912
|
+
}
|
2913
|
+
}break;
|
2914
|
+
/*11111111 (i*j)%3+i*j+1&1
|
2915
|
+
11100011
|
2916
|
+
11011011
|
2917
|
+
10101010*/
|
2918
|
+
case 6:{
|
2919
|
+
for(j=0;j<_dim;j++){
|
2920
|
+
unsigned m;
|
2921
|
+
m=0;
|
2922
|
+
for(i=0;i<6;i++)m|=((i*j)%3+i*j+1&1)<<i;
|
2923
|
+
for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
|
2924
|
+
for(i=0;i<stride;i++){
|
2925
|
+
_mask[j*stride+i]=m;
|
2926
|
+
m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
|
2927
|
+
}
|
2928
|
+
}
|
2929
|
+
}break;
|
2930
|
+
/*10101010 (i*j)%3+i+j+1&1
|
2931
|
+
00011100
|
2932
|
+
10001110
|
2933
|
+
01010101*/
|
2934
|
+
default:{
|
2935
|
+
for(j=0;j<_dim;j++){
|
2936
|
+
unsigned m;
|
2937
|
+
m=0;
|
2938
|
+
for(i=0;i<6;i++)m|=((i*j)%3+i+j+1&1)<<i;
|
2939
|
+
for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
|
2940
|
+
for(i=0;i<stride;i++){
|
2941
|
+
_mask[j*stride+i]=m;
|
2942
|
+
m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
|
2943
|
+
}
|
2944
|
+
}
|
2945
|
+
}break;
|
2946
|
+
}
|
2947
|
+
}
|
2948
|
+
|
2949
|
+
static void qr_sampling_grid_sample(const qr_sampling_grid *_grid,
|
2950
|
+
unsigned *_data_bits,int _dim,int _fmt_info,
|
2951
|
+
const unsigned char *_img,int _width,int _height){
|
2952
|
+
int stride;
|
2953
|
+
int u0;
|
2954
|
+
int u1;
|
2955
|
+
int j;
|
2956
|
+
/*We initialize the buffer with the data mask and XOR bits into it as we read
|
2957
|
+
them out of the image instead of unmasking in a separate step.*/
|
2958
|
+
qr_data_mask_fill(_data_bits,_dim,_fmt_info&7);
|
2959
|
+
stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
|
2960
|
+
u0=0;
|
2961
|
+
svg_path_start("sampling-grid", 1, 0, 0);
|
2962
|
+
/*We read data cell-by-cell to avoid having to constantly change which
|
2963
|
+
projection we're using as we read each bit.
|
2964
|
+
This (and the position-dependent data mask) is the reason we buffer the
|
2965
|
+
bits we read instead of converting them directly to codewords here.
|
2966
|
+
Note that bits are stored column-wise, since that's how we'll scan them.*/
|
2967
|
+
for(j=0;j<_grid->ncells;j++){
|
2968
|
+
int i;
|
2969
|
+
int v0;
|
2970
|
+
int v1;
|
2971
|
+
u1=_grid->cell_limits[j];
|
2972
|
+
v0=0;
|
2973
|
+
for(i=0;i<_grid->ncells;i++){
|
2974
|
+
qr_hom_cell *cell;
|
2975
|
+
int x0;
|
2976
|
+
int y0;
|
2977
|
+
int w0;
|
2978
|
+
int u;
|
2979
|
+
int du;
|
2980
|
+
int dv;
|
2981
|
+
v1=_grid->cell_limits[i];
|
2982
|
+
cell=_grid->cells[i]+j;
|
2983
|
+
du=u0-cell->u0;
|
2984
|
+
dv=v0-cell->v0;
|
2985
|
+
x0=cell->fwd[0][0]*du+cell->fwd[0][1]*dv+cell->fwd[0][2];
|
2986
|
+
y0=cell->fwd[1][0]*du+cell->fwd[1][1]*dv+cell->fwd[1][2];
|
2987
|
+
w0=cell->fwd[2][0]*du+cell->fwd[2][1]*dv+cell->fwd[2][2];
|
2988
|
+
for(u=u0;u<u1;u++){
|
2989
|
+
int x;
|
2990
|
+
int y;
|
2991
|
+
int w;
|
2992
|
+
int v;
|
2993
|
+
x=x0;
|
2994
|
+
y=y0;
|
2995
|
+
w=w0;
|
2996
|
+
for(v=v0;v<v1;v++){
|
2997
|
+
/*Skip doing all the divisions and bounds checks if the bit is in the
|
2998
|
+
function pattern.*/
|
2999
|
+
if(!qr_sampling_grid_is_in_fp(_grid,_dim,u,v)){
|
3000
|
+
qr_point p;
|
3001
|
+
qr_hom_cell_fproject(p,cell,x,y,w);
|
3002
|
+
_data_bits[u*stride+(v>>QR_INT_LOGBITS)]^=
|
3003
|
+
qr_img_get_bit(_img,_width,_height,p[0],p[1])<<(v&QR_INT_BITS-1);
|
3004
|
+
svg_path_moveto(SVG_ABS, p[0], p[1]);
|
3005
|
+
}
|
3006
|
+
x+=cell->fwd[0][1];
|
3007
|
+
y+=cell->fwd[1][1];
|
3008
|
+
w+=cell->fwd[2][1];
|
3009
|
+
}
|
3010
|
+
x0+=cell->fwd[0][0];
|
3011
|
+
y0+=cell->fwd[1][0];
|
3012
|
+
w0+=cell->fwd[2][0];
|
3013
|
+
}
|
3014
|
+
v0=v1;
|
3015
|
+
}
|
3016
|
+
u0=u1;
|
3017
|
+
}
|
3018
|
+
svg_path_end();
|
3019
|
+
}
|
3020
|
+
|
3021
|
+
/*Arranges the sample bits read by qr_sampling_grid_sample() into bytes and
|
3022
|
+
groups those bytes into Reed-Solomon blocks.
|
3023
|
+
The individual block pointers are destroyed by this routine.*/
|
3024
|
+
static void qr_samples_unpack(unsigned char **_blocks,int _nblocks,
|
3025
|
+
int _nshort_data,int _nshort_blocks,const unsigned *_data_bits,
|
3026
|
+
const unsigned *_fp_mask,int _dim){
|
3027
|
+
unsigned bits;
|
3028
|
+
int biti;
|
3029
|
+
int stride;
|
3030
|
+
int blocki;
|
3031
|
+
int blockj;
|
3032
|
+
int i;
|
3033
|
+
int j;
|
3034
|
+
stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
|
3035
|
+
/*If _all_ the blocks are short, don't skip anything (see below).*/
|
3036
|
+
if(_nshort_blocks>=_nblocks)_nshort_blocks=0;
|
3037
|
+
/*Scan columns in pairs from right to left.*/
|
3038
|
+
bits=0;
|
3039
|
+
for(blocki=blockj=biti=0,j=_dim-1;j>0;j-=2){
|
3040
|
+
unsigned data1;
|
3041
|
+
unsigned data2;
|
3042
|
+
unsigned fp_mask1;
|
3043
|
+
unsigned fp_mask2;
|
3044
|
+
int nbits;
|
3045
|
+
int l;
|
3046
|
+
/*Scan up a pair of columns.*/
|
3047
|
+
nbits=(_dim-1&QR_INT_BITS-1)+1;
|
3048
|
+
l=j*stride;
|
3049
|
+
for(i=stride;i-->0;){
|
3050
|
+
data1=_data_bits[l+i];
|
3051
|
+
fp_mask1=_fp_mask[l+i];
|
3052
|
+
data2=_data_bits[l+i-stride];
|
3053
|
+
fp_mask2=_fp_mask[l+i-stride];
|
3054
|
+
while(nbits-->0){
|
3055
|
+
/*Pull a bit from the right column.*/
|
3056
|
+
if(!(fp_mask1>>nbits&1)){
|
3057
|
+
bits=bits<<1|data1>>nbits&1;
|
3058
|
+
biti++;
|
3059
|
+
}
|
3060
|
+
/*Pull a bit from the left column.*/
|
3061
|
+
if(!(fp_mask2>>nbits&1)){
|
3062
|
+
bits=bits<<1|data2>>nbits&1;
|
3063
|
+
biti++;
|
3064
|
+
}
|
3065
|
+
/*If we finished a byte, drop it in a block.*/
|
3066
|
+
if(biti>=8){
|
3067
|
+
biti-=8;
|
3068
|
+
*_blocks[blocki++]++=(unsigned char)(bits>>biti);
|
3069
|
+
/*For whatever reason, the long blocks are at the _end_ of the list,
|
3070
|
+
instead of the beginning.
|
3071
|
+
Even worse, the extra bytes they get come at the end of the data
|
3072
|
+
bytes, before the parity bytes.
|
3073
|
+
Hence the logic here: when we've filled up the data portion of the
|
3074
|
+
short blocks, skip directly to the long blocks for the next byte.
|
3075
|
+
It's also the reason we increment _blocks[blocki] on each store,
|
3076
|
+
instead of just indexing with blockj (after this iteration the
|
3077
|
+
number of bytes in each block differs).*/
|
3078
|
+
if(blocki>=_nblocks)blocki=++blockj==_nshort_data?_nshort_blocks:0;
|
3079
|
+
}
|
3080
|
+
}
|
3081
|
+
nbits=QR_INT_BITS;
|
3082
|
+
}
|
3083
|
+
j-=2;
|
3084
|
+
/*Skip the column with the vertical timing pattern.*/
|
3085
|
+
if(j==6)j--;
|
3086
|
+
/*Scan down a pair of columns.*/
|
3087
|
+
l=j*stride;
|
3088
|
+
for(i=0;i<stride;i++){
|
3089
|
+
data1=_data_bits[l+i];
|
3090
|
+
fp_mask1=_fp_mask[l+i];
|
3091
|
+
data2=_data_bits[l+i-stride];
|
3092
|
+
fp_mask2=_fp_mask[l+i-stride];
|
3093
|
+
nbits=QR_MINI(_dim-(i<<QR_INT_LOGBITS),QR_INT_BITS);
|
3094
|
+
while(nbits-->0){
|
3095
|
+
/*Pull a bit from the right column.*/
|
3096
|
+
if(!(fp_mask1&1)){
|
3097
|
+
bits=bits<<1|data1&1;
|
3098
|
+
biti++;
|
3099
|
+
}
|
3100
|
+
data1>>=1;
|
3101
|
+
fp_mask1>>=1;
|
3102
|
+
/*Pull a bit from the left column.*/
|
3103
|
+
if(!(fp_mask2&1)){
|
3104
|
+
bits=bits<<1|data2&1;
|
3105
|
+
biti++;
|
3106
|
+
}
|
3107
|
+
data2>>=1;
|
3108
|
+
fp_mask2>>=1;
|
3109
|
+
/*If we finished a byte, drop it in a block.*/
|
3110
|
+
if(biti>=8){
|
3111
|
+
biti-=8;
|
3112
|
+
*_blocks[blocki++]++=(unsigned char)(bits>>biti);
|
3113
|
+
/*See comments on the "up" loop for the reason behind this mess.*/
|
3114
|
+
if(blocki>=_nblocks)blocki=++blockj==_nshort_data?_nshort_blocks:0;
|
3115
|
+
}
|
3116
|
+
}
|
3117
|
+
}
|
3118
|
+
}
|
3119
|
+
}
|
3120
|
+
|
3121
|
+
|
3122
|
+
/*Bit reading code blatantly stolen^W^Wadapted from libogg/libtheora (because
|
3123
|
+
I've already debugged it and I know it works).
|
3124
|
+
Portions (C) Xiph.Org Foundation 1994-2008, BSD-style license.*/
|
3125
|
+
struct qr_pack_buf{
|
3126
|
+
const unsigned char *buf;
|
3127
|
+
int endbyte;
|
3128
|
+
int endbit;
|
3129
|
+
int storage;
|
3130
|
+
};
|
3131
|
+
|
3132
|
+
|
3133
|
+
static void qr_pack_buf_init(qr_pack_buf *_b,
|
3134
|
+
const unsigned char *_data,int _ndata){
|
3135
|
+
_b->buf=_data;
|
3136
|
+
_b->storage=_ndata;
|
3137
|
+
_b->endbyte=_b->endbit=0;
|
3138
|
+
}
|
3139
|
+
|
3140
|
+
/*Assumes 0<=_bits<=16.*/
|
3141
|
+
static int qr_pack_buf_read(qr_pack_buf *_b,int _bits){
|
3142
|
+
const unsigned char *p;
|
3143
|
+
unsigned ret;
|
3144
|
+
int m;
|
3145
|
+
int d;
|
3146
|
+
m=16-_bits;
|
3147
|
+
_bits+=_b->endbit;
|
3148
|
+
d=_b->storage-_b->endbyte;
|
3149
|
+
if(d<=2){
|
3150
|
+
/*Not the main path.*/
|
3151
|
+
if(d*8<_bits){
|
3152
|
+
_b->endbyte+=_bits>>3;
|
3153
|
+
_b->endbit=_bits&7;
|
3154
|
+
return -1;
|
3155
|
+
}
|
3156
|
+
/*Special case to avoid reading p[0] below, which might be past the end of
|
3157
|
+
the buffer; also skips some useless accounting.*/
|
3158
|
+
else if(!_bits)return 0;
|
3159
|
+
}
|
3160
|
+
p=_b->buf+_b->endbyte;
|
3161
|
+
ret=p[0]<<8+_b->endbit;
|
3162
|
+
if(_bits>8){
|
3163
|
+
ret|=p[1]<<_b->endbit;
|
3164
|
+
if(_bits>16)ret|=p[2]>>8-_b->endbit;
|
3165
|
+
}
|
3166
|
+
_b->endbyte+=_bits>>3;
|
3167
|
+
_b->endbit=_bits&7;
|
3168
|
+
return (ret&0xFFFF)>>m;
|
3169
|
+
}
|
3170
|
+
|
3171
|
+
static int qr_pack_buf_avail(const qr_pack_buf *_b){
|
3172
|
+
return (_b->storage-_b->endbyte<<3)-_b->endbit;
|
3173
|
+
}
|
3174
|
+
|
3175
|
+
|
3176
|
+
/*The characters available in QR_MODE_ALNUM.*/
|
3177
|
+
static const unsigned char QR_ALNUM_TABLE[45]={
|
3178
|
+
'0','1','2','3','4','5','6','7','8','9',
|
3179
|
+
'A','B','C','D','E','F','G','H','I','J',
|
3180
|
+
'K','L','M','N','O','P','Q','R','S','T',
|
3181
|
+
'U','V','W','X','Y','Z',' ','$','%','*',
|
3182
|
+
'+','-','.','/',':'
|
3183
|
+
};
|
3184
|
+
|
3185
|
+
static int qr_code_data_parse(qr_code_data *_qrdata,int _version,
|
3186
|
+
const unsigned char *_data,int _ndata){
|
3187
|
+
qr_pack_buf qpb;
|
3188
|
+
int centries;
|
3189
|
+
int len_bits_idx;
|
3190
|
+
/*Entries are stored directly in the struct during parsing.
|
3191
|
+
Caller cleans up any allocated data on failure.*/
|
3192
|
+
_qrdata->entries=NULL;
|
3193
|
+
_qrdata->nentries=0;
|
3194
|
+
_qrdata->sa_size=0;
|
3195
|
+
centries=0;
|
3196
|
+
/*The versions are divided into 3 ranges that each use a different number of
|
3197
|
+
bits for length fields.*/
|
3198
|
+
len_bits_idx=(_version>9)+(_version>26);
|
3199
|
+
qr_pack_buf_init(&qpb,_data,_ndata);
|
3200
|
+
/*While we have enough bits to read a mode...*/
|
3201
|
+
while(qr_pack_buf_avail(&qpb)>=4){
|
3202
|
+
qr_code_data_entry *entry;
|
3203
|
+
int mode;
|
3204
|
+
mode=qr_pack_buf_read(&qpb,4);
|
3205
|
+
/*Mode 0 is a terminator.*/
|
3206
|
+
if(!mode)break;
|
3207
|
+
if(_qrdata->nentries>=centries){
|
3208
|
+
centries=centries<<1|1;
|
3209
|
+
_qrdata->entries=(qr_code_data_entry *)realloc(_qrdata->entries,
|
3210
|
+
centries*sizeof(*_qrdata->entries));
|
3211
|
+
}
|
3212
|
+
entry=_qrdata->entries+_qrdata->nentries++;
|
3213
|
+
/*Set the mode to an invalid value until we allocate a buffer for it.
|
3214
|
+
This ensures we don't try to free it on clean-up until then.*/
|
3215
|
+
entry->mode=-1;
|
3216
|
+
switch(mode){
|
3217
|
+
/*The number of bits used to encode the character count for each version
|
3218
|
+
range and each data mode.*/
|
3219
|
+
static const unsigned char LEN_BITS[3][4]={
|
3220
|
+
{10, 9, 8, 8},
|
3221
|
+
{12,11,16,10},
|
3222
|
+
{14,13,16,12}
|
3223
|
+
};
|
3224
|
+
case QR_MODE_NUM:{
|
3225
|
+
unsigned char *buf;
|
3226
|
+
unsigned bits;
|
3227
|
+
int len;
|
3228
|
+
int count;
|
3229
|
+
int rem;
|
3230
|
+
len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][0]);
|
3231
|
+
if(len<0)return -1;
|
3232
|
+
/*Check to see if there are enough bits left now, so we don't have to
|
3233
|
+
in the decode loop.*/
|
3234
|
+
count=len/3;
|
3235
|
+
rem=len%3;
|
3236
|
+
if(qr_pack_buf_avail(&qpb)<10*count+7*(rem>>1&1)+4*(rem&1))return -1;
|
3237
|
+
entry->mode=mode;
|
3238
|
+
entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
|
3239
|
+
entry->payload.data.len=len;
|
3240
|
+
/*Read groups of 3 digits encoded in 10 bits.*/
|
3241
|
+
while(count-->0){
|
3242
|
+
bits=qr_pack_buf_read(&qpb,10);
|
3243
|
+
if(bits>=1000)return -1;
|
3244
|
+
*buf++=(unsigned char)('0'+bits/100);
|
3245
|
+
bits%=100;
|
3246
|
+
*buf++=(unsigned char)('0'+bits/10);
|
3247
|
+
*buf++=(unsigned char)('0'+bits%10);
|
3248
|
+
}
|
3249
|
+
/*Read the last two digits encoded in 7 bits.*/
|
3250
|
+
if(rem>1){
|
3251
|
+
bits=qr_pack_buf_read(&qpb,7);
|
3252
|
+
if(bits>=100)return -1;
|
3253
|
+
*buf++=(unsigned char)('0'+bits/10);
|
3254
|
+
*buf++=(unsigned char)('0'+bits%10);
|
3255
|
+
}
|
3256
|
+
/*Or the last one digit encoded in 4 bits.*/
|
3257
|
+
else if(rem){
|
3258
|
+
bits=qr_pack_buf_read(&qpb,4);
|
3259
|
+
if(bits>=10)return -1;
|
3260
|
+
*buf++=(unsigned char)('0'+bits);
|
3261
|
+
}
|
3262
|
+
}break;
|
3263
|
+
case QR_MODE_ALNUM:{
|
3264
|
+
unsigned char *buf;
|
3265
|
+
unsigned bits;
|
3266
|
+
int len;
|
3267
|
+
int count;
|
3268
|
+
int rem;
|
3269
|
+
len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][1]);
|
3270
|
+
if(len<0)return -1;
|
3271
|
+
/*Check to see if there are enough bits left now, so we don't have to
|
3272
|
+
in the decode loop.*/
|
3273
|
+
count=len>>1;
|
3274
|
+
rem=len&1;
|
3275
|
+
if(qr_pack_buf_avail(&qpb)<11*count+6*rem)return -1;
|
3276
|
+
entry->mode=mode;
|
3277
|
+
entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
|
3278
|
+
entry->payload.data.len=len;
|
3279
|
+
/*Read groups of two characters encoded in 11 bits.*/
|
3280
|
+
while(count-->0){
|
3281
|
+
bits=qr_pack_buf_read(&qpb,11);
|
3282
|
+
if(bits>=2025)return -1;
|
3283
|
+
*buf++=QR_ALNUM_TABLE[bits/45];
|
3284
|
+
*buf++=QR_ALNUM_TABLE[bits%45];
|
3285
|
+
len-=2;
|
3286
|
+
}
|
3287
|
+
/*Read the last character encoded in 6 bits.*/
|
3288
|
+
if(rem){
|
3289
|
+
bits=qr_pack_buf_read(&qpb,6);
|
3290
|
+
if(bits>=45)return -1;
|
3291
|
+
*buf++=QR_ALNUM_TABLE[bits];
|
3292
|
+
}
|
3293
|
+
}break;
|
3294
|
+
/*Structured-append header.*/
|
3295
|
+
case QR_MODE_STRUCT:{
|
3296
|
+
int bits;
|
3297
|
+
entry->mode=mode;
|
3298
|
+
bits=qr_pack_buf_read(&qpb,16);
|
3299
|
+
if(bits<0)return -1;
|
3300
|
+
/*We also save a copy of the data in _qrdata for easy reference when
|
3301
|
+
grouping structured-append codes.
|
3302
|
+
If for some reason the code has multiple S-A headers, last one wins
|
3303
|
+
(TODO: should we return an error instead?).*/
|
3304
|
+
_qrdata->sa_index=entry->payload.sa.sa_index=
|
3305
|
+
(unsigned char)(bits>>12&0xF);
|
3306
|
+
_qrdata->sa_size=entry->payload.sa.sa_size=
|
3307
|
+
(unsigned char)((bits>>8&0xF)+1);
|
3308
|
+
_qrdata->sa_parity=entry->payload.sa.sa_parity=
|
3309
|
+
(unsigned char)(bits&0xFF);
|
3310
|
+
}break;
|
3311
|
+
case QR_MODE_BYTE:{
|
3312
|
+
unsigned char *buf;
|
3313
|
+
int len;
|
3314
|
+
len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][2]);
|
3315
|
+
if(len<0)return -1;
|
3316
|
+
/*Check to see if there are enough bits left now, so we don't have to
|
3317
|
+
in the decode loop.*/
|
3318
|
+
if(qr_pack_buf_avail(&qpb)<len<<3)return -1;
|
3319
|
+
entry->mode=mode;
|
3320
|
+
entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
|
3321
|
+
entry->payload.data.len=len;
|
3322
|
+
while(len-->0)*buf++=(unsigned char)qr_pack_buf_read(&qpb,8);
|
3323
|
+
}break;
|
3324
|
+
/*FNC1 first position marker.*/
|
3325
|
+
case QR_MODE_FNC1_1ST:entry->mode=mode;break;
|
3326
|
+
/*Extended Channel Interpretation data.*/
|
3327
|
+
case QR_MODE_ECI:{
|
3328
|
+
unsigned val;
|
3329
|
+
int bits;
|
3330
|
+
/*ECI uses a variable-width encoding similar to UTF-8*/
|
3331
|
+
bits=qr_pack_buf_read(&qpb,8);
|
3332
|
+
if(bits<0)return -1;
|
3333
|
+
/*One byte:*/
|
3334
|
+
if(!(bits&0x80))val=bits;
|
3335
|
+
/*Two bytes:*/
|
3336
|
+
else if(!(bits&0x40)){
|
3337
|
+
val=bits&0x3F<<8;
|
3338
|
+
bits=qr_pack_buf_read(&qpb,8);
|
3339
|
+
if(bits<0)return -1;
|
3340
|
+
val|=bits;
|
3341
|
+
}
|
3342
|
+
/*Three bytes:*/
|
3343
|
+
else if(!(bits&0x20)){
|
3344
|
+
val=bits&0x1F<<16;
|
3345
|
+
bits=qr_pack_buf_read(&qpb,16);
|
3346
|
+
if(bits<0)return -1;
|
3347
|
+
val|=bits;
|
3348
|
+
/*Valid ECI values are 0...999999.*/
|
3349
|
+
if(val>=1000000)return -1;
|
3350
|
+
}
|
3351
|
+
/*Invalid lead byte.*/
|
3352
|
+
else return -1;
|
3353
|
+
entry->mode=mode;
|
3354
|
+
entry->payload.eci=val;
|
3355
|
+
}break;
|
3356
|
+
case QR_MODE_KANJI:{
|
3357
|
+
unsigned char *buf;
|
3358
|
+
unsigned bits;
|
3359
|
+
int len;
|
3360
|
+
len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][3]);
|
3361
|
+
if(len<0)return -1;
|
3362
|
+
/*Check to see if there are enough bits left now, so we don't have to
|
3363
|
+
in the decode loop.*/
|
3364
|
+
if(qr_pack_buf_avail(&qpb)<13*len)return -1;
|
3365
|
+
entry->mode=mode;
|
3366
|
+
entry->payload.data.buf=buf=(unsigned char *)malloc(2*len*sizeof(*buf));
|
3367
|
+
entry->payload.data.len=2*len;
|
3368
|
+
/*Decode 2-byte SJIS characters encoded in 13 bits.*/
|
3369
|
+
while(len-->0){
|
3370
|
+
bits=qr_pack_buf_read(&qpb,13);
|
3371
|
+
bits=(bits/0xC0<<8|bits%0xC0)+0x8140;
|
3372
|
+
if(bits>=0xA000)bits+=0x4000;
|
3373
|
+
/*Are values 0xXX7F, 0xXXFD...0xXXFF always invalid?
|
3374
|
+
Should we reject them here?*/
|
3375
|
+
*buf++=(unsigned char)(bits>>8);
|
3376
|
+
*buf++=(unsigned char)(bits&0xFF);
|
3377
|
+
}
|
3378
|
+
}break;
|
3379
|
+
/*FNC1 second position marker.*/
|
3380
|
+
case QR_MODE_FNC1_2ND:entry->mode=mode;break;
|
3381
|
+
/*Unknown mode number:*/
|
3382
|
+
default:{
|
3383
|
+
/*Unfortunately, because we have to understand the format of a mode to
|
3384
|
+
know how many bits it occupies, we can't skip unknown modes.
|
3385
|
+
Therefore we have to fail.*/
|
3386
|
+
return -1;
|
3387
|
+
}break;
|
3388
|
+
}
|
3389
|
+
}
|
3390
|
+
/*TODO: If there was a S-A header, we should compute the parity of this
|
3391
|
+
code; how are non-data modes handled (ECI, FNC1)?*/
|
3392
|
+
_qrdata->self_parity=0;
|
3393
|
+
/*Success.*/
|
3394
|
+
_qrdata->entries=(qr_code_data_entry *)realloc(_qrdata->entries,
|
3395
|
+
_qrdata->nentries*sizeof(*_qrdata->entries));
|
3396
|
+
return 0;
|
3397
|
+
}
|
3398
|
+
|
3399
|
+
static void qr_code_data_clear(qr_code_data *_qrdata){
|
3400
|
+
int i;
|
3401
|
+
for(i=0;i<_qrdata->nentries;i++){
|
3402
|
+
if(QR_MODE_HAS_DATA(_qrdata->entries[i].mode)){
|
3403
|
+
free(_qrdata->entries[i].payload.data.buf);
|
3404
|
+
}
|
3405
|
+
}
|
3406
|
+
free(_qrdata->entries);
|
3407
|
+
}
|
3408
|
+
|
3409
|
+
|
3410
|
+
void qr_code_data_list_init(qr_code_data_list *_qrlist){
|
3411
|
+
_qrlist->qrdata=NULL;
|
3412
|
+
_qrlist->nqrdata=_qrlist->cqrdata=0;
|
3413
|
+
}
|
3414
|
+
|
3415
|
+
void qr_code_data_list_clear(qr_code_data_list *_qrlist){
|
3416
|
+
int i;
|
3417
|
+
for(i=0;i<_qrlist->nqrdata;i++)qr_code_data_clear(_qrlist->qrdata+i);
|
3418
|
+
free(_qrlist->qrdata);
|
3419
|
+
qr_code_data_list_init(_qrlist);
|
3420
|
+
}
|
3421
|
+
|
3422
|
+
static void qr_code_data_list_add(qr_code_data_list *_qrlist,
|
3423
|
+
qr_code_data *_qrdata){
|
3424
|
+
if(_qrlist->nqrdata>=_qrlist->cqrdata){
|
3425
|
+
_qrlist->cqrdata=_qrlist->cqrdata<<1|1;
|
3426
|
+
_qrlist->qrdata=(qr_code_data *)realloc(_qrlist->qrdata,
|
3427
|
+
_qrlist->cqrdata*sizeof(*_qrlist->qrdata));
|
3428
|
+
}
|
3429
|
+
memcpy(_qrlist->qrdata+_qrlist->nqrdata++,_qrdata,sizeof(*_qrdata));
|
3430
|
+
}
|
3431
|
+
|
3432
|
+
#if 0
|
3433
|
+
static const unsigned short QR_NCODEWORDS[40]={
|
3434
|
+
26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
|
3435
|
+
404, 466, 532, 581, 655, 733, 815, 901, 991,1085,
|
3436
|
+
1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,
|
3437
|
+
2323,2465,2611,2761,2876,3034,3196,3362,3532,3706
|
3438
|
+
};
|
3439
|
+
#endif
|
3440
|
+
|
3441
|
+
/*The total number of codewords in a QR code.*/
|
3442
|
+
static int qr_code_ncodewords(unsigned _version){
|
3443
|
+
unsigned nalign;
|
3444
|
+
/*This is 24-27 instructions on ARM in thumb mode, or a 26-32 byte savings
|
3445
|
+
over just using a table (not counting the instructions that would be
|
3446
|
+
needed to do the table lookup).*/
|
3447
|
+
if(_version==1)return 26;
|
3448
|
+
nalign=(_version/7)+2;
|
3449
|
+
return (_version<<4)*(_version+8)
|
3450
|
+
-(5*nalign)*(5*nalign-2)+36*(_version<7)+83>>3;
|
3451
|
+
}
|
3452
|
+
|
3453
|
+
#if 0
|
3454
|
+
/*The number of parity bytes per Reed-Solomon block for each version and error
|
3455
|
+
correction level.*/
|
3456
|
+
static const unsigned char QR_RS_NPAR[40][4]={
|
3457
|
+
{ 7,10,13,17},{10,16,22,28},{15,26,18,22},{20,18,26,16},
|
3458
|
+
{26,24,18,22},{18,16,24,28},{20,18,18,26},{24,22,22,26},
|
3459
|
+
{30,22,20,24},{18,26,24,28},{20,30,28,24},{24,22,26,28},
|
3460
|
+
{26,22,24,22},{30,24,20,24},{22,24,30,24},{24,28,24,30},
|
3461
|
+
{28,28,28,28},{30,26,28,28},{28,26,26,26},{28,26,30,28},
|
3462
|
+
{28,26,28,30},{28,28,30,24},{30,28,30,30},{30,28,30,30},
|
3463
|
+
{26,28,30,30},{28,28,28,30},{30,28,30,30},{30,28,30,30},
|
3464
|
+
{30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
|
3465
|
+
{30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
|
3466
|
+
{30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30}
|
3467
|
+
};
|
3468
|
+
#endif
|
3469
|
+
|
3470
|
+
/*Bulk data for the number of parity bytes per Reed-Solomon block.*/
|
3471
|
+
static const unsigned char QR_RS_NPAR_VALS[71]={
|
3472
|
+
/*[ 0]*/ 7,10,13,17,
|
3473
|
+
/*[ 4]*/10,16,22, 28,26,26, 26,22, 24,22,22, 26,24,18,22,
|
3474
|
+
/*[19]*/15,26,18, 22,24, 30,24,20,24,
|
3475
|
+
/*[28]*/18,16,24, 28, 28, 28,28,30,24,
|
3476
|
+
/*[37]*/20,18, 18,26, 24,28,24, 30,26,28, 28, 26,28,30, 30,22,20,24,
|
3477
|
+
/*[55]*/20,18,26,16,
|
3478
|
+
/*[59]*/20,30,28, 24,22,26, 28,26, 30,28,30,30
|
3479
|
+
};
|
3480
|
+
|
3481
|
+
/*An offset into QR_RS_NPAR_DATA for each version that gives the number of
|
3482
|
+
parity bytes per Reed-Solomon block for each error correction level.*/
|
3483
|
+
static const unsigned char QR_RS_NPAR_OFFS[40]={
|
3484
|
+
0, 4,19,55,15,28,37,12,51,39,
|
3485
|
+
59,62,10,24,22,41,31,44, 7,65,
|
3486
|
+
47,33,67,67,48,32,67,67,67,67,
|
3487
|
+
67,67,67,67,67,67,67,67,67,67
|
3488
|
+
};
|
3489
|
+
|
3490
|
+
/*The number of Reed-Solomon blocks for each version and error correction
|
3491
|
+
level.*/
|
3492
|
+
static const unsigned char QR_RS_NBLOCKS[40][4]={
|
3493
|
+
{ 1, 1, 1, 1},{ 1, 1, 1, 1},{ 1, 1, 2, 2},{ 1, 2, 2, 4},
|
3494
|
+
{ 1, 2, 4, 4},{ 2, 4, 4, 4},{ 2, 4, 6, 5},{ 2, 4, 6, 6},
|
3495
|
+
{ 2, 5, 8, 8},{ 4, 5, 8, 8},{ 4, 5, 8,11},{ 4, 8,10,11},
|
3496
|
+
{ 4, 9,12,16},{ 4, 9,16,16},{ 6,10,12,18},{ 6,10,17,16},
|
3497
|
+
{ 6,11,16,19},{ 6,13,18,21},{ 7,14,21,25},{ 8,16,20,25},
|
3498
|
+
{ 8,17,23,25},{ 9,17,23,34},{ 9,18,25,30},{10,20,27,32},
|
3499
|
+
{12,21,29,35},{12,23,34,37},{12,25,34,40},{13,26,35,42},
|
3500
|
+
{14,28,38,45},{15,29,40,48},{16,31,43,51},{17,33,45,54},
|
3501
|
+
{18,35,48,57},{19,37,51,60},{19,38,53,63},{20,40,56,66},
|
3502
|
+
{21,43,59,70},{22,45,62,74},{24,47,65,77},{25,49,68,81}
|
3503
|
+
};
|
3504
|
+
|
3505
|
+
/*Attempts to fully decode a QR code.
|
3506
|
+
_qrdata: Returns the parsed code data.
|
3507
|
+
_gf: Used for Reed-Solomon error correction.
|
3508
|
+
_ul_pos: The location of the UL finder pattern.
|
3509
|
+
_ur_pos: The location of the UR finder pattern.
|
3510
|
+
_dl_pos: The location of the DL finder pattern.
|
3511
|
+
_version: The (decoded) version number.
|
3512
|
+
_fmt_info: The decoded format info.
|
3513
|
+
_img: The binary input image.
|
3514
|
+
_width: The width of the input image.
|
3515
|
+
_height: The height of the input image.
|
3516
|
+
Return: 0 on success, or a negative value on error.*/
|
3517
|
+
static int qr_code_decode(qr_code_data *_qrdata,const rs_gf256 *_gf,
|
3518
|
+
const qr_point _ul_pos,const qr_point _ur_pos,const qr_point _dl_pos,
|
3519
|
+
int _version,int _fmt_info,
|
3520
|
+
const unsigned char *_img,int _width,int _height){
|
3521
|
+
qr_sampling_grid grid;
|
3522
|
+
unsigned *data_bits;
|
3523
|
+
unsigned char **blocks;
|
3524
|
+
unsigned char *block_data;
|
3525
|
+
int nblocks;
|
3526
|
+
int nshort_blocks;
|
3527
|
+
int ncodewords;
|
3528
|
+
int block_sz;
|
3529
|
+
int ecc_level;
|
3530
|
+
int ndata;
|
3531
|
+
int npar;
|
3532
|
+
int dim;
|
3533
|
+
int ret;
|
3534
|
+
int i;
|
3535
|
+
/*Read the bits out of the image.*/
|
3536
|
+
qr_sampling_grid_init(&grid,_version,_ul_pos,_ur_pos,_dl_pos,_qrdata->bbox,
|
3537
|
+
_img,_width,_height);
|
3538
|
+
#if defined(QR_DEBUG)
|
3539
|
+
qr_sampling_grid_dump(&grid,_version,_img,_width,_height);
|
3540
|
+
#endif
|
3541
|
+
dim=17+(_version<<2);
|
3542
|
+
data_bits=(unsigned *)malloc(
|
3543
|
+
dim*(dim+QR_INT_BITS-1>>QR_INT_LOGBITS)*sizeof(*data_bits));
|
3544
|
+
qr_sampling_grid_sample(&grid,data_bits,dim,_fmt_info,_img,_width,_height);
|
3545
|
+
/*Group those bits into Reed-Solomon codewords.*/
|
3546
|
+
ecc_level=(_fmt_info>>3)^1;
|
3547
|
+
nblocks=QR_RS_NBLOCKS[_version-1][ecc_level];
|
3548
|
+
npar=*(QR_RS_NPAR_VALS+QR_RS_NPAR_OFFS[_version-1]+ecc_level);
|
3549
|
+
ncodewords=qr_code_ncodewords(_version);
|
3550
|
+
block_sz=ncodewords/nblocks;
|
3551
|
+
nshort_blocks=nblocks-(ncodewords%nblocks);
|
3552
|
+
blocks=(unsigned char **)malloc(nblocks*sizeof(*blocks));
|
3553
|
+
block_data=(unsigned char *)malloc(ncodewords*sizeof(*block_data));
|
3554
|
+
blocks[0]=block_data;
|
3555
|
+
for(i=1;i<nblocks;i++)blocks[i]=blocks[i-1]+block_sz+(i>nshort_blocks);
|
3556
|
+
qr_samples_unpack(blocks,nblocks,block_sz-npar,nshort_blocks,
|
3557
|
+
data_bits,grid.fpmask,dim);
|
3558
|
+
qr_sampling_grid_clear(&grid);
|
3559
|
+
free(blocks);
|
3560
|
+
free(data_bits);
|
3561
|
+
/*Perform the error correction.*/
|
3562
|
+
ndata=0;
|
3563
|
+
ncodewords=0;
|
3564
|
+
ret=0;
|
3565
|
+
for(i=0;i<nblocks;i++){
|
3566
|
+
int block_szi;
|
3567
|
+
int ndatai;
|
3568
|
+
block_szi=block_sz+(i>=nshort_blocks);
|
3569
|
+
if(rs_correct(_gf,QR_M0,block_data+ncodewords,block_szi,npar,NULL,0)<0){
|
3570
|
+
ret=-1;
|
3571
|
+
break;
|
3572
|
+
}
|
3573
|
+
ndatai=block_szi-npar;
|
3574
|
+
memmove(block_data+ndata,block_data+ncodewords,ndatai*sizeof(*block_data));
|
3575
|
+
ncodewords+=block_szi;
|
3576
|
+
ndata+=ndatai;
|
3577
|
+
}
|
3578
|
+
/*Parse the corrected bitstream.*/
|
3579
|
+
if(ret>=0){
|
3580
|
+
ret=qr_code_data_parse(_qrdata,_version,block_data,ndata);
|
3581
|
+
/*We could return any partially decoded data, but then we'd have to have
|
3582
|
+
API support for that; a mode ignoring ECC errors might also be useful.*/
|
3583
|
+
if(ret<0)qr_code_data_clear(_qrdata);
|
3584
|
+
_qrdata->version=_version;
|
3585
|
+
_qrdata->ecc_level=ecc_level;
|
3586
|
+
}
|
3587
|
+
free(block_data);
|
3588
|
+
return ret;
|
3589
|
+
}
|
3590
|
+
|
3591
|
+
/*Searches for an arrangement of these three finder centers that yields a valid
|
3592
|
+
configuration.
|
3593
|
+
_c: On input, the three finder centers to consider in any order.
|
3594
|
+
Return: The detected version number, or a negative value on error.*/
|
3595
|
+
static int qr_reader_try_configuration(qr_reader *_reader,
|
3596
|
+
qr_code_data *_qrdata,const unsigned char *_img,int _width,int _height,
|
3597
|
+
qr_finder_center *_c[3]){
|
3598
|
+
int ci[7];
|
3599
|
+
unsigned maxd;
|
3600
|
+
int ccw;
|
3601
|
+
int i0;
|
3602
|
+
int i;
|
3603
|
+
/*Sort the points in counter-clockwise order.*/
|
3604
|
+
ccw=qr_point_ccw(_c[0]->pos,_c[1]->pos,_c[2]->pos);
|
3605
|
+
/*Colinear points can't be the corners of a quadrilateral.*/
|
3606
|
+
if(!ccw)return -1;
|
3607
|
+
/*Include a few extra copies of the cyclical list to avoid mods.*/
|
3608
|
+
ci[6]=ci[3]=ci[0]=0;
|
3609
|
+
ci[4]=ci[1]=1+(ccw<0);
|
3610
|
+
ci[5]=ci[2]=2-(ccw<0);
|
3611
|
+
/*Assume the points farthest from each other are the opposite corners, and
|
3612
|
+
find the top-left point.*/
|
3613
|
+
maxd=qr_point_distance2(_c[1]->pos,_c[2]->pos);
|
3614
|
+
i0=0;
|
3615
|
+
for(i=1;i<3;i++){
|
3616
|
+
unsigned d;
|
3617
|
+
d=qr_point_distance2(_c[ci[i+1]]->pos,_c[ci[i+2]]->pos);
|
3618
|
+
if(d>maxd){
|
3619
|
+
i0=i;
|
3620
|
+
maxd=d;
|
3621
|
+
}
|
3622
|
+
}
|
3623
|
+
/*However, try all three possible orderings, just to be sure (a severely
|
3624
|
+
skewed projection could move opposite corners closer than adjacent).*/
|
3625
|
+
for(i=i0;i<i0+3;i++){
|
3626
|
+
qr_aff aff;
|
3627
|
+
qr_hom hom;
|
3628
|
+
qr_finder ul;
|
3629
|
+
qr_finder ur;
|
3630
|
+
qr_finder dl;
|
3631
|
+
int res;
|
3632
|
+
int ur_version;
|
3633
|
+
int dl_version;
|
3634
|
+
int fmt_info;
|
3635
|
+
ul.c=_c[ci[i]];
|
3636
|
+
ur.c=_c[ci[i+1]];
|
3637
|
+
dl.c=_c[ci[i+2]];
|
3638
|
+
/*Estimate the module size and version number from the two opposite corners.
|
3639
|
+
The module size is not constant in the image, so we compute an affine
|
3640
|
+
projection from the three points we have to a square domain, and
|
3641
|
+
estimate it there.
|
3642
|
+
Although it should be the same along both axes, we keep separate
|
3643
|
+
estimates to account for any remaining projective distortion.*/
|
3644
|
+
res=QR_INT_BITS-2-QR_FINDER_SUBPREC-qr_ilog(QR_MAXI(_width,_height)-1);
|
3645
|
+
qr_aff_init(&aff,ul.c->pos,ur.c->pos,dl.c->pos,res);
|
3646
|
+
qr_aff_unproject(ur.o,&aff,ur.c->pos[0],ur.c->pos[1]);
|
3647
|
+
qr_finder_edge_pts_aff_classify(&ur,&aff);
|
3648
|
+
if(qr_finder_estimate_module_size_and_version(&ur,1<<res,1<<res)<0)continue;
|
3649
|
+
qr_aff_unproject(dl.o,&aff,dl.c->pos[0],dl.c->pos[1]);
|
3650
|
+
qr_finder_edge_pts_aff_classify(&dl,&aff);
|
3651
|
+
if(qr_finder_estimate_module_size_and_version(&dl,1<<res,1<<res)<0)continue;
|
3652
|
+
/*If the estimated versions are significantly different, reject the
|
3653
|
+
configuration.*/
|
3654
|
+
if(abs(ur.eversion[1]-dl.eversion[0])>QR_LARGE_VERSION_SLACK)continue;
|
3655
|
+
qr_aff_unproject(ul.o,&aff,ul.c->pos[0],ul.c->pos[1]);
|
3656
|
+
qr_finder_edge_pts_aff_classify(&ul,&aff);
|
3657
|
+
if(qr_finder_estimate_module_size_and_version(&ul,1<<res,1<<res)<0||
|
3658
|
+
abs(ul.eversion[1]-ur.eversion[1])>QR_LARGE_VERSION_SLACK||
|
3659
|
+
abs(ul.eversion[0]-dl.eversion[0])>QR_LARGE_VERSION_SLACK){
|
3660
|
+
continue;
|
3661
|
+
}
|
3662
|
+
#if defined(QR_DEBUG)
|
3663
|
+
qr_finder_dump_aff_undistorted(&ul,&ur,&dl,&aff,_img,_width,_height);
|
3664
|
+
#endif
|
3665
|
+
/*If we made it this far, upgrade the affine homography to a full
|
3666
|
+
homography.*/
|
3667
|
+
if(qr_hom_fit(&hom,&ul,&ur,&dl,_qrdata->bbox,&aff,
|
3668
|
+
&_reader->isaac,_img,_width,_height)<0){
|
3669
|
+
continue;
|
3670
|
+
}
|
3671
|
+
qr_hom_unproject(ul.o,&hom,ul.c->pos[0],ul.c->pos[1]);
|
3672
|
+
qr_hom_unproject(ur.o,&hom,ur.c->pos[0],ur.c->pos[1]);
|
3673
|
+
qr_hom_unproject(dl.o,&hom,dl.c->pos[0],dl.c->pos[1]);
|
3674
|
+
qr_finder_edge_pts_hom_classify(&ur,&hom);
|
3675
|
+
if(qr_finder_estimate_module_size_and_version(&ur,
|
3676
|
+
ur.o[0]-ul.o[0],ur.o[0]-ul.o[0])<0){
|
3677
|
+
continue;
|
3678
|
+
}
|
3679
|
+
qr_finder_edge_pts_hom_classify(&dl,&hom);
|
3680
|
+
if(qr_finder_estimate_module_size_and_version(&dl,
|
3681
|
+
dl.o[1]-ul.o[1],dl.o[1]-ul.o[1])<0){
|
3682
|
+
continue;
|
3683
|
+
}
|
3684
|
+
#if defined(QR_DEBUG)
|
3685
|
+
qr_finder_dump_hom_undistorted(&ul,&ur,&dl,&hom,_img,_width,_height);
|
3686
|
+
#endif
|
3687
|
+
/*If we have a small version (less than 7), there's no encoded version
|
3688
|
+
information.
|
3689
|
+
If the estimated version on the two corners matches and is sufficiently
|
3690
|
+
small, we assume this is the case.*/
|
3691
|
+
if(ur.eversion[1]==dl.eversion[0]&&ur.eversion[1]<7){
|
3692
|
+
/*We used to do a whole bunch of extra geometric checks for small
|
3693
|
+
versions, because with just an affine correction, it was fairly easy
|
3694
|
+
to estimate two consistent module sizes given a random configuration.
|
3695
|
+
However, now that we're estimating a full homography, these appear to
|
3696
|
+
be unnecessary.*/
|
3697
|
+
#if 0
|
3698
|
+
static const signed char LINE_TESTS[12][6]={
|
3699
|
+
/*DL left, UL > 0, UR > 0*/
|
3700
|
+
{2,0,0, 1,1, 1},
|
3701
|
+
/*DL right, UL > 0, UR < 0*/
|
3702
|
+
{2,1,0, 1,1,-1},
|
3703
|
+
/*UR top, UL > 0, DL > 0*/
|
3704
|
+
{1,2,0, 1,2, 1},
|
3705
|
+
/*UR bottom, UL > 0, DL < 0*/
|
3706
|
+
{1,3,0, 1,2,-1},
|
3707
|
+
/*UR left, DL < 0, UL < 0*/
|
3708
|
+
{1,0,2,-1,0,-1},
|
3709
|
+
/*UR right, DL > 0, UL > 0*/
|
3710
|
+
{1,1,2, 1,0, 1},
|
3711
|
+
/*DL top, UR < 0, UL < 0*/
|
3712
|
+
{2,2,1,-1,0,-1},
|
3713
|
+
/*DL bottom, UR > 0, UL > 0*/
|
3714
|
+
{2,3,1, 1,0, 1},
|
3715
|
+
/*UL left, DL > 0, UR > 0*/
|
3716
|
+
{0,0,2, 1,1, 1},
|
3717
|
+
/*UL right, DL > 0, UR < 0*/
|
3718
|
+
{0,1,2, 1,1,-1},
|
3719
|
+
/*UL top, UR > 0, DL > 0*/
|
3720
|
+
{0,2,1, 1,2, 1},
|
3721
|
+
/*UL bottom, UR > 0, DL < 0*/
|
3722
|
+
{0,3,1, 1,2,-1}
|
3723
|
+
};
|
3724
|
+
qr_finder *f[3];
|
3725
|
+
int j;
|
3726
|
+
/*Start by decoding the format information.
|
3727
|
+
This is cheap, but unlikely to reject invalid configurations.
|
3728
|
+
56.25% of all bitstrings are valid, and we mix and match several pieces
|
3729
|
+
until we find a valid combination, so our real chances of finding a
|
3730
|
+
valid codeword in random bits are even higher.*/
|
3731
|
+
fmt_info=qr_finder_fmt_info_decode(&ul,&ur,&dl,&aff,_img,_width,_height);
|
3732
|
+
if(fmt_info<0)continue;
|
3733
|
+
/*Now we fit lines to the edges of each finder pattern and check to make
|
3734
|
+
sure the centers of the other finder patterns lie on the proper side.*/
|
3735
|
+
f[0]=&ul;
|
3736
|
+
f[1]=&ur;
|
3737
|
+
f[2]=&dl;
|
3738
|
+
for(j=0;j<12;j++){
|
3739
|
+
const signed char *t;
|
3740
|
+
qr_line l0;
|
3741
|
+
int *p;
|
3742
|
+
t=LINE_TESTS[j];
|
3743
|
+
qr_finder_ransac(f[t[0]],&aff,&_reader->isaac,t[1]);
|
3744
|
+
/*We may not have enough points to fit a line accurately here.
|
3745
|
+
If not, we just skip the test.*/
|
3746
|
+
if(qr_line_fit_finder_edge(l0,f[t[0]],t[1],res)<0)continue;
|
3747
|
+
p=f[t[2]]->c->pos;
|
3748
|
+
if(qr_line_eval(l0,p[0],p[1])*t[3]<0)break;
|
3749
|
+
p=f[t[4]]->c->pos;
|
3750
|
+
if(qr_line_eval(l0,p[0],p[1])*t[5]<0)break;
|
3751
|
+
}
|
3752
|
+
if(j<12)continue;
|
3753
|
+
/*All tests passed.*/
|
3754
|
+
#endif
|
3755
|
+
ur_version=ur.eversion[1];
|
3756
|
+
}
|
3757
|
+
else{
|
3758
|
+
/*If the estimated versions are significantly different, reject the
|
3759
|
+
configuration.*/
|
3760
|
+
if(abs(ur.eversion[1]-dl.eversion[0])>QR_LARGE_VERSION_SLACK)continue;
|
3761
|
+
/*Otherwise we try to read the actual version data from the image.
|
3762
|
+
If the real version is not sufficiently close to our estimated version,
|
3763
|
+
then we assume there was an unrecoverable decoding error (so many bit
|
3764
|
+
errors we were within 3 errors of another valid code), and throw that
|
3765
|
+
value away.
|
3766
|
+
If no decoded version could be sufficiently close, we don't even try.*/
|
3767
|
+
if(ur.eversion[1]>=7-QR_LARGE_VERSION_SLACK){
|
3768
|
+
ur_version=qr_finder_version_decode(&ur,&hom,_img,_width,_height,0);
|
3769
|
+
if(abs(ur_version-ur.eversion[1])>QR_LARGE_VERSION_SLACK)ur_version=-1;
|
3770
|
+
}
|
3771
|
+
else ur_version=-1;
|
3772
|
+
if(dl.eversion[0]>=7-QR_LARGE_VERSION_SLACK){
|
3773
|
+
dl_version=qr_finder_version_decode(&dl,&hom,_img,_width,_height,1);
|
3774
|
+
if(abs(dl_version-dl.eversion[0])>QR_LARGE_VERSION_SLACK)dl_version=-1;
|
3775
|
+
}
|
3776
|
+
else dl_version=-1;
|
3777
|
+
/*If we got at least one valid version, or we got two and they match,
|
3778
|
+
then we found a valid configuration.*/
|
3779
|
+
if(ur_version>=0){
|
3780
|
+
if(dl_version>=0&&dl_version!=ur_version)continue;
|
3781
|
+
}
|
3782
|
+
else if(dl_version<0)continue;
|
3783
|
+
else ur_version=dl_version;
|
3784
|
+
}
|
3785
|
+
qr_finder_edge_pts_hom_classify(&ul,&hom);
|
3786
|
+
if(qr_finder_estimate_module_size_and_version(&ul,
|
3787
|
+
ur.o[0]-dl.o[0],dl.o[1]-ul.o[1])<0||
|
3788
|
+
abs(ul.eversion[1]-ur.eversion[1])>QR_SMALL_VERSION_SLACK||
|
3789
|
+
abs(ul.eversion[0]-dl.eversion[0])>QR_SMALL_VERSION_SLACK){
|
3790
|
+
continue;
|
3791
|
+
}
|
3792
|
+
fmt_info=qr_finder_fmt_info_decode(&ul,&ur,&dl,&hom,_img,_width,_height);
|
3793
|
+
if(fmt_info<0)continue;
|
3794
|
+
if(qr_code_decode(_qrdata,&_reader->gf,ul.c->pos,ur.c->pos,dl.c->pos,
|
3795
|
+
ur_version,fmt_info,_img,_width,_height)<0){
|
3796
|
+
/*TODO: Maybe somebody flipped the code?
|
3797
|
+
We'd still get a valid version, and probably valid (but incorrect)
|
3798
|
+
format info.
|
3799
|
+
After we've come this far, it should be a simple matter to check.*/
|
3800
|
+
continue;
|
3801
|
+
}
|
3802
|
+
return ur_version;
|
3803
|
+
}
|
3804
|
+
return -1;
|
3805
|
+
}
|
3806
|
+
|
3807
|
+
void qr_reader_match_centers(qr_reader *_reader,qr_code_data_list *_qrlist,
|
3808
|
+
qr_finder_center *_centers,int _ncenters,
|
3809
|
+
const unsigned char *_img,int _width,int _height){
|
3810
|
+
/*The number of centers should be small, so an O(n^3) exhaustive search of
|
3811
|
+
which ones go together should be reasonable.*/
|
3812
|
+
unsigned char *mark;
|
3813
|
+
int i;
|
3814
|
+
int j;
|
3815
|
+
int k;
|
3816
|
+
mark=(unsigned char *)calloc(_ncenters,sizeof(*mark));
|
3817
|
+
for(i=0;i<_ncenters;i++){
|
3818
|
+
/*TODO: We might be able to accelerate this step significantly by
|
3819
|
+
considering the remaining finder centers in a more intelligent order,
|
3820
|
+
based on the first finder center we just chose.*/
|
3821
|
+
for(j=i+1;!mark[i]&&j<_ncenters;j++){
|
3822
|
+
for(k=j+1;!mark[j]&&k<_ncenters;k++)if(!mark[k]){
|
3823
|
+
qr_finder_center *c[3];
|
3824
|
+
qr_code_data qrdata;
|
3825
|
+
int version;
|
3826
|
+
c[0]=_centers+i;
|
3827
|
+
c[1]=_centers+j;
|
3828
|
+
c[2]=_centers+k;
|
3829
|
+
version=qr_reader_try_configuration(_reader,&qrdata,
|
3830
|
+
_img,_width,_height,c);
|
3831
|
+
if(version>=0){
|
3832
|
+
int ninside;
|
3833
|
+
int l;
|
3834
|
+
/*Add the data to the list.*/
|
3835
|
+
qr_code_data_list_add(_qrlist,&qrdata);
|
3836
|
+
/*Convert the bounding box we're returning to the user to normal
|
3837
|
+
image coordinates.*/
|
3838
|
+
for(l=0;l<4;l++){
|
3839
|
+
_qrlist->qrdata[_qrlist->nqrdata-1].bbox[l][0]>>=QR_FINDER_SUBPREC;
|
3840
|
+
_qrlist->qrdata[_qrlist->nqrdata-1].bbox[l][1]>>=QR_FINDER_SUBPREC;
|
3841
|
+
}
|
3842
|
+
/*Mark these centers as used.*/
|
3843
|
+
mark[i]=mark[j]=mark[k]=1;
|
3844
|
+
/*Find any other finder centers located inside this code.*/
|
3845
|
+
for(l=ninside=0;l<_ncenters;l++)if(!mark[l]){
|
3846
|
+
if(qr_point_ccw(qrdata.bbox[0],qrdata.bbox[1],_centers[l].pos)>=0&&
|
3847
|
+
qr_point_ccw(qrdata.bbox[1],qrdata.bbox[3],_centers[l].pos)>=0&&
|
3848
|
+
qr_point_ccw(qrdata.bbox[3],qrdata.bbox[2],_centers[l].pos)>=0&&
|
3849
|
+
qr_point_ccw(qrdata.bbox[2],qrdata.bbox[0],_centers[l].pos)>=0){
|
3850
|
+
mark[l]=2;
|
3851
|
+
ninside++;
|
3852
|
+
}
|
3853
|
+
}
|
3854
|
+
if(ninside>=3){
|
3855
|
+
/*We might have a "Double QR": a code inside a code.
|
3856
|
+
Copy the relevant centers to a new array and do a search confined
|
3857
|
+
to that subset.*/
|
3858
|
+
qr_finder_center *inside;
|
3859
|
+
inside=(qr_finder_center *)malloc(ninside*sizeof(*inside));
|
3860
|
+
for(l=ninside=0;l<_ncenters;l++){
|
3861
|
+
if(mark[l]==2)*&inside[ninside++]=*&_centers[l];
|
3862
|
+
}
|
3863
|
+
qr_reader_match_centers(_reader,_qrlist,inside,ninside,
|
3864
|
+
_img,_width,_height);
|
3865
|
+
free(inside);
|
3866
|
+
}
|
3867
|
+
/*Mark _all_ such centers used: codes cannot partially overlap.*/
|
3868
|
+
for(l=0;l<_ncenters;l++)if(mark[l]==2)mark[l]=1;
|
3869
|
+
}
|
3870
|
+
}
|
3871
|
+
}
|
3872
|
+
}
|
3873
|
+
free(mark);
|
3874
|
+
}
|
3875
|
+
|
3876
|
+
int _zbar_qr_found_line (qr_reader *reader,
|
3877
|
+
int dir,
|
3878
|
+
const qr_finder_line *line)
|
3879
|
+
{
|
3880
|
+
/* minimally intrusive brute force version */
|
3881
|
+
qr_finder_lines *lines = &reader->finder_lines[dir];
|
3882
|
+
|
3883
|
+
if(lines->nlines >= lines->clines) {
|
3884
|
+
lines->clines *= 2;
|
3885
|
+
lines->lines = realloc(lines->lines,
|
3886
|
+
++lines->clines * sizeof(*lines->lines));
|
3887
|
+
}
|
3888
|
+
|
3889
|
+
memcpy(lines->lines + lines->nlines++, line, sizeof(*line));
|
3890
|
+
|
3891
|
+
return(0);
|
3892
|
+
}
|
3893
|
+
|
3894
|
+
static inline void qr_svg_centers (const qr_finder_center *centers,
|
3895
|
+
int ncenters)
|
3896
|
+
{
|
3897
|
+
int i, j;
|
3898
|
+
svg_path_start("centers", 1, 0, 0);
|
3899
|
+
for(i = 0; i < ncenters; i++)
|
3900
|
+
svg_path_moveto(SVG_ABS, centers[i].pos[0], centers[i].pos[1]);
|
3901
|
+
svg_path_end();
|
3902
|
+
|
3903
|
+
svg_path_start("edge-pts", 1, 0, 0);
|
3904
|
+
for(i = 0; i < ncenters; i++) {
|
3905
|
+
const qr_finder_center *cen = centers + i;
|
3906
|
+
for(j = 0; j < cen->nedge_pts; j++)
|
3907
|
+
svg_path_moveto(SVG_ABS,
|
3908
|
+
cen->edge_pts[j].pos[0], cen->edge_pts[j].pos[1]);
|
3909
|
+
}
|
3910
|
+
svg_path_end();
|
3911
|
+
}
|
3912
|
+
|
3913
|
+
int _zbar_qr_decode (qr_reader *reader,
|
3914
|
+
zbar_image_scanner_t *iscn,
|
3915
|
+
zbar_image_t *img)
|
3916
|
+
{
|
3917
|
+
int nqrdata = 0, ncenters;
|
3918
|
+
qr_finder_edge_pt *edge_pts = NULL;
|
3919
|
+
qr_finder_center *centers = NULL;
|
3920
|
+
|
3921
|
+
if(reader->finder_lines[0].nlines < 9 ||
|
3922
|
+
reader->finder_lines[1].nlines < 9)
|
3923
|
+
return(0);
|
3924
|
+
|
3925
|
+
svg_group_start("finder", 0, 1. / (1 << QR_FINDER_SUBPREC), 0, 0, 0);
|
3926
|
+
|
3927
|
+
ncenters = qr_finder_centers_locate(¢ers, &edge_pts, reader, 0, 0);
|
3928
|
+
|
3929
|
+
zprintf(14, "%dx%d finders, %d centers:\n",
|
3930
|
+
reader->finder_lines[0].nlines,
|
3931
|
+
reader->finder_lines[1].nlines,
|
3932
|
+
ncenters);
|
3933
|
+
qr_svg_centers(centers, ncenters);
|
3934
|
+
|
3935
|
+
if(ncenters >= 3) {
|
3936
|
+
void *bin = qr_binarize(img->data, img->width, img->height);
|
3937
|
+
|
3938
|
+
qr_code_data_list qrlist;
|
3939
|
+
qr_code_data_list_init(&qrlist);
|
3940
|
+
|
3941
|
+
qr_reader_match_centers(reader, &qrlist, centers, ncenters,
|
3942
|
+
bin, img->width, img->height);
|
3943
|
+
|
3944
|
+
if(qrlist.nqrdata > 0)
|
3945
|
+
nqrdata = qr_code_data_list_extract_text(&qrlist, iscn, img);
|
3946
|
+
|
3947
|
+
qr_code_data_list_clear(&qrlist);
|
3948
|
+
free(bin);
|
3949
|
+
}
|
3950
|
+
svg_group_end();
|
3951
|
+
|
3952
|
+
if(centers)
|
3953
|
+
free(centers);
|
3954
|
+
if(edge_pts)
|
3955
|
+
free(edge_pts);
|
3956
|
+
return(nqrdata);
|
3957
|
+
}
|