From 515f743dc06f2d745ff0cda8db34759b0bb97ae5 Mon Sep 17 00:00:00 2001 From: ftylitak Date: Tue, 4 May 2010 00:24:11 +0000 Subject: [PATCH] ZXing on Symbian using OpenC++ (currently only Qr decoder) git-svn-id: https://zxing.googlecode.com/svn/trunk@1332 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- symbian/ZXingBarcodeReader/.cproject | 143 +++++ symbian/ZXingBarcodeReader/.project | 19 + .../.settings/org.eclipse.cdt.ui.prefs | 4 + symbian/ZXingBarcodeReader/Nokia_Licence.txt | 31 + symbian/ZXingBarcodeReader/ZXing_Licence.txt | 201 ++++++ .../CameraWrapper/sis/camerawrapper.sisx | Bin 0 -> 8104 bytes .../epoc32/include/cameraengine.h | 241 ++++++++ .../epoc32/include/cameraengineobserver.h | 92 +++ .../release/armv5/lib/camerawrapper.dso | Bin 0 -> 2880 bytes .../release/armv5/lib/camerawrapper.lib | Bin 0 -> 31016 bytes .../armv5/lib/camerawrapper{000a0000}.dso | Bin 0 -> 2880 bytes .../armv5/lib/camerawrapper{000a0000}.lib | Bin 0 -> 31016 bytes .../release/armv5/urel/camerawrapper.dll | Bin 0 -> 3573 bytes .../release/armv5/urel/camerawrapper.dll.map | 431 +++++++++++++ .../release/winscw/udeb/CamAutoFocus.dll | Bin 0 -> 174148 bytes .../release/winscw/udeb/camerawrapper.dll | Bin 0 -> 238940 bytes .../release/winscw/udeb/camerawrapper.lib | Bin 0 -> 11814 bytes .../data/ZXingBarcodeReader.rls | 16 + .../data/ZXingBarcodeReader.rss | 158 +++++ .../data/ZXingBarcodeReader_reg.rss | 23 + symbian/ZXingBarcodeReader/gfx/QrDecoder.svg | 91 +++ symbian/ZXingBarcodeReader/group/ABLD.BAT | 15 + .../group/CameraWrapperExample.mmp | 91 +++ .../group/Icons_scalable_dc.mk | 40 ++ symbian/ZXingBarcodeReader/group/bld.inf | 11 + .../group/zxing/BarcodeFormat.cpp | 22 + .../group/zxing/BarcodeFormat.h | 42 ++ .../group/zxing/Binarizer.cpp | 48 ++ .../group/zxing/Binarizer.h | 51 ++ .../group/zxing/BinaryBitmap.cpp | 57 ++ .../group/zxing/BinaryBitmap.h | 51 ++ .../group/zxing/Exception.cpp | 25 + .../group/zxing/Exception.h | 40 ++ .../group/zxing/LuminanceSource.cpp | 43 ++ .../group/zxing/LuminanceSource.h | 42 ++ .../group/zxing/MultiFormatReader.cpp | 54 ++ .../group/zxing/MultiFormatReader.h | 38 ++ .../ZXingBarcodeReader/group/zxing/Reader.cpp | 27 + .../ZXingBarcodeReader/group/zxing/Reader.h | 38 ++ .../group/zxing/ReaderException.cpp | 32 + .../group/zxing/ReaderException.h | 35 ++ .../ZXingBarcodeReader/group/zxing/Result.cpp | 59 ++ .../ZXingBarcodeReader/group/zxing/Result.h | 54 ++ .../group/zxing/ResultPoint.cpp | 22 + .../group/zxing/ResultPoint.h | 36 ++ .../group/zxing/common/Array.cpp | 22 + .../group/zxing/common/Array.h | 209 +++++++ .../group/zxing/common/BitArray.cpp | 118 ++++ .../group/zxing/common/BitArray.h | 57 ++ .../group/zxing/common/BitMatrix.cpp | 148 +++++ .../group/zxing/common/BitMatrix.h | 61 ++ .../group/zxing/common/BitSource.cpp | 75 +++ .../group/zxing/common/BitSource.h | 68 +++ .../group/zxing/common/Counted.cpp | 32 + .../group/zxing/common/Counted.h | 202 ++++++ .../group/zxing/common/DecoderResult.cpp | 37 ++ .../group/zxing/common/DecoderResult.h | 44 ++ .../group/zxing/common/DetectorResult.cpp | 41 ++ .../group/zxing/common/DetectorResult.h | 47 ++ .../group/zxing/common/EdgeDetector.cpp | 190 ++++++ .../group/zxing/common/EdgeDetector.h | 38 ++ .../zxing/common/GlobalHistogramBinarizer.cpp | 177 ++++++ .../zxing/common/GlobalHistogramBinarizer.h | 44 ++ .../group/zxing/common/GridSampler.cpp | 101 +++ .../group/zxing/common/GridSampler.h | 44 ++ .../zxing/common/IllegalArgumentException.cpp | 31 + .../zxing/common/IllegalArgumentException.h | 34 ++ .../zxing/common/LocalBlockBinarizer.cpp | 196 ++++++ .../group/zxing/common/LocalBlockBinarizer.h | 47 ++ .../zxing/common/PerspectiveTransform.cpp | 121 ++++ .../group/zxing/common/PerspectiveTransform.h | 50 ++ .../group/zxing/common/Point.h | 47 ++ .../group/zxing/common/Str.cpp | 38 ++ .../group/zxing/common/Str.h | 41 ++ .../group/zxing/common/reedsolomon/GF256.cpp | 140 +++++ .../group/zxing/common/reedsolomon/GF256.h | 69 +++ .../zxing/common/reedsolomon/GF256Poly.cpp | 198 ++++++ .../zxing/common/reedsolomon/GF256Poly.h | 54 ++ .../common/reedsolomon/ReedSolomonDecoder.cpp | 193 ++++++ .../common/reedsolomon/ReedSolomonDecoder.h | 47 ++ .../reedsolomon/ReedSolomonException.cpp | 30 + .../common/reedsolomon/ReedSolomonException.h | 34 ++ .../group/zxing/oned/Code128Reader.cpp | 478 +++++++++++++++ .../group/zxing/oned/Code128Reader.h | 61 ++ .../group/zxing/oned/Code39Reader.cpp | 340 +++++++++++ .../group/zxing/oned/Code39Reader.h | 57 ++ .../group/zxing/oned/EAN13Reader.cpp | 95 +++ .../group/zxing/oned/EAN13Reader.h | 41 ++ .../group/zxing/oned/EAN8Reader.cpp | 75 +++ .../group/zxing/oned/EAN8Reader.h | 40 ++ .../group/zxing/oned/ITFReader.cpp | 353 +++++++++++ .../group/zxing/oned/ITFReader.h | 53 ++ .../zxing/oned/MultiFormatOneDReader.cpp | 55 ++ .../group/zxing/oned/MultiFormatOneDReader.h | 39 ++ .../zxing/oned/MultiFormatUPCEANReader.cpp | 79 +++ .../zxing/oned/MultiFormatUPCEANReader.h | 41 ++ .../group/zxing/oned/OneDReader.cpp | 194 ++++++ .../group/zxing/oned/OneDReader.h | 46 ++ .../group/zxing/oned/OneDResultPoint.cpp | 39 ++ .../group/zxing/oned/OneDResultPoint.h | 37 ++ .../group/zxing/oned/UPCAReader.cpp | 64 ++ .../group/zxing/oned/UPCAReader.h | 45 ++ .../group/zxing/oned/UPCEANReader.cpp | 310 ++++++++++ .../group/zxing/oned/UPCEANReader.h | 65 ++ .../group/zxing/oned/UPCEReader.cpp | 150 +++++ .../group/zxing/oned/UPCEReader.h | 45 ++ .../zxing/qrcode/ErrorCorrectionLevel.cpp | 49 ++ .../group/zxing/qrcode/ErrorCorrectionLevel.h | 47 ++ .../group/zxing/qrcode/FormatInformation.cpp | 108 ++++ .../group/zxing/qrcode/FormatInformation.h | 55 ++ .../group/zxing/qrcode/QRCodeReader.cpp | 82 +++ .../group/zxing/qrcode/QRCodeReader.h | 43 ++ .../group/zxing/qrcode/Version.cpp | 559 +++++++++++++++++ .../group/zxing/qrcode/Version.h | 87 +++ .../zxing/qrcode/decoder/BitMatrixParser.cpp | 191 ++++++ .../zxing/qrcode/decoder/BitMatrixParser.h | 52 ++ .../group/zxing/qrcode/decoder/DataBlock.cpp | 118 ++++ .../group/zxing/qrcode/decoder/DataBlock.h | 52 ++ .../group/zxing/qrcode/decoder/DataMask.cpp | 159 +++++ .../group/zxing/qrcode/decoder/DataMask.h | 51 ++ .../qrcode/decoder/DecodedBitStreamParser.cpp | 282 +++++++++ .../qrcode/decoder/DecodedBitStreamParser.h | 60 ++ .../group/zxing/qrcode/decoder/Decoder.cpp | 103 ++++ .../group/zxing/qrcode/decoder/Decoder.h | 49 ++ .../group/zxing/qrcode/decoder/Mode.cpp | 73 +++ .../group/zxing/qrcode/decoder/Mode.h | 51 ++ .../qrcode/detector/AlignmentPattern.cpp | 46 ++ .../zxing/qrcode/detector/AlignmentPattern.h | 46 ++ .../detector/AlignmentPatternFinder.cpp | 204 +++++++ .../qrcode/detector/AlignmentPatternFinder.h | 62 ++ .../group/zxing/qrcode/detector/Detector.cpp | 265 ++++++++ .../group/zxing/qrcode/detector/Detector.h | 60 ++ .../zxing/qrcode/detector/FinderPattern.cpp | 58 ++ .../zxing/qrcode/detector/FinderPattern.h | 49 ++ .../qrcode/detector/FinderPatternFinder.cpp | 501 +++++++++++++++ .../qrcode/detector/FinderPatternFinder.h | 65 ++ .../qrcode/detector/FinderPatternInfo.cpp | 41 ++ .../zxing/qrcode/detector/FinderPatternInfo.h | 48 ++ .../zxing/qrcode/detector/QREdgeDetector.cpp | 168 +++++ .../zxing/qrcode/detector/QREdgeDetector.h | 48 ++ symbian/ZXingBarcodeReader/inc/CameraImage.h | 31 + .../inc/CameraWrapperExample.hrh | 19 + .../inc/CameraWrapperExample.pan | 20 + .../inc/CameraWrapperExampleAppUi.h | 79 +++ .../inc/CameraWrapperExampleAppView.h | 108 ++++ .../inc/CameraWrapperExampleApplication.h | 34 ++ .../inc/CameraWrapperExampleDocument.h | 40 ++ .../sis/ZXingBarcodeReader_S60.pkg | 27 + .../sis/ZXingBarcodeReader_S60.sisx | Bin 0 -> 175388 bytes .../ZXingBarcodeReader/src/CameraImage.cpp | 45 ++ .../src/CameraWrapperExample.cpp | 18 + .../src/CameraWrapperExampleAppUi.cpp | 260 ++++++++ .../src/CameraWrapperExampleAppView.cpp | 575 ++++++++++++++++++ .../src/CameraWrapperExampleApplication.cpp | 24 + .../src/CameraWrapperExampleDocument.cpp | 49 ++ .../src/DecodingOperations.cpp | 104 ++++ 156 files changed, 13715 insertions(+) create mode 100644 symbian/ZXingBarcodeReader/.cproject create mode 100644 symbian/ZXingBarcodeReader/.project create mode 100644 symbian/ZXingBarcodeReader/.settings/org.eclipse.cdt.ui.prefs create mode 100644 symbian/ZXingBarcodeReader/Nokia_Licence.txt create mode 100644 symbian/ZXingBarcodeReader/ZXing_Licence.txt create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/InstallToDevice/CameraWrapper/sis/camerawrapper.sisx create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengine.h create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengineobserver.h create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.dso create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.lib create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.dso create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.lib create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll.map create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/CamAutoFocus.dll create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.dll create mode 100644 symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.lib create mode 100644 symbian/ZXingBarcodeReader/data/ZXingBarcodeReader.rls create mode 100644 symbian/ZXingBarcodeReader/data/ZXingBarcodeReader.rss create mode 100644 symbian/ZXingBarcodeReader/data/ZXingBarcodeReader_reg.rss create mode 100644 symbian/ZXingBarcodeReader/gfx/QrDecoder.svg create mode 100644 symbian/ZXingBarcodeReader/group/ABLD.BAT create mode 100644 symbian/ZXingBarcodeReader/group/CameraWrapperExample.mmp create mode 100644 symbian/ZXingBarcodeReader/group/Icons_scalable_dc.mk create mode 100644 symbian/ZXingBarcodeReader/group/bld.inf create mode 100644 symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Binarizer.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Exception.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Exception.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Reader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Reader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/ReaderException.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/ReaderException.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Result.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/Result.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/ResultPoint.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Array.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Array.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitSource.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/BitSource.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Counted.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Counted.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Point.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/Str.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.h create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp create mode 100644 symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.h create mode 100644 symbian/ZXingBarcodeReader/inc/CameraImage.h create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExample.hrh create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExample.pan create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppUi.h create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppView.h create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExampleApplication.h create mode 100644 symbian/ZXingBarcodeReader/inc/CameraWrapperExampleDocument.h create mode 100644 symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.pkg create mode 100644 symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx create mode 100644 symbian/ZXingBarcodeReader/src/CameraImage.cpp create mode 100644 symbian/ZXingBarcodeReader/src/CameraWrapperExample.cpp create mode 100644 symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppUi.cpp create mode 100644 symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppView.cpp create mode 100644 symbian/ZXingBarcodeReader/src/CameraWrapperExampleApplication.cpp create mode 100644 symbian/ZXingBarcodeReader/src/CameraWrapperExampleDocument.cpp create mode 100644 symbian/ZXingBarcodeReader/src/DecodingOperations.cpp diff --git a/symbian/ZXingBarcodeReader/.cproject b/symbian/ZXingBarcodeReader/.cproject new file mode 100644 index 000000000..14100f346 --- /dev/null +++ b/symbian/ZXingBarcodeReader/.cproject @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/symbian/ZXingBarcodeReader/.project b/symbian/ZXingBarcodeReader/.project new file mode 100644 index 000000000..cc8486fc9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/.project @@ -0,0 +1,19 @@ + + + ZXingBarcodeReader + + + + + + com.nokia.carbide.cdt.builder.carbideCPPBuilder + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + com.nokia.carbide.cdt.builder.carbideCPPBuilderNature + + diff --git a/symbian/ZXingBarcodeReader/.settings/org.eclipse.cdt.ui.prefs b/symbian/ZXingBarcodeReader/.settings/org.eclipse.cdt.ui.prefs new file mode 100644 index 000000000..55c6104f1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/.settings/org.eclipse.cdt.ui.prefs @@ -0,0 +1,4 @@ +#Tue Apr 27 21:26:48 EEST 2010 +eclipse.preferences.version=1 +formatter_profile=Qt +formatter_settings_version=1 diff --git a/symbian/ZXingBarcodeReader/Nokia_Licence.txt b/symbian/ZXingBarcodeReader/Nokia_Licence.txt new file mode 100644 index 000000000..758a74555 --- /dev/null +++ b/symbian/ZXingBarcodeReader/Nokia_Licence.txt @@ -0,0 +1,31 @@ +Copyright © 2009 Nokia Corporation. All rights reserved. +Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. +Java and all Java-based marks are trademarks or registered trademarks of +Sun Microsystems, Inc. Other product and company names mentioned herein may be +trademarks or trade names of their respective owners. + + +Subject to the conditions below, you may, without charge: + +· Use, copy, modify and/or merge copies of this software and + associated documentation files (the “Software”) + +· Publish, distribute, sub-license and/or sell new software + derived from or incorporating the Software. + + + +This file, unmodified, shall be included with all copies or substantial portions +of the Software that are distributed in source code form. + +The Software cannot constitute the primary value of any new software derived +from or incorporating the Software. + +Any person dealing with the Software shall not misrepresent the source of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/symbian/ZXingBarcodeReader/ZXing_Licence.txt b/symbian/ZXingBarcodeReader/ZXing_Licence.txt new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/ZXing_Licence.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/InstallToDevice/CameraWrapper/sis/camerawrapper.sisx b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/InstallToDevice/CameraWrapper/sis/camerawrapper.sisx new file mode 100644 index 0000000000000000000000000000000000000000..8a4fab2e21b56d2b5f0dc0229bde81dfe6b6088d GIT binary patch literal 8104 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 pk8vKG=Tm$^|&> literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengine.h b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengine.h new file mode 100644 index 000000000..d802fb377 --- /dev/null +++ b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengine.h @@ -0,0 +1,241 @@ +/* +* ============================================================================ +* Name : cameraengine.h +* Part of : CameraWrapper +* Description : Camera engine class declaration +* Version : %version: 2 % +* +* Copyright (c) 2009 Nokia Corporation. +* This material, including documentation and any related +* computer programs, is protected by copyright controlled by +* Nokia Corporation. +* ============================================================================== +*/ + +#ifndef CCAMERAENGINE_H +#define CCAMERAENGINE_H + +// INCLUDES +#include +#include + +// FORWARD DECLARATIONS +class CCameraEnginePrivate; +class MCameraEngineObserver; +class CCameraAdvancedSettings; + +NONSHARABLE_CLASS( CCameraEngine ) : public CBase + { +public: + + enum TCameraEngineState + { + EEngineNotReady, + EEngineIdle, + EEngineViewFinding, + EEngineCapturing, + EEngineFocusing + }; + + IMPORT_C static CCameraEngine* NewL( TInt aCameraHandle, + TInt aPriority, + MCameraEngineObserver* aObserver ); + IMPORT_C ~CCameraEngine(); + +public: + + /** + * Returns the current state (TCameraEngineState) + * of the camera engine. + */ + IMPORT_C TCameraEngineState State() const; + + /** + * Returns true if the camera has been reserved and + * powered on. + */ + IMPORT_C TBool IsCameraReady() const; + + /** + * Returns true if the camera supports AutoFocus. + */ + IMPORT_C TBool IsAutoFocusSupported() const; + + /** + * Captures an image. When complete, observer will receive + * MceoCapturedDataReady() or MceoCapturedBitmapReady() callback, + * depending on which image format was used in PrepareL(). + * @leave May leave with KErrNotReady if camera is not + * reserved or prepared for capture. + */ + IMPORT_C void CaptureL(); + + /** + * Reserves and powers on the camera. When complete, + * observer will receive MceoCameraReady() callback + * + */ + IMPORT_C void ReserveAndPowerOn(); + + /** + * Releases and powers off the camera + * + */ + IMPORT_C void ReleaseAndPowerOff(); + + /** + * Prepares for image capture. + * @param aCaptureSize requested capture size. On return, + * contains the selected size (closest match) + * @param aFormat Image format to use. Default is JPEG with + * EXIF information as provided by the camera module + * @leave KErrNotSupported, KErrNoMemory, KErrNotReady + */ + IMPORT_C void PrepareL( TSize& aCaptureSize, + CCamera::TFormat aFormat = CCamera::EFormatExif ); + + /** + * Starts the viewfinder. Observer will receive + * MceoViewFinderFrameReady() callbacks periodically. + * @param aSize requested viewfinder size. On return, + * contains the selected size. + * + * @leave KErrNotSupported is viewfinding with bitmaps is not + * supported, KErrNotReady + */ + IMPORT_C void StartViewFinderL( TSize& aSize ); + + /** + * Stops the viewfinder if active. + */ + IMPORT_C void StopViewFinder(); + + /** + * Releases memory for the last received viewfinder frame. + * Client must call this in response to MceoViewFinderFrameReady() + * callback, after drawing the viewfinder frame is complete. + */ + IMPORT_C void ReleaseViewFinderBuffer(); + + /** + * Releases memory for the last captured image. + * Client must call this in response to MceoCapturedDataReady() + * or MceoCapturedBitmapReady()callback, after processing the + * data/bitmap is complete. + */ + IMPORT_C void ReleaseImageBuffer(); + + /** + * Starts focusing. Does nothing if AutoFocus is not supported. + * When complete, observer will receive MceoFocusComplete() + * callback. + * @leave KErrInUse, KErrNotReady + */ + IMPORT_C void StartFocusL(); + + /** + * Cancels the ongoing focusing operation. + */ + IMPORT_C void FocusCancel(); + + /** + * Gets a bitfield of supported focus ranges. + * @param aSupportedRanges a bitfield of either TAutoFocusRange + * (S60 3.0/3.1 devices) or TFocusRange (S60 3.2 and onwards) values + */ + IMPORT_C void SupportedFocusRanges( TInt& aSupportedRanges ) const; + + /** + * Sets the focus range + * @param aFocusRange one of the values returned by + * SupportedFocusRanges(). + */ + IMPORT_C void SetFocusRange( TInt aFocusRange ); + + /** + * Returns a pointer to CCamera object used by the engine. + * Allows getting access to additional functionality + * from CCamera - do not use for functionality already provided + * by CCameraEngine methods. + */ + IMPORT_C CCamera* Camera(); + + /** + * Returns a pointer to CCameraAdvancedSettings object used by + * the engine. May be NULL if adv. settings is not available. + * Allows getting access to additional functionality + * from CCameraAdvancedSettings - do not use for functionality already + * provided by CCameraEngine methods. + */ + IMPORT_C CCamera::CCameraAdvancedSettings* AdvancedSettings(); + + /** + * Static function that returns the number of cameras on the device. + */ + IMPORT_C static TInt CamerasAvailable(); + + /** + * Maximum digital zoom value. 0 if digital zoom is not supported + */ + IMPORT_C TInt MaxDigitalZoom(); + + /** + * Current digital zoom value + */ + IMPORT_C TInt DigitalZoom(); + + /** + * Adjust digital zoom. set aTele to ETrue to increase zoom (tele) + * or EFalse to decrease zoom (wide) + * @return Returns the new zoom level or KErrNotSupported + */ + IMPORT_C TInt AdjustDigitalZoom( TBool aTele ); + + /** + * Returns a bitfield of supported exposure modes + * See CCamera::TExposure + */ + IMPORT_C TInt SupportedExposureModes(); + + /** + * Returns the current exposure mode + * See CCamera::TExposure + */ + IMPORT_C TInt Exposure(); + + /** + * Set camera exposure mode + * See CCamera::TExposure + * @param aExposure One of the modes from SupportedExposureModes + * @return KErrNone or KErrNotSupported + */ + IMPORT_C TInt SetExposure( TInt aExposure ); + + /** + * Returns a bitfield of supported flash modes + * See CCamera::TFlash + */ + IMPORT_C TInt SupportedFlashModes(); + + /** + * Returns the current flash mode + * See CCamera::TFlash + */ + IMPORT_C TInt Flash(); + + /** + * Set camera flash mode + * See CCamera::TFlash + * @param aFlash One of the modes from SupportedFlashModes + * @return KErrNone or KErrNotSupported + */ + IMPORT_C TInt SetFlash( TInt aFlash ); + +protected: + CCameraEngine(); + +private: + CCameraEnginePrivate* iPimpl; + }; + +#endif //CCAMERAENGINE_H diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengineobserver.h b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengineobserver.h new file mode 100644 index 000000000..832dfc1c1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/include/cameraengineobserver.h @@ -0,0 +1,92 @@ +/* +* ============================================================================ +* Name : cameraengineobserver.h +* Part of : CameraWrapper +* Description : Observer interface for camera engine (wrapper DLL) +* Version : %version: 1 % +* +* Copyright (c) 2009 Nokia Corporation. +* This material, including documentation and any related +* computer programs, is protected by copyright controlled by +* Nokia Corporation. +* ============================================================================== +*/ + +#ifndef __CCAMERAENGINEOBSERVER_H__ +#define __CCAMERAENGINEOBSERVER_H__ + +// FORWARD DECLARATIONS +class CFbsBitmap; +class TECAMEvent; + +enum TCameraEngineError + { + EErrReserve, + EErrPowerOn, + EErrViewFinderReady, + EErrImageReady, + EErrAutoFocusInit, + EErrAutoFocusMode, + EErrAutoFocusArea, + EErrAutoFocusRange, + EErrAutoFocusType, + EErrOptimisedFocusComplete, + }; + + +class MCameraEngineObserver + { +public: + + /** + * Camera is ready to use for capturing images. + */ + virtual void MceoCameraReady() = 0; + + /** + * Camera AF lens has attained optimal focus + */ + virtual void MceoFocusComplete() = 0; + + /** + * Captured data is ready - call CCameraEngine::ReleaseImageBuffer() + * after processing/saving the data (typically, JPG-encoded image) + * @param aData Pointer to a descriptor containing a frame of camera data. + */ + virtual void MceoCapturedDataReady( TDesC8* aData ) = 0; + + /** + * Captured bitmap is ready. + * after processing/saving the image, call + * CCameraEngine::ReleaseImageBuffer() to free the bitmap. + * @param aBitmap Pointer to an FBS bitmap containing a captured image. + */ + virtual void MceoCapturedBitmapReady( CFbsBitmap* aBitmap ) = 0; + + /** + * A new viewfinder frame is ready. + * after displaying the frame, call + * CCameraEngine::ReleaseViewFinderBuffer() + * to free the bitmap. + * @param aFrame Pointer to an FBS bitmap containing a viewfinder frame. + */ + virtual void MceoViewFinderFrameReady( CFbsBitmap& aFrame ) = 0; + + /** + * Notifies clients about errors in camera engine + * @param aErrorType type of error (see TCameraEngineError) + * @param aError Symbian system-wide error code + */ + virtual void MceoHandleError( TCameraEngineError aErrorType, TInt aError ) = 0; + + /** + * Notifies client about other events not recognized by camera engine. + * The default implementation is empty. + * @param aEvent camera event (see MCameraObserver2::HandleEvent()) + */ + virtual void MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ) {} + }; + +#endif // __CCAMERAENGINEOBSERVER_H__ + +// eof diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.dso b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.dso new file mode 100644 index 0000000000000000000000000000000000000000..cc620316138c64d70f440bc59552a59f1a118a6f GIT binary patch literal 2880 zcmbtW%WoS+9G)b+`ruXGZxybf~Jm<79uJcy^(VaMXU5KW_x zdi44ja6h0WhTcygoKMmAo<{qh{rw>6#G||*LJo1P z7@Ep=Ab)6QX)p6E0w~#3uER+V2I!aLoWdO51x$NC9G&<@_f)7)&_8uKm$}mx<750s z08CAM9>@D(;1S?afPNkaP5@5;PXbQ?tj#mPv%qt}^S}$hi@;03%fKr@4mb%=X!9Ec zK;O)XIqJ1wEf@pqaSOF%4R7PknsW^pKV#=wX<@9dri5`ZPc1rE&FPbQYM~j{fq5`r z)`Ib|9*m2zFgE&N9hf`wWgS=#)_^%PSLUqiz+9O(h4sj>0bxB3%N!!+-^S~I9b^2o z!}?H|%RHVp&YWN180D9A?B>mRjQzhqv3YU5P+D1$0~Jc!@4LP#6zV~D6s<_Vt2}$0 zsnL#Q7$<6tY>iS|O~zZ&?8dkkBn}M5uHTPls3j2{ z7;D(ArB2)ZL}fW%ZmCFxV^#H?X0W5e4L{pxrKLP2qXWHO@9v7L1KC$+N4?&RY>K7S z;z6Ky(Jrs6ordkY&0=BAT%e7uB>FHTwbQ9y)~Z!ja= zxl<3qfsE}8e>E$!AhkkvcX87F{^1>0TE%wb4s0pu>}4wzt<|VHii2d=wMWBY5XQ=x zr8`wf)RRpZ*{x(79`?S3trM%nP-nGh{pVX~hVB@H$h>o5=FpuVP|fYTvGgtm!C(^L z;e-p=&Gzmvh_D_rK8`iHdrvdza!1v%bUnG{O|rNnp5?0Z@hFN-bD1CHI|o(sWVF2& zI4b*dD;B4kI*ZxLOLZE{tV2c5&K~6%lFW5QH`yLLp&SlX_^D-C60kncJ5exe>{8LP z3aY!*`!Mf#p2+2r!_#>1Y^CrxJ%Ka!wY06d4bFQ&a~Eyi1Dbz@Htz<_zek&AwC2B~ z&HF&}qj1QxUGoxn&fu597Y%+5{FK3e1b@rmzkyo@{}a4y@V9Zf@pp>$R|7v|@JrzD z89W598T@PTa|ZtzykYQL;7x-c$7S0w_#5CK82l{wWrI859~t~haL3@^f^QrAS8&hZ ze}fMVzKBF)gP#ZAHMj@@?#Z7Zs2b^)27Hr qaTv?3L^awQfN!TgSOUS{rCP3{L7?jj+~KyK{2s+C5!R2wG2&lY%octC literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.lib b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper.lib new file mode 100644 index 0000000000000000000000000000000000000000..9e972bda9c8035b8c31a2aebda9c520abb6303c4 GIT binary patch literal 31016 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 Ljh>_{9q#-;?O~p! literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.dso b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.dso new file mode 100644 index 0000000000000000000000000000000000000000..cc620316138c64d70f440bc59552a59f1a118a6f GIT binary patch literal 2880 zcmbtW%WoS+9G)b+`ruXGZxybf~Jm<79uJcy^(VaMXU5KW_x zdi44ja6h0WhTcygoKMmAo<{qh{rw>6#G||*LJo1P z7@Ep=Ab)6QX)p6E0w~#3uER+V2I!aLoWdO51x$NC9G&<@_f)7)&_8uKm$}mx<750s z08CAM9>@D(;1S?afPNkaP5@5;PXbQ?tj#mPv%qt}^S}$hi@;03%fKr@4mb%=X!9Ec zK;O)XIqJ1wEf@pqaSOF%4R7PknsW^pKV#=wX<@9dri5`ZPc1rE&FPbQYM~j{fq5`r z)`Ib|9*m2zFgE&N9hf`wWgS=#)_^%PSLUqiz+9O(h4sj>0bxB3%N!!+-^S~I9b^2o z!}?H|%RHVp&YWN180D9A?B>mRjQzhqv3YU5P+D1$0~Jc!@4LP#6zV~D6s<_Vt2}$0 zsnL#Q7$<6tY>iS|O~zZ&?8dkkBn}M5uHTPls3j2{ z7;D(ArB2)ZL}fW%ZmCFxV^#H?X0W5e4L{pxrKLP2qXWHO@9v7L1KC$+N4?&RY>K7S z;z6Ky(Jrs6ordkY&0=BAT%e7uB>FHTwbQ9y)~Z!ja= zxl<3qfsE}8e>E$!AhkkvcX87F{^1>0TE%wb4s0pu>}4wzt<|VHii2d=wMWBY5XQ=x zr8`wf)RRpZ*{x(79`?S3trM%nP-nGh{pVX~hVB@H$h>o5=FpuVP|fYTvGgtm!C(^L z;e-p=&Gzmvh_D_rK8`iHdrvdza!1v%bUnG{O|rNnp5?0Z@hFN-bD1CHI|o(sWVF2& zI4b*dD;B4kI*ZxLOLZE{tV2c5&K~6%lFW5QH`yLLp&SlX_^D-C60kncJ5exe>{8LP z3aY!*`!Mf#p2+2r!_#>1Y^CrxJ%Ka!wY06d4bFQ&a~Eyi1Dbz@Htz<_zek&AwC2B~ z&HF&}qj1QxUGoxn&fu597Y%+5{FK3e1b@rmzkyo@{}a4y@V9Zf@pp>$R|7v|@JrzD z89W598T@PTa|ZtzykYQL;7x-c$7S0w_#5CK82l{wWrI859~t~haL3@^f^QrAS8&hZ ze}fMVzKBF)gP#ZAHMj@@?#Z7Zs2b^)27Hr qaTv?3L^awQfN!TgSOUS{rCP3{L7?jj+~KyK{2s+C5!R2wG2&lY%octC literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.lib b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.lib new file mode 100644 index 0000000000000000000000000000000000000000..9e972bda9c8035b8c31a2aebda9c520abb6303c4 GIT binary patch literal 31016 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 Ljh>_{9q#-;?O~p! literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll new file mode 100644 index 0000000000000000000000000000000000000000..04e2b18a637c5532d9afc67de78e900d9872ffa7 GIT binary patch literal 3573 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 vNOI8TA&!T_hC&?FA|cL0FBSCLI{000a0000}[10003a15].DLL#<\DLL>19 - Undefined Reference + #FBSCLI{000a0000}[10003a15].DLL#<\DLL>1e - Undefined Reference + #FBSCLI{000a0000}[10003a15].DLL#<\DLL>1f - Undefined Reference + #FBSCLI{000a0000}[10003a15].DLL#<\DLL>82 - Undefined Reference + #drtaeabi{000a0000}.dll#<\DLL>9e - Undefined Reference + #drtaeabi{000a0000}.dll#<\DLL>b4 - Undefined Reference + #drtaeabi{000a0000}.dll#<\DLL>b7 - Undefined Reference + #drtaeabi{000a0000}.dll#<\DLL>b8 - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>1a - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>1c - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>29 - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>2a - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>40 - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>78 - Undefined Reference + #ecamadvsettings{000a0000}[1020e76b].dll#<\DLL>7d - Undefined Reference + #ecam{000a0000}[101fb4c3].dll#<\DLL>2 - Undefined Reference + #ecam{000a0000}[101fb4c3].dll#<\DLL>3 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>251 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>289 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>28e - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>29d - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>491 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>51c - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>51f - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>54c - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>641 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>679 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>67b - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>72e - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>80c - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>80d - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>822 - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>84b - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>84d - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>cd - Undefined Reference + #euser{000a0000}[100039e5].dll#<\DLL>d0 - Undefined Reference + #scppnwdl{000a0000}.dll#<\DLL>3 - Undefined Reference + SHT$$INIT_ARRAY$$Base - Undefined Weak Reference + SHT$$INIT_ARRAY$$Limit - Undefined Weak Reference + typeinfo for XLeaveException - Undefined Reference + typeinfo for CBase - Undefined Reference + vtable for __cxxabiv1::__class_type_info - Undefined Reference + vtable for __cxxabiv1::__si_class_type_info - Undefined Reference + vtable for __cxxabiv1::__vmi_class_type_info - Undefined Reference + _fp_init - Undefined Weak Reference + run_static_dtors - Undefined Weak Reference + Image$$ER_RO$$Base 0x00008000 Number 0 anon$$obj.o(linker$$defined$$symbols) + _E32Dll 0x00008000 ARM Code 40 uc_dll_.o(.emb_text) + Symbian$$CPP$$Exception$$Descriptor 0x00008014 Data 0 uc_dll_.o(.emb_text) + __cpp_initialize__aeabi_ 0x00008028 ARM Code 72 ucppinit_aeabi.o(.emb_text) + CCameraEngine::CCameraEngine() 0x00008071 Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::CCameraEngine__sub_object() 0x00008071 Thumb Code 0 camerawrapper.in(.text) + std::nothrow 0x00008071 Thumb Code 0 ucppinit_aeabi.o(.emb_text) + CCameraEngine::NewL(int, int, MCameraEngineObserver*) 0x00008077 Thumb Code 44 camerawrapper.in(.text) + CCameraEngine::~CCameraEngine() 0x000080a3 Thumb Code 28 camerawrapper.in(.text) + CCameraEngine::~CCameraEngine__sub_object() 0x000080a3 Thumb Code 0 camerawrapper.in(.text) + CCameraEngine::~CCameraEngine__deallocating() 0x000080bf Thumb Code 16 camerawrapper.in(.text) + CCameraEngine::State() const 0x000080cf Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::IsCameraReady() const 0x000080d5 Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::IsAutoFocusSupported() const 0x000080db Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::CaptureL() 0x000080e5 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::ReserveAndPowerOn() 0x000080ef Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::ReleaseAndPowerOff() 0x000080f9 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::PrepareL(TSize&, CCamera::TFormat) 0x00008103 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::StartViewFinderL(TSize&) 0x0000810d Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::StopViewFinder() 0x00008117 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::ReleaseViewFinderBuffer() 0x00008121 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::ReleaseImageBuffer() 0x0000812b Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::StartFocusL() 0x00008135 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::FocusCancel() 0x0000813f Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::SupportedFocusRanges(int&) const 0x00008149 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::SetFocusRange(int) 0x00008153 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::Camera() 0x0000815d Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::AdvancedSettings() 0x00008163 Thumb Code 8 camerawrapper.in(.text) + CCameraEngine::CamerasAvailable() 0x0000816b Thumb Code 8 camerawrapper.in(.text) + CCameraEngine::MaxDigitalZoom() 0x00008173 Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::DigitalZoom() 0x00008179 Thumb Code 8 camerawrapper.in(.text) + CCameraEngine::AdjustDigitalZoom(int) 0x00008181 Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::SupportedExposureModes() 0x0000818b Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::Exposure() 0x00008191 Thumb Code 14 camerawrapper.in(.text) + CCameraEngine::SetExposure(int) 0x0000819f Thumb Code 10 camerawrapper.in(.text) + CCameraEngine::SupportedFlashModes() 0x000081a9 Thumb Code 6 camerawrapper.in(.text) + CCameraEngine::Flash() 0x000081af Thumb Code 14 camerawrapper.in(.text) + CCameraEngine::SetFlash(int) 0x000081bd Thumb Code 10 camerawrapper.in(.text) + CCameraEnginePrivate::ConstructL() 0x000081cd Thumb Code 268 camerawrapper.in(.text) + CCameraEnginePrivate::CCameraEnginePrivate(int, int, MCameraEngineObserver*) 0x000082d9 Thumb Code 48 camerawrapper.in(.text) + CCameraEnginePrivate::CCameraEnginePrivate__sub_object(int, int, MCameraEngineObserver*) 0x000082d9 Thumb Code 0 camerawrapper.in(.text) + CCameraEnginePrivate::NewL(int, int, MCameraEngineObserver*) 0x00008309 Thumb Code 44 camerawrapper.in(.text) + CCameraEnginePrivate::ReleaseImageBuffer() 0x00008335 Thumb Code 40 camerawrapper.in(.text) + CCameraEnginePrivate::ReleaseViewFinderBuffer() 0x0000835d Thumb Code 22 camerawrapper.in(.text) + CCameraEnginePrivate::StopViewFinder() 0x00008373 Thumb Code 30 camerawrapper.in(.text) + CCameraEnginePrivate::~CCameraEnginePrivate() 0x00008391 Thumb Code 98 camerawrapper.in(.text) + CCameraEnginePrivate::~CCameraEnginePrivate__sub_object() 0x00008391 Thumb Code 0 camerawrapper.in(.text) + CCameraEnginePrivate::~CCameraEnginePrivate__deallocating() 0x000083f3 Thumb Code 16 camerawrapper.in(.text) + CCameraEnginePrivate::IsAutoFocusSupported() const 0x00008403 Thumb Code 34 camerawrapper.in(.text) + CCameraEnginePrivate::CaptureL() 0x00008425 Thumb Code 34 camerawrapper.in(.text) + CCameraEnginePrivate::ReserveAndPowerOn() 0x00008447 Thumb Code 8 camerawrapper.in(.text) + CCameraEnginePrivate::FocusCancel() 0x0000844f Thumb Code 38 camerawrapper.in(.text) + CCameraEnginePrivate::ReleaseAndPowerOff() 0x00008475 Thumb Code 44 camerawrapper.in(.text) + CCameraEnginePrivate::PrepareL(TSize&, CCamera::TFormat) 0x000084a1 Thumb Code 118 camerawrapper.in(.text) + CCameraEnginePrivate::StartViewFinderL(TSize&) 0x00008517 Thumb Code 62 camerawrapper.in(.text) + CCameraEnginePrivate::StartFocusL() 0x00008555 Thumb Code 88 camerawrapper.in(.text) + CCameraEnginePrivate::SupportedFocusRanges(int&) const 0x000085ad Thumb Code 36 camerawrapper.in(.text) + CCameraEnginePrivate::SetFocusRange(int) 0x000085d1 Thumb Code 98 camerawrapper.in(.text) + CCameraEnginePrivate::AdjustDigitalZoom(int) 0x00008633 Thumb Code 110 camerawrapper.in(.text) + CCameraEnginePrivate::SetExposure(int) 0x000086a1 Thumb Code 62 camerawrapper.in(.text) + CCameraEnginePrivate::SetFlash(int) 0x000086df Thumb Code 62 camerawrapper.in(.text) + CCameraEnginePrivate::HandleEvent(const TECAMEvent&) 0x0000871d Thumb Code 196 camerawrapper.in(.text) + thunk{-8} to CCameraEnginePrivate::HandleEvent(const TECAMEvent&) 0x000087e1 Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::ViewFinderReady(MCameraBuffer&, int) 0x000087e5 Thumb Code 46 camerawrapper.in(.text) + thunk{-8} to CCameraEnginePrivate::ViewFinderReady(MCameraBuffer&, int) 0x00008813 Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::HandleImageReady(CFbsBitmap*, TDesC8*, int) 0x00008817 Thumb Code 60 camerawrapper.in(.text) + CCameraEnginePrivate::ImageBufferReady(MCameraBuffer&, int) 0x00008853 Thumb Code 126 camerawrapper.in(.text) + thunk{-8} to CCameraEnginePrivate::ImageBufferReady(MCameraBuffer&, int) 0x000088d1 Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::ReserveComplete(int) 0x000088d5 Thumb Code 24 camerawrapper.in(.text) + thunk{-4} to CCameraEnginePrivate::ReserveComplete(int) 0x000088ed Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::PowerOnComplete(int) 0x000088f1 Thumb Code 142 camerawrapper.in(.text) + thunk{-4} to CCameraEnginePrivate::PowerOnComplete(int) 0x0000897f Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::ViewFinderFrameReady(CFbsBitmap&) 0x00008983 Thumb Code 8 camerawrapper.in(.text) + thunk{-4} to CCameraEnginePrivate::ViewFinderFrameReady(CFbsBitmap&) 0x0000898b Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::ImageReady(CFbsBitmap*, HBufC8*, int) 0x0000898f Thumb Code 48 camerawrapper.in(.text) + thunk{-4} to CCameraEnginePrivate::ImageReady(CFbsBitmap*, HBufC8*, int) 0x000089bf Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::InitComplete(int) 0x000089c3 Thumb Code 18 camerawrapper.in(.text) + thunk{-12} to CCameraEnginePrivate::InitComplete(int) 0x000089d5 Thumb Code 4 camerawrapper.in(.text) + CCameraEnginePrivate::OptimisedFocusComplete(int) 0x000089d9 Thumb Code 26 camerawrapper.in(.text) + thunk{-12} to CCameraEnginePrivate::OptimisedFocusComplete(int) 0x000089f3 Thumb Code 4 camerawrapper.in(.text) + _E32Dll_Body 0x00008a05 Thumb Code 34 uc_dll.o(.text) + CCamAutoFocus::ConstructL(CCamera*) 0x00008a2d Thumb Code 26 CCamAutoFocus.o(.text) + CCamAutoFocus::CCamAutoFocus() 0x00008a47 Thumb Code 6 CCamAutoFocus.o(.text) + CCamAutoFocus::CCamAutoFocus__sub_object() 0x00008a47 Thumb Code 0 CCamAutoFocus.o(.text) + CCamAutoFocus::NewL(CCamera*) 0x00008a4d Thumb Code 36 CCamAutoFocus.o(.text) + CCamAutoFocus::~CCamAutoFocus() 0x00008a71 Thumb Code 28 CCamAutoFocus.o(.text) + CCamAutoFocus::~CCamAutoFocus__sub_object() 0x00008a71 Thumb Code 0 CCamAutoFocus.o(.text) + CCamAutoFocus::~CCamAutoFocus__deallocating() 0x00008a8d Thumb Code 16 CCamAutoFocus.o(.text) + CCamAutoFocus::InitL(MCamAutoFocusObserver&) 0x00008a9d Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::AttemptOptimisedFocusL() 0x00008aa7 Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::SetFocusRangeL(CCamAutoFocus::TAutoFocusRange) 0x00008ab1 Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::FocusRange(CCamAutoFocus::TAutoFocusRange&) 0x00008abb Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::Cancel() 0x00008ac5 Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::ResetToIdleL() 0x00008acf Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocus::Close() 0x00008ad9 Thumb Code 10 CCamAutoFocus.o(.text) + CCamAutoFocusImpl::CCamAutoFocusImpl(CCamera*) 0x00008ae9 Thumb Code 22 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::CCamAutoFocusImpl__sub_object(CCamera*) 0x00008ae9 Thumb Code 0 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::ConstructL() 0x00008aff Thumb Code 2 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::Close() 0x00008b01 Thumb Code 22 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::~CCamAutoFocusImpl() 0x00008b17 Thumb Code 26 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::~CCamAutoFocusImpl__sub_object() 0x00008b17 Thumb Code 0 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::~CCamAutoFocusImpl__deallocating() 0x00008b31 Thumb Code 16 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::InitL(MCamAutoFocusObserver&) 0x00008b41 Thumb Code 60 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::AttemptOptimisedFocusL() 0x00008b7d Thumb Code 28 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::SetFocusRangeL(int) 0x00008b99 Thumb Code 34 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::FocusRange(int&) 0x00008bbb Thumb Code 6 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::Cancel() 0x00008bc1 Thumb Code 14 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::ResetToIdleL() 0x00008bcf Thumb Code 28 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::InitComplete(int) 0x00008beb Thumb Code 14 CCamAutoFocusImpl.o(.text) + thunk{-4} to CCamAutoFocusImpl::InitComplete(int) 0x00008bf9 Thumb Code 4 CCamAutoFocusImpl.o(.text) + CCamAutoFocusImpl::OptimisedFocusComplete(int) 0x00008bfd Thumb Code 14 CCamAutoFocusImpl.o(.text) + thunk{-4} to CCamAutoFocusImpl::OptimisedFocusComplete(int) 0x00008c0b Thumb Code 4 CCamAutoFocusImpl.o(.text) + __DLL_Export_Table__ 0x00008c84 ARM Code 0 camerawrapper{000a0000}.exp(ExportTable) + DLL##ExportTableSize 0x00008c88 Data 0 camerawrapper{000a0000}.exp(ExportTable) + DLL##ExportTable 0x00008c8c Data 0 camerawrapper{000a0000}.exp(ExportTable) + TPtrC16::TPtrC16(const unsigned short*) 0x00008d10 ARM Code 0 euser{000a0000}-1169.o(StubCode) + RLibrary::Load(const TDesC16&, const TDesC16&) 0x00008d18 ARM Code 0 euser{000a0000}-1308.o(StubCode) + RLibrary::Close() 0x00008d20 ARM Code 0 euser{000a0000}-1311.o(StubCode) + TVersion::TVersion() 0x00008d28 ARM Code 0 euser{000a0000}-1356.o(StubCode) + TUid::operator ==(const TUid&) const 0x00008d30 ARM Code 0 euser{000a0000}-1601.o(StubCode) + TSize::operator ==(const TSize&) const 0x00008d38 ARM Code 0 euser{000a0000}-1657.o(StubCode) + TSize::operator -(const TSize&) const 0x00008d40 ARM Code 0 euser{000a0000}-1659.o(StubCode) + RLibrary::Lookup(int) const 0x00008d48 ARM Code 0 euser{000a0000}-1838.o(StubCode) + CleanupStack::Pop() 0x00008d50 ARM Code 0 euser{000a0000}-205.o(StubCode) + User::MarkCleanupStack() 0x00008d58 ARM Code 0 euser{000a0000}-2060.o(StubCode) + User::UnMarkCleanupStack(TTrapHandler*) 0x00008d60 ARM Code 0 euser{000a0000}-2061.o(StubCode) + CleanupStack::PushL(CBase*) 0x00008d68 ARM Code 0 euser{000a0000}-208.o(StubCode) + XLeaveException::GetReason() const 0x00008d70 ARM Code 0 euser{000a0000}-2082.o(StubCode) + CBase::Extension_(unsigned, void*&, void*) 0x00008d78 ARM Code 0 euser{000a0000}-2123.o(StubCode) + CBase::~CBase() 0x00008d80 ARM Code 0 euser{000a0000}-2125.o(StubCode) + User::LeaveIfError(int) 0x00008d88 ARM Code 0 euser{000a0000}-593.o(StubCode) + User::Leave(int) 0x00008d90 ARM Code 0 euser{000a0000}-649.o(StubCode) + User::AllocZL(int) 0x00008d98 ARM Code 0 euser{000a0000}-654.o(StubCode) + User::Invariant() 0x00008da0 ARM Code 0 euser{000a0000}-669.o(StubCode) + CCamera::CamerasAvailable() 0x00008da8 ARM Code 0 ecam{000a0000}-2.o(StubCode) + CCamera::NewL(MCameraObserver&, int) 0x00008db0 ARM Code 0 ecam{000a0000}-3.o(StubCode) + CFbsBitmap::Handle() const 0x00008db8 ARM Code 0 FBSCLI{000a0000}-130.o(StubCode) + CFbsBitmap::Reset() 0x00008dc0 ARM Code 0 FBSCLI{000a0000}-25.o(StubCode) + CFbsBitmap::Duplicate(int) 0x00008dc8 ARM Code 0 FBSCLI{000a0000}-30.o(StubCode) + CFbsBitmap::CFbsBitmap() 0x00008dd0 ARM Code 0 FBSCLI{000a0000}-31.o(StubCode) + CCamera::CCameraAdvancedSettings::SupportedFocusModes() const 0x00008dd8 ARM Code 0 ecamadvsettings{000a0000}-120.o(StubCode) + CCamera::CCameraAdvancedSettings::SupportedFocusRanges() const 0x00008de0 ARM Code 0 ecamadvsettings{000a0000}-125.o(StubCode) + CCamera::CCameraAdvancedSettings::SetFocusMode(CCamera::CCameraAdvancedSettings::TFocusMode) 0x00008de8 ARM Code 0 ecamadvsettings{000a0000}-26.o(StubCode) + CCamera::CCameraAdvancedSettings::SetFocusRange(CCamera::CCameraAdvancedSettings::TFocusRange) 0x00008df0 ARM Code 0 ecamadvsettings{000a0000}-28.o(StubCode) + CCamera::CCameraAdvancedSettings::SetAutoFocusArea(CCamera::CCameraAdvancedSettings::TAutoFocusArea) 0x00008df8 ARM Code 0 ecamadvsettings{000a0000}-41.o(StubCode) + CCamera::CCameraAdvancedSettings::SetAutoFocusType(CCamera::CCameraAdvancedSettings::TAutoFocusType) 0x00008e00 ARM Code 0 ecamadvsettings{000a0000}-42.o(StubCode) + CCamera::CCameraAdvancedSettings::NewL(CCamera&) 0x00008e08 ARM Code 0 ecamadvsettings{000a0000}-64.o(StubCode) + __aeabi_unwind_cpp_pr0 0x00008e10 ARM Code 0 drtaeabi{000a0000}-158.o(StubCode) + __cxa_begin_catch 0x00008e18 ARM Code 0 drtaeabi{000a0000}-180.o(StubCode) + __cxa_end_catch 0x00008e20 ARM Code 0 drtaeabi{000a0000}-183.o(StubCode) + __cxa_end_cleanup 0x00008e28 ARM Code 0 drtaeabi{000a0000}-184.o(StubCode) + operator delete (void*) 0x00008e30 ARM Code 0 scppnwdl{000a0000}-3.o(StubCode) + CCameraEnginePrivate::FrameBufferReady(MFrameBuffer*, int) 0x00008e39 Thumb Code 2 camerawrapper.in(i._ZN20CCameraEnginePrivate16FrameBufferReadyEP12MFrameBufferi) + CCameraEnginePrivate::VideoBufferReady(MCameraBuffer&, int) 0x00008e3b Thumb Code 2 camerawrapper.in(i._ZN20CCameraEnginePrivate16VideoBufferReadyER13MCameraBufferi) + thunk{-4} to CCameraEnginePrivate::FrameBufferReady(MFrameBuffer*, int) 0x00008e3d Thumb Code 2 camerawrapper.in(i._ZThn4_N20CCameraEnginePrivate16FrameBufferReadyEP12MFrameBufferi) + thunk{-8} to CCameraEnginePrivate::VideoBufferReady(MCameraBuffer&, int) 0x00008e3f Thumb Code 2 camerawrapper.in(i._ZThn8_N20CCameraEnginePrivate16VideoBufferReadyER13MCameraBufferi) + typeinfo for CCamAutoFocus 0x0000901c Data 12 CCamAutoFocus.o(.constdata__ZTI13CCamAutoFocus) + typeinfo for CCameraEngine 0x00009028 Data 12 camerawrapper.in(.constdata__ZTI13CCameraEngine) + typeinfo for MCameraObserver 0x00009034 Data 8 camerawrapper.in(.constdata__ZTI15MCameraObserver) + typeinfo for MCameraObserver2 0x0000903c Data 8 camerawrapper.in(.constdata__ZTI16MCameraObserver2) + typeinfo for CCamAutoFocusImpl 0x00009044 Data 32 CCamAutoFocusImpl.o(.constdata__ZTI17CCamAutoFocusImpl) + typeinfo for CCameraEnginePrivate 0x00009064 Data 48 camerawrapper.in(.constdata__ZTI20CCameraEnginePrivate) + typeinfo for MCamAutoFocusObserver 0x00009094 Data 8 camerawrapper.in(.constdata__ZTI21MCamAutoFocusObserver) + typeinfo for MCameraAutoFocusObserver 0x0000909c Data 8 CCamAutoFocusImpl.o(.constdata__ZTI24MCameraAutoFocusObserver) + typeinfo name for CCamAutoFocus 0x000090a4 Data 16 CCamAutoFocus.o(.constdata__ZTS13CCamAutoFocus) + typeinfo name for CCameraEngine 0x000090b4 Data 16 camerawrapper.in(.constdata__ZTS13CCameraEngine) + typeinfo name for MCameraObserver 0x000090c4 Data 18 camerawrapper.in(.constdata__ZTS15MCameraObserver) + typeinfo name for MCameraObserver2 0x000090d6 Data 19 camerawrapper.in(.constdata__ZTS16MCameraObserver2) + typeinfo name for CCamAutoFocusImpl 0x000090e9 Data 20 CCamAutoFocusImpl.o(.constdata__ZTS17CCamAutoFocusImpl) + typeinfo name for CCameraEnginePrivate 0x000090fd Data 23 camerawrapper.in(.constdata__ZTS20CCameraEnginePrivate) + typeinfo name for MCamAutoFocusObserver 0x00009114 Data 24 camerawrapper.in(.constdata__ZTS21MCamAutoFocusObserver) + typeinfo name for MCameraAutoFocusObserver 0x0000912c Data 27 CCamAutoFocusImpl.o(.constdata__ZTS24MCameraAutoFocusObserver) + vtable for CCamAutoFocus 0x00009148 Data 20 CCamAutoFocus.o(.constdata__ZTV13CCamAutoFocus) + vtable for CCameraEngine 0x0000915c Data 20 camerawrapper.in(.constdata__ZTV13CCameraEngine) + vtable for CCamAutoFocusImpl 0x00009170 Data 44 CCamAutoFocusImpl.o(.constdata__ZTV17CCamAutoFocusImpl) + vtable for CCameraEnginePrivate 0x0000919c Data 132 camerawrapper.in(.constdata__ZTV20CCameraEnginePrivate) + .ARM.exidx$$Base 0x00009220 Number 0 ucppinit_aeabi.o(.ARM.exidx) + .ARM.exidx$$Limit 0x00009338 Number 0 camerawrapper.in(.ARM.exidx) + Image$$ER_RO$$Limit 0x00009338 Number 0 anon$$obj.o(linker$$defined$$symbols) + diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/CamAutoFocus.dll b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/CamAutoFocus.dll new file mode 100644 index 0000000000000000000000000000000000000000..da16da62e721c393bc05d6755d706ba2adfdc757 GIT binary patch literal 174148 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 K7uW2Ing0bI^KP2} literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.dll b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.dll new file mode 100644 index 0000000000000000000000000000000000000000..d352fa8a6d474553e2aeb07f437c4c7a3bc689ce GIT binary patch literal 238940 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�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 literal 0 HcmV?d00001 diff --git a/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.lib b/symbian/ZXingBarcodeReader/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.lib new file mode 100644 index 0000000000000000000000000000000000000000..272d0aa5de11ec64fdaa6aa0d873748930e1ba35 GIT binary patch literal 11814 zcmeHNOLG%P5N_GQfO)^)V4mTSSBL_|#I8ywD@B{J-IPeEZ&+g3ZuJ$prC?OYA)f#E{+n#S`dU|?#_Uw?}TwJ-; zuMD_9YGN?0=8|eW<-Q)Le-pW6!uol?9{|1wINk$r@&&-DdjO}0sJy`v<;*CRk65A% zJhJ5MHULu|V~KKZFO{cQqMYAP~FHAAl*(uzXf7PfX2B&(4)ci=~m-iJ7_S z+47>kYBcrDrru~6O(>Ud-e_P4NAZj{PixaE{@{YyhM>Ewt;kVQ73F4iRVX8?W?7(1Z%fYm? zv9yX{TxX-b-ZUmVbz!3yEM=khsTRQq6GdVO)m41hsJD=k4riPe0xm|Zg_giu`*Ep5GBH{qrAMx)+r8x@bz;iB2P2w1M&8t_>|ulyFQ zRt%#0ru2v6vC2!KsK(pIrpLZY8qO)TFg}jOl*P@OZ_^K2Msvex77D~IeEy@f?wO|1 z&;#sS)8^+&)!)&b{hXW|t2bBmHtRpD_HG`g_0JkLLvI<{T4kobX*8#omRJ=I_hOop zG}5hkVpU%@hS!&tu*J-chl_a)XQ0yyUyyL%aQXAP!d$*C7YJ-WG_dASc47c|W>NY+@>&`jeEfk%(rQ#^7Xz&N?* zIKYdO0QXJ-3}Kx724(aNz(I;n{CBnlzn?pXN%*ht$h)MV<4%YG!LNCOM<0-iqsf!RN-%Wgy zmyS0WQXD@pr0sG=k%QdYo|jm$2`112v$iO(!Dw?GX0pY2@i3L^Vs{-}gkW>^+Kvk4g%&38T{^w6FMc=v_`>4JQ((h>m6+OUM z769IoD=X}Z$%p9fWml2}gBNT}%DzIblZ`$5SVNmXOYU}If=6^n2}&wS*~+ypJ;>nX%=ptM zfXNu~9+(g^TNrq(>0Qu3$uKV@S9g|sId|P;{$~wZ$Sa9eqKZ16emDa(iA9XdU)UA>%G&5z-I% zatDaghh7Sbnu}zg=>VHhu=eeQLEttCH{9OpK}o35Y%*jV&`4!+puQ{yBiUn?+m72F zZy|#nghhl@ftQYwU}pxFFA!Pn1tl%P$elw)vR5 zN0F@EWMjbc-~3cN@U-7cMj2%9vB_Ds?H#>b_BptSvr2wk(!8ZIT+uJyK)?L}GrK(+w{TC8=_~GGmls0e#0R zO|~D0D2u=aisbRU6hKK1a&Irif%lucCx{n3%sB8YR#1}AOGHVgBH3#uWTiY}@(?B< zy(F+V(vfV`_T28?7)1t0ISYHvh|ih4q?BZq_qognaO}idYW5HbCA;kx0vWi72T=Bn!@R)@~jJ +#include +#include +#include +#include "CameraWrapperExample.hrh" +#include "ZXingBarcodeReader.rls" + +// RESOURCE DEFINITIONS +// ----------------------------------------------------------------------------- +// +// Define the resource file signature +// This resource should be empty. +// +// ----------------------------------------------------------------------------- +// +RESOURCE RSS_SIGNATURE + { + } + +// ----------------------------------------------------------------------------- +// +// Default Document Name +// +// ----------------------------------------------------------------------------- +// +RESOURCE TBUF r_default_document_name + { + buf="CAME"; + } + +// ----------------------------------------------------------------------------- +// +// Define default menu and CBA key. +// +// ----------------------------------------------------------------------------- +// +RESOURCE EIK_APP_INFO + { + menubar = r_menubar; + cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; + } + + +// ----------------------------------------------------------------------------- +// +// r_menubar +// Main menubar +// +// ----------------------------------------------------------------------------- +// +RESOURCE MENU_BAR r_menubar + { + titles = + { + MENU_TITLE { menu_pane = r_menu; } + }; + } + + +// ----------------------------------------------------------------------------- +// +// r_menu +// Menu for "Options" +// +// ----------------------------------------------------------------------------- +// +RESOURCE MENU_PANE r_menu + { + items = + { + MENU_ITEM + { + command = EAbout; + txt = qtn_about; + }, + MENU_ITEM + { + command = EAknSoftkeyExit; + txt = qtn_exit; + } + }; + } + +// ----------------------------------------------------------------------------- +// +// About dialog resource. +// +// ----------------------------------------------------------------------------- +// +RESOURCE DIALOG r_about_query_dialog + { + flags = EGeneralQueryFlags | EEikDialogFlagNoBorder | EEikDialogFlagNoShadow; + buttons = R_AVKON_SOFTKEYS_OK_EMPTY; + items= + { + DLG_LINE + { + type = EAknCtPopupHeadingPane; + id = EAknMessageQueryHeaderId; + itemflags = EEikDlgItemNonFocusing; + control = AVKON_HEADING + { + }; + }, + DLG_LINE + { + type = EAknCtMessageQuery; + id = EAknMessageQueryContentId; + control = AVKON_MESSAGE_QUERY + { + }; + } + }; + } + + +// ----------------------------------------------------------------------------- +// +// Resources for messages. +// +// ----------------------------------------------------------------------------- +// +RESOURCE TBUF32 r_caption_string { buf=qtn_caption_string; } +RESOURCE TBUF32 r_about_dialog_title { buf=qtn_about_dialog_title; } +RESOURCE TBUF r_about_dialog_text { buf=qtn_about_dialog_text; } +RESOURCE TBUF r_command1_text { buf=qtn_command1_text; } + + +// ---------------------------------------------------------------------------- +// +// r_localisable_app_info +// +// ---------------------------------------------------------------------------- +// +RESOURCE LOCALISABLE_APP_INFO r_localisable_app_info + { + short_caption = qtn_caption_string; + caption_and_icon = + CAPTION_AND_ICON_INFO + { + caption = qtn_caption_string; + + number_of_icons = 1; + icon_file = "\\resource\\apps\\ZXingBarcodeReader_0xEF24C10A.mif"; + }; + } + +// End of File diff --git a/symbian/ZXingBarcodeReader/data/ZXingBarcodeReader_reg.rss b/symbian/ZXingBarcodeReader/data/ZXingBarcodeReader_reg.rss new file mode 100644 index 000000000..24fdbabeb --- /dev/null +++ b/symbian/ZXingBarcodeReader/data/ZXingBarcodeReader_reg.rss @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#include "CameraWrapperExample.hrh" +#include "ZXingBarcodeReader.rls" +#include +#include + +UID2 KUidAppRegistrationResourceFile +UID3 _UID3 + +RESOURCE APP_REGISTRATION_INFO + { + app_file="ZXingBarcodeReader_0xEF24C10A"; + //app_file="ZXingBarcodeReader"; + localisable_resource_file = qtn_loc_resource_file_1; + localisable_resource_id = R_LOCALISABLE_APP_INFO; + + embeddability=KAppNotEmbeddable; + newfile=KAppDoesNotSupportNewFile; + } + diff --git a/symbian/ZXingBarcodeReader/gfx/QrDecoder.svg b/symbian/ZXingBarcodeReader/gfx/QrDecoder.svg new file mode 100644 index 000000000..3bd9d64ae --- /dev/null +++ b/symbian/ZXingBarcodeReader/gfx/QrDecoder.svg @@ -0,0 +1,91 @@ + + + + + + diff --git a/symbian/ZXingBarcodeReader/group/ABLD.BAT b/symbian/ZXingBarcodeReader/group/ABLD.BAT new file mode 100644 index 000000000..f77106118 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/ABLD.BAT @@ -0,0 +1,15 @@ +@ECHO OFF + +REM Bldmake-generated batch file - ABLD.BAT +REM ** DO NOT EDIT ** + +perl -S ABLD.PL "\Carbide\ZXingWorkspace\ZXingBarcodeReader\group\\" %1 %2 %3 %4 %5 %6 %7 %8 %9 +if errorlevel==1 goto CheckPerl +goto End + +:CheckPerl +perl -v >NUL +if errorlevel==1 echo Is Perl, version 5.003_07 or later, installed? +goto End + +:End diff --git a/symbian/ZXingBarcodeReader/group/CameraWrapperExample.mmp b/symbian/ZXingBarcodeReader/group/CameraWrapperExample.mmp new file mode 100644 index 000000000..1ee5a1190 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/CameraWrapperExample.mmp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +TARGET ZXingBarcodeReader_0xEF24C10A.exe +TARGETTYPE exe +UID 0x100039CE 0xEF24C10A +VENDORID 0 +EPOCSTACKSIZE 0x5000 + +SOURCEPATH ..\data + +START RESOURCE ZXingBarcodeReader.rss +HEADER +TARGET ZXingBarcodeReader_0xEF24C10A +TARGETPATH resource\apps +END //RESOURCE + +START RESOURCE ZXingBarcodeReader_reg.rss +TARGET ZXingBarcodeReader_0xEF24C10A_reg +TARGETPATH \private\10003a3f\apps +END //RESOURCE + +SYSTEMINCLUDE /epoc32/include +SYSTEMINCLUDE /epoc32/include/stdapis +SYSTEMINCLUDE /epoc32/include/stdapis/sys +SYSTEMINCLUDE /epoc32/include/stdapis/stlport +SYSTEMINCLUDE /epoc32/include/variant +SYSTEMINCLUDE /epoc32/include/ecom +SYSTEMINCLUDE /epoc32/include/stdapis/stlport/stl + +SYSTEMINCLUDE . +SYSTEMINCLUDE ../inc +SYSTEMINCLUDE zxing/common/reedsolomon +SYSTEMINCLUDE zxing/oned +SYSTEMINCLUDE zxing/qrcode +SYSTEMINCLUDE zxing/qrcode/decoder +SYSTEMINCLUDE zxing/qrcode/detector + +SOURCEPATH ../src +SOURCE CameraWrapperExample.cpp +SOURCE CameraWrapperExampleApplication.cpp +SOURCE CameraWrapperExampleAppView.cpp +SOURCE CameraWrapperExampleAppUi.cpp +SOURCE CameraWrapperExampleDocument.cpp +SOURCE CameraImage.cpp + +LIBRARY euser.lib +LIBRARY apparc.lib +LIBRARY cone.lib +LIBRARY eikcore.lib +LIBRARY avkon.lib +LIBRARY commonengine.lib +LIBRARY efsrv.lib +LIBRARY estor.lib +LIBRARY aknnotify.lib +LIBRARY fbscli.lib +LIBRARY bitgdi.lib +LIBRARY eikcoctl.lib +LIBRARY PlatformEnv.lib // PathInfo +LIBRARY bafl.lib // BafUtils +LIBRARY ecam.lib // Camera +LIBRARY camerawrapper.lib // CameraWrapper library +LIBRARY libc.lib +LIBRARY libm.lib +LIBRARY libdl.lib +LIBRARY libstdcpp.lib + +CAPABILITY UserEnvironment + +SOURCEPATH zxing/common/reedsolomon +SOURCE GF256.cpp GF256Poly.cpp ReedSolomonDecoder.cpp ReedSolomonException.cpp +SOURCEPATH zxing/common +SOURCE Array.cpp BitArray.cpp BitMatrix.cpp BitSource.cpp Counted.cpp DecoderResult.cpp DetectorResult.cpp EdgeDetector.cpp GlobalHistogramBinarizer.cpp GridSampler.cpp IllegalArgumentException.cpp LocalBlockBinarizer.cpp PerspectiveTransform.cpp Str.cpp +SOURCEPATH zxing/oned +SOURCE Code128Reader.cpp Code39Reader.cpp EAN13Reader.cpp EAN8Reader.cpp ITFReader.cpp MultiFormatOneDReader.cpp MultiFormatUPCEANReader.cpp OneDReader.cpp OneDResultPoint.cpp UPCAReader.cpp UPCEANReader.cpp UPCEReader.cpp +SOURCEPATH zxing/qrcode/decoder +SOURCE BitMatrixParser.cpp DataBlock.cpp DataMask.cpp DecodedBitStreamParser.cpp Decoder.cpp Mode.cpp +SOURCEPATH zxing/qrcode/detector +SOURCE AlignmentPattern.cpp AlignmentPatternFinder.cpp Detector.cpp FinderPattern.cpp FinderPatternFinder.cpp FinderPatternInfo.cpp QREdgeDetector.cpp +SOURCEPATH zxing/qrcode +SOURCE ErrorCorrectionLevel.cpp FormatInformation.cpp QRCodeReader.cpp Version.cpp +SOURCEPATH zxing +SOURCE BarcodeFormat.cpp Binarizer.cpp BinaryBitmap.cpp Exception.cpp LuminanceSource.cpp MultiFormatReader.cpp Reader.cpp ReaderException.cpp Result.cpp ResultPoint.cpp + +OPTION CW -wchar_t on +OPTION ARMCC --visibility_inlines_hidden +OPTION GCCE -fvisibility-inlines-hidden + +SOURCEPATH ../src +SOURCE DecodingOperations.cpp diff --git a/symbian/ZXingBarcodeReader/group/Icons_scalable_dc.mk b/symbian/ZXingBarcodeReader/group/Icons_scalable_dc.mk new file mode 100644 index 000000000..f29691fea --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/Icons_scalable_dc.mk @@ -0,0 +1,40 @@ + +ifeq (WINS,$(findstring WINS, $(PLATFORM))) +ZDIR=$(EPOCROOT)epoc32\release\$(PLATFORM)\$(CFG)\Z +else +ZDIR=$(EPOCROOT)epoc32\data\z +endif + +TARGETDIR=$(ZDIR)\resource\apps +ICONTARGETFILENAME=$(TARGETDIR)\ZXingBarcodeReader_0xEF24C10A.mif + +ICONDIR=..\gfx + +do_nothing : + @rem do_nothing + +MAKMAKE : do_nothing + +BLD : do_nothing + +CLEAN : do_nothing + +LIB : do_nothing + +CLEANLIB : do_nothing + +RESOURCE : $(ICONTARGETFILENAME) + +$(ICONTARGETFILENAME) : $(ICONDIR)\QrDecoder.svg + mifconv $(ICONTARGETFILENAME) \ + /c32 $(ICONDIR)\QrDecoder.svg + +FREEZE : do_nothing + +SAVESPACE : do_nothing + +RELEASABLES : + @echo $(ICONTARGETFILENAME) + +FINAL : do_nothing + diff --git a/symbian/ZXingBarcodeReader/group/bld.inf b/symbian/ZXingBarcodeReader/group/bld.inf new file mode 100644 index 000000000..c196b5053 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/bld.inf @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +PRJ_PLATFORMS +WINSCW GCCE ARMV5 + +PRJ_MMPFILES +gnumakefile icons_scalable_dc.mk +CameraWrapperExample.mmp + diff --git a/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.cpp b/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.cpp new file mode 100644 index 000000000..b31afccf1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.cpp @@ -0,0 +1,22 @@ +/* + * BarcodeFormat.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + diff --git a/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.h b/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.h new file mode 100644 index 000000000..943831dad --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/BarcodeFormat.h @@ -0,0 +1,42 @@ +#ifndef __BARCODE_FORMAT_H__ +#define __BARCODE_FORMAT_H__ + +/* + * BarcodeFormat.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Modified by Lukasz Warchol on 02/02/2010 + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace zxing { + + typedef enum BarcodeFormat { + BarcodeFormat_None = 0, + BarcodeFormat_QR_CODE, + BarcodeFormat_DATA_MATRIX, + BarcodeFormat_UPC_E, + BarcodeFormat_UPC_A, + BarcodeFormat_EAN_8, + BarcodeFormat_EAN_13, + BarcodeFormat_CODE_128, + BarcodeFormat_CODE_39, + BarcodeFormat_ITF + } BarcodeFormat; + +} + +#endif // __BARCODE_FORMAT_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp new file mode 100644 index 000000000..5f6e746bc --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.cpp @@ -0,0 +1,48 @@ +/* + * Binarizer.cpp + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + Binarizer::Binarizer(Ref source) : source_(source) { + } + + Binarizer::~Binarizer() { + } + + Ref Binarizer::getBlackRow(int y, Ref row){ + if (array_ == NULL) + array_ = estimateBlackRow(y, row); + return array_; + } + + Ref Binarizer::getBlackMatrix() { + if (matrix_ == NULL) + matrix_ = estimateBlackMatrix(); + return matrix_; + } + + Ref Binarizer::getSource() { + return source_; + } + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h new file mode 100644 index 000000000..ea1240c0b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Binarizer.h @@ -0,0 +1,51 @@ +/* + * Binarizer.h + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BINARIZER_H_ +#define BINARIZER_H_ + +#include +#include +#include +#include + +namespace zxing { + + class Binarizer : public Counted { + private: + Ref source_; + Ref matrix_; + Ref array_; + + public: + Binarizer(Ref source); + virtual ~Binarizer(); + + virtual Ref estimateBlackRow(int y, Ref row)=0; + Ref getBlackRow(int y, Ref row); + + virtual Ref estimateBlackMatrix() = 0; + Ref getBlackMatrix(); + Ref getSource(); + }; + +} +#endif /* BINARIZER_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp new file mode 100644 index 000000000..1e692a9f5 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.cpp @@ -0,0 +1,57 @@ +/* + * BinaryBitmap.cpp + * zxing + * + * Created by Ralf Kistner on 19/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + + BinaryBitmap::BinaryBitmap(Ref binarizer) : bits_(NULL), binarizer_(binarizer) { + + } + + BinaryBitmap::~BinaryBitmap() { + } + + Ref BinaryBitmap::getBlackRow(int y, Ref row) { + if (array_bits_ == NULL) { + array_bits_ = binarizer_->getBlackRow(y, row); + } + return array_bits_; + } + + Ref BinaryBitmap::getBlackMatrix() { + if (bits_ == NULL) { + bits_ = binarizer_->getBlackMatrix(); + } + return bits_; + } + int BinaryBitmap::getWidth() { + return getSource()->getWidth(); + } + int BinaryBitmap::getHeight() { + return getSource()->getHeight(); + } + + Ref BinaryBitmap::getSource() { + return binarizer_->getSource(); + } + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h new file mode 100644 index 000000000..ecd9a8549 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/BinaryBitmap.h @@ -0,0 +1,51 @@ +/* + * BinaryBitmap.h + * zxing + * + * Created by Ralf Kistner on 19/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef BINARYBITMAP_H_ +#define BINARYBITMAP_H_ + +#include +#include +#include +#include + +namespace zxing { + + class BinaryBitmap : public Counted { + private: + Ref bits_; + Ref array_bits_; + Ref binarizer_; + + public: + BinaryBitmap(Ref binarizer); + virtual ~BinaryBitmap(); + + Ref getBlackRow(int y, Ref row); + Ref getBlackMatrix(); + Ref getSource(); + + int getWidth(); + int getHeight(); + }; + +} + +#endif /* BINARYBITMAP_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp b/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp new file mode 100644 index 000000000..47143c964 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Exception.cpp @@ -0,0 +1,25 @@ +/* + * Exception.cpp + * ZXing + * + * Created by Christian Brunschen on 03/06/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + */ + +#include + +namespace zxing { + +Exception::Exception(const char *msg) : + message(msg) { +} + +const char* Exception::what() const throw() { + return message; +} + +Exception::~Exception() throw() { +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/Exception.h b/symbian/ZXingBarcodeReader/group/zxing/Exception.h new file mode 100644 index 000000000..7502c5cb6 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Exception.h @@ -0,0 +1,40 @@ +#ifndef __EXCEPTION_H__ +#define __EXCEPTION_H__ + +/* + * Exception.h + * ZXing + * + * Created by Christian Brunschen on 03/06/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + +class Exception : public std::exception { +private: + const char * message; + +public: + Exception(const char *msg); + virtual const char* what() const throw(); + virtual ~Exception() throw(); +}; + +} +#endif // __EXCEPTION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.cpp b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.cpp new file mode 100644 index 000000000..6c8ef1e6e --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.cpp @@ -0,0 +1,43 @@ +/* + * LuminanceSource.cpp + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +LuminanceSource::LuminanceSource() { +} + +LuminanceSource::~LuminanceSource() { +} + +unsigned char* LuminanceSource::copyMatrix() { + int width = getWidth(); + int height = getHeight(); + unsigned char* matrix = new unsigned char[width*height]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + matrix[y*width+x] = getPixel(x, y); + } + } + return matrix; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h new file mode 100644 index 000000000..e23621ef9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/LuminanceSource.h @@ -0,0 +1,42 @@ +/* + * LuminanceSource.h + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LUMINANCESOURCE_H_ +#define LUMINANCESOURCE_H_ + +#include + +namespace zxing { + +class LuminanceSource : public Counted { +public: + LuminanceSource(); + virtual ~LuminanceSource(); + + virtual int getWidth() = 0; + virtual int getHeight() = 0; + + virtual unsigned char getPixel(int x, int y) = 0; + virtual unsigned char* copyMatrix(); +}; + +} + +#endif /* LUMINANCESOURCE_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp new file mode 100644 index 000000000..fd3d8d2f5 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.cpp @@ -0,0 +1,54 @@ +/* + * MultiFormatBarcodeReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Modified by Luiz Silva on 09/02/2010. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MultiFormatReader.h" +#include +//#include +#include +#include +#include + +namespace zxing { + MultiFormatReader::MultiFormatReader(){ + readers = new std::vector(); + + readers->push_back(new zxing::qrcode::QRCodeReader()); + //readers->push_back(new zxing::datamatrix::DataMatrixReader()); + readers->push_back(new zxing::oned::MultiFormatUPCEANReader()); + readers->push_back(new zxing::oned::MultiFormatOneDReader()); + } + + Ref MultiFormatReader::decode(Ref image){ + int size = readers->size(); + for (int i = 0; i < size; i++) { + Reader* reader = (*readers)[i]; + try { + return reader->decode(image); + } catch (ReaderException re) { + // continue + } + } + throw ReaderException("No code detected"); + } + MultiFormatReader::~MultiFormatReader(){ + delete readers; + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h new file mode 100644 index 000000000..9fca54f6c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/MultiFormatReader.h @@ -0,0 +1,38 @@ +/* + * MultiFormatBarcodeReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include + +namespace zxing { + class MultiFormatReader : public Reader { + + private: + std::vector* readers; + public: + MultiFormatReader(); + + Ref decode(Ref image); + + ~MultiFormatReader(); + }; +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/Reader.cpp new file mode 100644 index 000000000..1e1fdc39b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Reader.cpp @@ -0,0 +1,27 @@ +/* + * Reader.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +Reader::~Reader() { } + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/Reader.h b/symbian/ZXingBarcodeReader/group/zxing/Reader.h new file mode 100644 index 000000000..3de270f95 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Reader.h @@ -0,0 +1,38 @@ +#ifndef __READER_H__ +#define __READER_H__ + +/* + * Reader.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + +class Reader { +public: + virtual Ref decode(Ref image) = 0; + virtual ~Reader(); +}; + +} + +#endif // __READER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/ReaderException.cpp b/symbian/ZXingBarcodeReader/group/zxing/ReaderException.cpp new file mode 100644 index 000000000..7d2bc9d98 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/ReaderException.cpp @@ -0,0 +1,32 @@ +/* + * ReaderException.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +ReaderException::ReaderException(const char *msg) : + Exception(msg) { +} + +ReaderException::~ReaderException() throw() { +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/ReaderException.h b/symbian/ZXingBarcodeReader/group/zxing/ReaderException.h new file mode 100644 index 000000000..1a31ae8e9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/ReaderException.h @@ -0,0 +1,35 @@ +#ifndef __READER_EXCEPTION_H__ +#define __READER_EXCEPTION_H__ + +/* + * ReaderException.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +class ReaderException : public Exception { +public: + ReaderException(const char *msg); + ~ReaderException() throw(); +}; + +} +#endif // __READER_EXCEPTION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/Result.cpp b/symbian/ZXingBarcodeReader/group/zxing/Result.cpp new file mode 100644 index 000000000..f87ef8844 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Result.cpp @@ -0,0 +1,59 @@ +/* + * Result.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +using namespace std; + +Result::Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, + BarcodeFormat format) : + text_(text), rawBytes_(rawBytes), resultPoints_(resultPoints), format_(format) { +} + +Result::~Result() { +} + +Ref Result::getText() { + return text_; +} + +ArrayRef Result::getRawBytes() { + return rawBytes_; +} + +std::vector > Result::getResultPoints() { + return resultPoints_; +} + +BarcodeFormat Result::getBarcodeFormat() { + return format_; +} + +ostream& operator<<(ostream &out, Result& result) { + if (result.text_ != 0) { + out << result.text_->getText(); + } else { + out << "[" << result.rawBytes_->size() << " bytes]"; + } + return out; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/Result.h b/symbian/ZXingBarcodeReader/group/zxing/Result.h new file mode 100644 index 000000000..710d8d5a6 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/Result.h @@ -0,0 +1,54 @@ +#ifndef __RESULT_H__ +#define __RESULT_H__ + +/* + * Result.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + +class Result : public Counted { +private: + Ref text_; + ArrayRef rawBytes_; + std::vector > resultPoints_; + BarcodeFormat format_; + +public: + Result(Ref text, ArrayRef rawBytes, std::vector > resultPoints, + BarcodeFormat format); + ~Result(); + Ref getText(); + ArrayRef getRawBytes(); + std::vector > getResultPoints(); + BarcodeFormat getBarcodeFormat(); + + friend std::ostream& operator<<(std::ostream &out, Result& result); +}; + +} +#endif // __RESULT_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.cpp b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.cpp new file mode 100644 index 000000000..464956873 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.cpp @@ -0,0 +1,22 @@ +/* + * ResultPoint.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + diff --git a/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h new file mode 100644 index 000000000..6118cc0dc --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/ResultPoint.h @@ -0,0 +1,36 @@ +#ifndef __RESULT_POINT_H__ +#define __RESULT_POINT_H__ + +/* + * ResultPoint.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +class ResultPoint : public Counted { +public: + virtual float getX() = 0; + virtual float getY() = 0; +}; + +} + +#endif // __RESULT_POINT_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Array.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/Array.cpp new file mode 100644 index 000000000..aa1834a27 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Array.cpp @@ -0,0 +1,22 @@ +/* + * Array.cpp + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Array.h b/symbian/ZXingBarcodeReader/group/zxing/common/Array.h new file mode 100644 index 000000000..39b178607 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Array.h @@ -0,0 +1,209 @@ +#ifndef __ARRAY_H__ +#define __ARRAY_H__ + +/* + * Array.h + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#ifdef DEBUG_COUNTING +#include +#include +#endif + +#include + + +namespace zxing { + +template class Array : public Counted { +protected: +public: + std::valarray values_; + Array(size_t n) : + Counted(), values_(T(), n) { + } + Array(T *ts, size_t n) : + Counted(), values_(ts, n) { + } + Array(T v, size_t n) : + Counted(), values_(v, n) { + } + Array(std::valarray &v) : + Counted(), values_(v) { + } + Array(Array &other) : + Counted(), values_(other.values_) { + } + Array(Array *other) : + Counted(), values_(other->values_) { + } + virtual ~Array() { + } + Array& operator=(const Array &other) { +#ifdef DEBUG_COUNTING + cout << "assigning values from Array " << &other << " to this Array " << this << ", "; +#endif + values_ = other.values_; +#ifdef DEBUG_COUNTING + cout << "new size = " << values_.size() << "\n"; +#endif + return *this; + } + Array& operator=(const std::valarray &array) { +#ifdef DEBUG_COUNTING + cout << "assigning values from Array " << &array << " to this Array " << this << ", "; +#endif + values_ = array; +#ifdef DEBUG_COUNTING + cout << "new size = " << values_.size() << "\n"; +#endif + return *this; + } + T operator[](size_t i) const { + return values_[i]; + } + T& operator[](size_t i) { + return values_[i]; + } + size_t size() const { + return values_.size(); + } + std::valarray values() const { + return values_; + } + std::valarray& values() { + return values_; + } +}; + +template class ArrayRef { +private: +public: + Array *array_; + ArrayRef() : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating empty ArrayRef " << this << "\n"; +#endif + } + ArrayRef(size_t n) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << "with size " << n << "\n"; +#endif + reset(new Array (n)); + } + ArrayRef(T *ts, size_t n) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << "with " << n << " elements at " << (void *)ts << "\n"; +#endif + reset(new Array (ts, n)); + } + ArrayRef(Array *a) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from pointer:\n"; +#endif + reset(a); + } + ArrayRef(const Array &a) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from reference to Array " << (void *)&a << ":\n"; +#endif + reset(const_cast *>(&a)); + } + ArrayRef(const ArrayRef &other) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from ArrayRef " << &other << ":\n"; +#endif + reset(other.array_); + } + + template + ArrayRef(const ArrayRef &other) : + array_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating ArrayRef " << this << " from ArrayRef " << &other << ":\n"; +#endif + reset(static_cast *>(other.array_)); + } + + ~ArrayRef() { +#ifdef DEBUG_COUNTING + cout << "destroying ArrayRef " << this << " with " << (array_ ? typeid(*array_).name() : "NULL") << " " + << array_ << "\n"; +#endif + if (array_) { + array_->release(); + } + array_ = 0; + } + + T operator[](size_t i) const { + return (*array_)[i]; + } + T& operator[](size_t i) { + return (*array_)[i]; + } + size_t size() const { + return array_->size(); + } + + void reset(Array *a) { +#ifdef DEBUG_COUNTING + cout << "resetting ArrayRef " << this << " from " << (array_ ? typeid(*array_).name() : "NULL") << " " + << array_ << " to " << (a ? typeid(*a).name() : "NULL") << " " << a << "\n"; +#endif + if (a) { + a->retain(); + } + if (array_) { + array_->release(); + } + array_ = a; + } + void reset(const ArrayRef &other) { + reset(other.array_); + } + ArrayRef& operator=(const ArrayRef &other) { + reset(other); + return *this; + } + ArrayRef& operator=(Array *a) { + reset(a); + return *this; + } + + Array& operator*() { + return *array_; + } + Array* operator->() { + return array_; + } +}; + +} // namespace zxing + +#endif // __ARRAY_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp new file mode 100644 index 000000000..26e686930 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.cpp @@ -0,0 +1,118 @@ +/* + * BitArray.cpp + * zxing + * + * Created by Christian Brunschen on 09/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +using namespace std; + +namespace zxing { +static unsigned int logDigits(unsigned digits) { + unsigned log = 0; + unsigned val = 1; + while (val < digits) { + log++; + val <<= 1; + } + return log; +} +const unsigned int BitArray::bitsPerWord_ = numeric_limits::digits; +const unsigned int BitArray::logBits_ = logDigits(bitsPerWord_); +const unsigned int BitArray::bitsMask_ = (1 << logBits_) - 1; +size_t BitArray::wordsForBits(size_t bits) { + int arraySize = bits >> logBits_; + if (bits - (arraySize << logBits_) != 0) { + arraySize++; + } + return arraySize; +} +BitArray::BitArray() { + cout << "hey! don't use this BitArrayConstructor!\n"; +} + +BitArray::BitArray(size_t size) : + size_(size), bits_((const unsigned int)0, wordsForBits(size)) { +} +BitArray::~BitArray() { +} +size_t BitArray::getSize() { + return size_; +} +bool BitArray::get(size_t i) { + return (bits_[i >> logBits_] & (1 << (i & bitsMask_))) != 0; +} +void BitArray::set(size_t i) { + bits_[i >> logBits_] |= 1 << (i & bitsMask_); +} +void BitArray::setBulk(size_t i, unsigned int newBits) { + bits_[i >> logBits_] = newBits; +} +void BitArray::clear() { + size_t max = bits_.size(); + for (size_t i = 0; i < max; i++) { + bits_[i] = 0; + } +} +bool BitArray::isRange(size_t start, size_t end, bool value) { + if (end < start) { + throw IllegalArgumentException("end must be after start"); + } + if (end == start) { + return true; + } + // treat the 'end' as inclusive, rather than exclusive + end--; + size_t firstWord = start >> logBits_; + size_t lastWord = end >> logBits_; + for (size_t i = firstWord; i <= lastWord; i++) { + size_t firstBit = i > firstWord ? 0 : start & bitsMask_; + size_t lastBit = i < lastWord ? logBits_ : end & bitsMask_; + unsigned int mask; + if (firstBit == 0 && lastBit == logBits_) { + mask = numeric_limits::max(); + } else { + mask = 0; + for (size_t j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + if (value) { + if ((bits_[i] & mask) != mask) { + return false; + } + } else { + if ((bits_[i] & mask) != 0) { + return false; + } + } + } + return true; +} +valarray& BitArray::getBitArray() { + return bits_; +} +void BitArray::reverse() { + unsigned int allBits = numeric_limits::max(); + size_t max = bits_.size(); + for (size_t i = 0; i < max; i++) { + bits_[i] = bits_[i] ^ allBits; + } +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h new file mode 100644 index 000000000..1e8828e96 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitArray.h @@ -0,0 +1,57 @@ +#ifndef __BIT_ARRAY_H__ +#define __BIT_ARRAY_H__ + +/* + * BitArray.h + * zxing + * + * Created by Christian Brunschen on 09/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { + +class BitArray : public Counted { +private: + size_t size_; + std::valarray bits_; + static const unsigned int bitsPerWord_; + static const unsigned int logBits_; + static const unsigned int bitsMask_; + static size_t wordsForBits(size_t bits); + explicit BitArray(); + +public: + BitArray(size_t size); + ~BitArray(); + size_t getSize(); + bool get(size_t i); + void set(size_t i); + void setBulk(size_t i, unsigned int newBits); + void clear(); + bool isRange(size_t start, size_t end, bool value); + std::valarray& getBitArray(); + void reverse(); +}; + +} + +#endif // __BIT_ARRAY_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp new file mode 100644 index 000000000..9256c4097 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.cpp @@ -0,0 +1,148 @@ +/* + * BitMatrix.cpp + * zxing + * + * Created by Christian Brunschen on 12/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include + +namespace zxing { +using namespace std; + +unsigned int logDigits(unsigned digits) { + unsigned log = 0; + unsigned val = 1; + while (val < digits) { + log++; + val <<= 1; + } + return log; +} + + +const unsigned int bitsPerWord = std::numeric_limits::digits; +const unsigned int logBits = logDigits(bitsPerWord); +const unsigned int bitsMask = (1 << logBits) - 1; + +static size_t wordsForSize(size_t width, size_t height) { + size_t bits = width * height; + int arraySize = bits >> logBits; + if (bits - (arraySize << logBits) != 0) { + arraySize++; + } + return arraySize; +} + +BitMatrix::BitMatrix(size_t dimension) : + width_(dimension), height_(dimension), bits_(NULL) { + + words_ = wordsForSize(width_, height_); + bits_ = new unsigned int[words_]; + clear(); +} + +BitMatrix::BitMatrix(size_t width, size_t height) : + width_(width), height_(height), bits_(NULL) { + + words_ = wordsForSize(width_, height_); + bits_ = new unsigned int[words_]; + clear(); +} + +BitMatrix::~BitMatrix() { + delete[] bits_; +} + + +bool BitMatrix::get(size_t x, size_t y) const { + size_t offset = x + width_ * y; + return ((bits_[offset >> logBits] >> (offset & bitsMask)) & 0x01) != 0; +} + +void BitMatrix::set(size_t x, size_t y) { + size_t offset = x + width_ * y; + bits_[offset >> logBits] |= 1 << (offset & bitsMask); +} + +void BitMatrix::flip(size_t x, size_t y) { + size_t offset = x + width_ * y; + bits_[offset >> logBits] ^= 1 << (offset & bitsMask); +} + +void BitMatrix::clear() { + std::memset(bits_, 0, sizeof(unsigned int) * words_); +} + +void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) { + if (top < 0 || left < 0) { + throw IllegalArgumentException("topI and leftJ must be nonnegative"); + } + if (height < 1 || width < 1) { + throw IllegalArgumentException("height and width must be at least 1"); + } + size_t right = left + width; + size_t bottom = top + height; + if (right > width_ || bottom > height_) { + throw IllegalArgumentException("top + height and left + width must be <= matrix dimension"); + } + for (size_t y = top; y < bottom; y++) { + int yOffset = width_ * y; + for (size_t x = left; x < right; x++) { + size_t offset = x + yOffset; + bits_[offset >> logBits] |= 1 << (offset & bitsMask); + } + } +} + +size_t BitMatrix::getWidth() const { + return width_; +} + +size_t BitMatrix::getHeight() const { + return height_; +} + +size_t BitMatrix::getDimension() const { + return width_; +} + +unsigned int* BitMatrix::getBits() { + return bits_; +} + +ostream& operator<<(ostream &out, BitMatrix &bm) { + for (size_t y = 0; y < bm.height_; y++) { + for (size_t x = 0; x < bm.width_; x++) { + out << (bm.get(x, y) ? "X " : " "); + } + out << "\n"; + } + return out; +} +const char *BitMatrix::description() { + ostringstream out; + out << *this; + return out.str().c_str(); +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h new file mode 100644 index 000000000..e8f8f847e --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitMatrix.h @@ -0,0 +1,61 @@ +#ifndef __BIT_MATRIX_H__ +#define __BIT_MATRIX_H__ + +/* + * BitMatrix.h + * zxing + * + * Created by Christian Brunschen on 12/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + +class BitMatrix : public Counted { +private: + size_t width_; + size_t height_; + size_t words_; + unsigned int* bits_; + +public: + BitMatrix(size_t dimension); + BitMatrix(size_t width, size_t height); + + ~BitMatrix(); + // Inlining this does not really improve performance. + bool get(size_t x, size_t y) const; + void set(size_t x, size_t y); + void flip(size_t x, size_t y); + void clear(); + void setRegion(size_t left, size_t top, size_t width, size_t height); + + size_t getDimension() const; + size_t getWidth() const; + size_t getHeight() const; + + unsigned int* getBits(); + + friend std::ostream& operator<<(std::ostream &out, BitMatrix &bm); + const char *description(); +}; + +} + +#endif // __BIT_MATRIX_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.cpp new file mode 100644 index 000000000..4b53b4da7 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.cpp @@ -0,0 +1,75 @@ +/* + * BitSource.cpp + * zxing + * + * Created by Christian Brunschen on 09/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + +int BitSource::readBits(int numBits) { + if (numBits < 0 || numBits > 32) { + throw IllegalArgumentException("cannot read <1 or >32 bits"); + } else if (numBits > available()) { + throw IllegalArgumentException("reading more bits than are available"); + } + + int result = 0; + + + // First, read remainder from current byte + if (bitOffset_ > 0) { + int bitsLeft = 8 - bitOffset_; + int toRead = numBits < bitsLeft ? numBits : bitsLeft; + int bitsToNotRead = bitsLeft - toRead; + int mask = (0xFF >> (8 - toRead)) << bitsToNotRead; + result = (bytes_[byteOffset_] & mask) >> bitsToNotRead; + numBits -= toRead; + bitOffset_ += toRead; + if (bitOffset_ == 8) { + bitOffset_ = 0; + byteOffset_++; + } + } + + // Next read whole bytes + if (numBits > 0) { + while (numBits >= 8) { + result = (result << 8) | (bytes_[byteOffset_] & 0xFF); + byteOffset_++; + numBits -= 8; + } + + + // Finally read a partial byte + if (numBits > 0) { + int bitsToNotRead = 8 - numBits; + int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; + result = (result << numBits) | ((bytes_[byteOffset_] & mask) >> bitsToNotRead); + bitOffset_ += numBits; + } + } + + return result; +} + +int BitSource::available() { + return 8 * (bytes_.size() - byteOffset_) - bitOffset_; +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.h b/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.h new file mode 100644 index 000000000..78201738f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/BitSource.h @@ -0,0 +1,68 @@ +#ifndef __BIT_SOURCE_H__ +#define __BIT_SOURCE_H__ + +/* + * BitSource.h + * zxing + * + * Created by Christian Brunschen on 09/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +/** + *

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

+ * + *

This class is not thread-safe.

+ * + * @author srowen@google.com (Sean Owen) + * @author christian.brunschen@gmail.com (Christian Brunschen) + */ +class BitSource : public Counted { + typedef unsigned char byte; +private: + ArrayRef bytes_; + int byteOffset_; + int bitOffset_; +public: + /** + * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. + * Bits are read within a byte from most-significant to least-significant bit. + */ + BitSource(ArrayRef &bytes) : + bytes_(bytes), byteOffset_(0), bitOffset_(0) { + } + + + /** + * @param numBits number of bits to read + * @return int representing the bits read. The bits will appear as the least-significant + * bits of the int + * @throws IllegalArgumentException if numBits isn't in [1,32] + */ + int readBits(int numBits); + + /** + * @return number of bits that can be read successfully + */ + int available(); +}; + +} + +#endif // __BIT_SOURCE_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Counted.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.cpp new file mode 100644 index 000000000..fb2a99b06 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.cpp @@ -0,0 +1,32 @@ +/* + * Counted.cpp + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +using namespace std; + +template +ostream& operator<<(ostream &out, Ref& ref) { + out << "Ref(" << (ref.object_ ? (*ref.object_) : "NULL") << ")"; + return out; +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h new file mode 100644 index 000000000..dd0f84552 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Counted.h @@ -0,0 +1,202 @@ +#ifndef __COUNTED_H__ +#define __COUNTED_H__ + +/* + * Counted.h + * zxing + * + * Created by Christian Brunschen on 07/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define DEBUG_COUNTING +//using namespace std; + +#include + +#ifdef DEBUG_COUNTING +#include +#endif + +namespace zxing { + +/* base class for reference-counted objects */ +class Counted { +private: + unsigned int count_; +public: + Counted() : + count_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating " << typeid(*this).name() << " " << this << + " @ " << count_ << "\n"; +#endif + } + virtual ~Counted() { + } + virtual Counted *retain() { +#ifdef DEBUG_COUNTING + cout << "retaining " << typeid(*this).name() << " " << this << + " @ " << count_; +#endif + count_++; +#ifdef DEBUG_COUNTING + cout << "->" << count_ << "\n"; +#endif + return this; + } + virtual void release() { +#ifdef DEBUG_COUNTING + cout << "releasing " << typeid(*this).name() << " " << this << + " @ " << count_; +#endif + if (count_ == 0 || count_ == 54321) { +#ifdef DEBUG_COUNTING + cout << "\nOverreleasing already-deleted object " << this << "!!!\n"; +#endif + throw 4711; + } + count_--; +#ifdef DEBUG_COUNTING + cout << "->" << count_ << "\n"; +#endif + if (count_ == 0) { +#ifdef DEBUG_COUNTING + cout << "deleting " << typeid(*this).name() << " " << this << "\n"; +#endif + count_ = 0xDEADF001; + delete this; + } + } + + + /* return the current count for denugging purposes or similar */ + int count() const { + return count_; + } +}; + +/* counting reference to reference-counted objects */ +template class Ref { +private: +public: + T *object_; + explicit Ref(T *o = 0) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from pointer" << o << "\n"; +#endif + reset(o); + } + + explicit Ref(const T &o) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from reference\n"; +#endif + reset(const_cast(&o)); + } + + Ref(const Ref &other) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from Ref " << &other << "\n"; +#endif + reset(other.object_); + } + + template + Ref(const Ref &other) : + object_(0) { +#ifdef DEBUG_COUNTING + cout << "instantiating Ref " << this << " from reference\n"; +#endif + reset(other.object_); + } + + ~Ref() { +#ifdef DEBUG_COUNTING + cout << "destroying Ref " << this << " with " << + (object_ ? typeid(*object_).name() : "NULL") << " " << object_ << "\n"; +#endif + if (object_) { + object_->release(); + } + } + + void reset(T *o) { +#ifdef DEBUG_COUNTING + cout << "resetting Ref " << this << " from " << + (object_ ? typeid(*object_).name() : "NULL") << " " << object_ << + " to " << (o ? typeid(*o).name() : "NULL") << " " << o << "\n"; +#endif + if (o) { + o->retain(); + } + if (object_ != 0) { + object_->release(); + } + object_ = o; + } + Ref& operator=(const Ref &other) { + reset(other.object_); + return *this; + } + template + Ref& operator=(const Ref &other) { + reset(other.object_); + return *this; + } + Ref& operator=(T* o) { + reset(o); + return *this; + } + template + Ref& operator=(Y* o) { + reset(o); + return *this; + } + + T& operator*() { + return *object_; + } + T* operator->() { + return object_; + } + operator T*() { + return object_; + } + + bool operator==(const int x) { + return x == 0 ? object_ == 0 : false; + } + bool operator==(const Ref &other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + template + bool operator==(const Ref &other) const { + return object_ == other.object_ || *object_ == *(other.object_); + } + + bool operator!=(const int x) { + return x == 0 ? object_ != 0 : true; + } + + template + friend std::ostream& operator<<(std::ostream &out, Ref& ref); +}; +} + +#endif // __COUNTED_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.cpp new file mode 100644 index 000000000..86b11f810 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.cpp @@ -0,0 +1,37 @@ +/* + * DecoderResult.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text) : + rawBytes_(rawBytes), text_(text) { +} + +ArrayRef DecoderResult::getRawBytes() { + return rawBytes_; +} + +Ref DecoderResult::getText() { + return text_; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.h b/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.h new file mode 100644 index 000000000..1e3e42b2a --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/DecoderResult.h @@ -0,0 +1,44 @@ +#ifndef __DECODER_RESULT_H__ +#define __DECODER_RESULT_H__ + +/* + * DecoderResult.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { + +class DecoderResult : public Counted { +private: + ArrayRef rawBytes_; + Ref text_; + +public: + DecoderResult(ArrayRef rawBytes, Ref text); + ArrayRef getRawBytes(); + Ref getText(); +}; + +} + +#endif // __DECODER_RESULT_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.cpp new file mode 100644 index 000000000..a314cfe79 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.cpp @@ -0,0 +1,41 @@ +/* + * DetectorResult.cpp + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +DetectorResult::DetectorResult(Ref bits, std::vector > points, Ref transform) : + bits_(bits), points_(points), transform_(transform) { +} + +Ref DetectorResult::getBits() { + return bits_; +} + +std::vector > DetectorResult::getPoints() { + return points_; +} + +Ref DetectorResult::getTransform() { + return transform_; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.h b/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.h new file mode 100644 index 000000000..ba8f9a821 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/DetectorResult.h @@ -0,0 +1,47 @@ +#ifndef __DETECTOR_RESULT_H__ +#define __DETECTOR_RESULT_H__ + +/* + * DetectorResult.h + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { + +class DetectorResult : public Counted { +private: + Ref bits_; + std::vector > points_; + Ref transform_; + +public: + DetectorResult(Ref bits, std::vector > points, Ref transform); + Ref getBits(); + std::vector > getPoints(); + Ref getTransform(); +}; +} + +#endif // __DETECTOR_RESULT_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp new file mode 100644 index 000000000..3f0b403cc --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.cpp @@ -0,0 +1,190 @@ +/* + * EdgeDetector.cpp + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +using namespace std; + +namespace zxing { +namespace EdgeDetector { + +void findEdgePoints(std::vector& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation) { + float xdist = end.x - start.x; + float ydist = end.y - start.y; + float length = sqrt(xdist * xdist + ydist * ydist); + + + int var; + + if (abs(xdist) > abs(ydist)) { + // Horizontal + if (xdist < 0) + skip = -skip; + + var = int(abs(deviation * length / xdist)); + + float dy = ydist / xdist * skip; + bool left = (skip < 0) ^ invert; + int x = int(start.x); + + int steps = int(xdist / skip); + for (int i = 0; i < steps; i++) { + x += skip; + if (x < 0 || x >= (int)image.getWidth()) + continue; // In case we start off the edge + int my = int(start.y + dy * i); + int ey = min(my + var + 1, (int)image.getHeight() - 1); + int sy = max(my - var, 0); + for (int y = sy + 1; y < ey; y++) { + if (left) { + if (image.get(x, y) && !image.get(x, y + 1)) { + points.push_back(Point(x, y + 0.5f)); + } + } else { + if (!image.get(x, y) && image.get(x, y + 1)) { + points.push_back(Point(x, y + 0.5f)); + } + } + } + } + } else { + // Vertical + if (ydist < 0) + skip = -skip; + + var = int(abs(deviation * length / ydist)); + + float dx = xdist / ydist * skip; + bool down = (skip > 0) ^ invert; + int y = int(start.y); + + int steps = int(ydist / skip); + for (int i = 0; i < steps; i++) { + y += skip; + if (y < 0 || y >= (int)image.getHeight()) + continue; // In case we start off the edge + int mx = int(start.x + dx * i); + int ex = min(mx + var + 1, (int)image.getWidth() - 1); + int sx = max(mx - var, 0); + for (int x = sx + 1; x < ex; x++) { + if (down) { + if (image.get(x, y) && !image.get(x + 1, y)) { + points.push_back(Point(x + 0.5f, y)); + } + + } else { + if (!image.get(x, y) && image.get(x + 1, y)) { + points.push_back(Point(x + 0.5f, y)); + } + } + + } + } + + } +} + +Line findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip) { + float t = threshold * threshold; + + Point start = estimate.start; + Point end = estimate.end; + + vector edges; + edges.clear(); + findEdgePoints(edges, image, start, end, invert, skip, deviation); + + int n = edges.size(); + + float xdist = end.x - start.x; + float ydist = end.y - start.y; + + bool horizontal = abs(xdist) > abs(ydist); + + float max = 0; + Line bestLine(start, end); // prepopulate with the given line, in case we can't find any line for some reason + + for (int i = -deviation; i < deviation; i++) { + float x1, y1; + if (horizontal) { + y1 = start.y + i; + x1 = start.x - i * ydist / xdist; + } else { + y1 = start.y - i * xdist / ydist; + x1 = start.x + i; + } + + for (int j = -deviation; j < deviation; j++) { + float x2, y2; + if (horizontal) { + y2 = end.y + j; + x2 = end.x - j * ydist / xdist; + } else { + y2 = end.y - j * xdist / ydist; + x2 = end.x + j; + } + + float dx = x1 - x2; + float dy = y1 - y2; + float length = sqrt(dx * dx + dy * dy); + + float score = 0; + + for(int k = 0; k < n; k++) { + const Point& edge = edges[k]; + float dist = ((x1 - edge.x) * dy - (y1 - edge.y) * dx) / length; + // Similar to least squares method + float s = t - dist * dist; + if (s > 0) + score += s; + } + + if (score > max) { + max = score; + bestLine.start = Point(x1, y1); + bestLine.end = Point(x2, y2); + } + } + } + + return bestLine; +} + +Point intersection(Line a, Line b) { + float dxa = a.start.x - a.end.x; + float dxb = b.start.x - b.end.x; + float dya = a.start.y - a.end.y; + float dyb = b.start.y - b.end.y; + + float p = a.start.x * a.end.y - a.start.y * a.end.x; + float q = b.start.x * b.end.y - b.start.y * b.end.x; + float denom = dxa * dyb - dya * dxb; + if(denom == 0) // Lines don't intersect + return Point(INFINITY, INFINITY); + + float x = (p * dxb - dxa * q) / denom; + float y = (p * dyb - dya * q) / denom; + + return Point(x, y); +} + +} // namespace EdgeDetector +} // namespace zxing diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.h b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.h new file mode 100644 index 000000000..3698c1c8b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/EdgeDetector.h @@ -0,0 +1,38 @@ +/* + * EdgeDetector.h + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef EDGEDETECTOR_H_ +#define EDGEDETECTOR_H_ + +#include +#include +#include + +namespace zxing { +namespace EdgeDetector { + +void findEdgePoints(std::vector& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation); +Line findLine(const BitMatrix& image, Line estimate, bool invert, int deviation, float threshold, int skip); + +Point intersection(Line a, Line b); + +} +} +#endif /* EDGEDETECTOR_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp new file mode 100644 index 000000000..8767dbd34 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.cpp @@ -0,0 +1,177 @@ +/* + * GlobalHistogramBinarizer.cpp + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace zxing { + using namespace std; + + const int LUMINANCE_BITS = 5; + const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS; + const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS; + + GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref source) : + Binarizer(source) { + + } + + GlobalHistogramBinarizer::~GlobalHistogramBinarizer() { + } + + + Ref GlobalHistogramBinarizer::estimateBlackRow(int y, Ref row){ + valarray histogram(0, LUMINANCE_BUCKETS); + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + if (row == NULL || row->getSize() < width) { + row = new BitArray(width); + } else { + row->clear(); + } + + for (int x = 0; x < width; x++) { + unsigned char pixel = source.getPixel(x, y); + histogram[pixel >> LUMINANCE_SHIFT]++; + } + int blackPoint = estimate(histogram) << LUMINANCE_SHIFT; + + + Ref array_ref(new BitArray(width)); + BitArray& array = *array_ref; + + int left = source.getPixel(0, y); + int center = source.getPixel(1, y); + for (int x = 1; x < width - 1; x++) { + int right = source.getPixel(x+1, y); + // A simple -1 4 -1 box filter with a weight of 2. + int luminance = ((center << 2) - left - right) >> 1; + if (luminance < blackPoint) { + array.set(x); + } + left = center; + center = right; + } + + return array_ref; + } + + Ref GlobalHistogramBinarizer::estimateBlackMatrix() { + // Faster than working with the reference + LuminanceSource& source = *getSource(); + int width = source.getWidth(); + int height = source.getHeight(); + valarray histogram(0, LUMINANCE_BUCKETS); + + + // Quickly calculates the histogram by sampling four rows from the image. This proved to be + // more robust on the blackbox tests than sampling a diagonal as we used to do. + for (int y = 1; y < 5; y++) { + int row = height * y / 5; + int right = (width << 2) / 5; + int sdf; + for (int x = width / 5; x < right; x++) { + unsigned char pixel = source.getPixel(x, row); + histogram[pixel >> LUMINANCE_SHIFT]++; + sdf = histogram[pixel >> LUMINANCE_SHIFT]; + } + } + + int blackPoint = estimate(histogram) << LUMINANCE_SHIFT; + + Ref matrix_ref(new BitMatrix(width, height)); + BitMatrix& matrix = *matrix_ref; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (source.getPixel(x, y) <= blackPoint) + matrix.set(x, y); + } + } + return matrix_ref; + } + + int GlobalHistogramBinarizer::estimate(valarray &histogram) { + int numBuckets = histogram.size(); + int maxBucketCount = 0; + + + // Find tallest peak in histogram + int firstPeak = 0; + int firstPeakSize = 0; + for (int i = 0; i < numBuckets; i++) { + if (histogram[i] > firstPeakSize) { + firstPeak = i; + firstPeakSize = histogram[i]; + } + if (histogram[i] > maxBucketCount) { + maxBucketCount = histogram[i]; + } + } + + // Find second-tallest peak -- well, another peak that is tall and not + // so close to the first one + int secondPeak = 0; + int secondPeakScore = 0; + for (int i = 0; i < numBuckets; i++) { + int distanceToBiggest = i - firstPeak; + // Encourage more distant second peaks by multiplying by square of distance + int score = histogram[i] * distanceToBiggest * distanceToBiggest; + if (score > secondPeakScore) { + secondPeak = i; + secondPeakScore = score; + } + } + + // Put firstPeak first + if (firstPeak > secondPeak) { + int temp = firstPeak; + firstPeak = secondPeak; + secondPeak = temp; + } + + // Kind of arbitrary; if the two peaks are very close, then we figure there is so little + // dynamic range in the image, that discriminating black and white is too error-prone. + // Decoding the image/line is either pointless, or may in some cases lead to a false positive + // for 1D formats, which are relatively lenient. + // We arbitrarily say "close" is "<= 1/16 of the total histogram buckets apart" + if (secondPeak - firstPeak <= numBuckets >> 4) { + throw IllegalArgumentException("Too little dynamic range in luminance"); + } + + // Find a valley between them that is low and closer to the white peak + int bestValley = secondPeak - 1; + int bestValleyScore = -1; + for (int i = secondPeak - 1; i > firstPeak; i--) { + int fromFirst = i - firstPeak; + // Favor a "valley" that is not too close to either peak -- especially not the black peak -- + // and that has a low value of course + int score = fromFirst * fromFirst * (secondPeak - i) * (maxBucketCount - histogram[i]); + if (score > bestValleyScore) { + bestValley = i; + bestValleyScore = score; + } + } + + return bestValley; + } + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h new file mode 100644 index 000000000..6735c5b9f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GlobalHistogramBinarizer.h @@ -0,0 +1,44 @@ +/* + * GlobalHistogramBinarizer.h + * zxing + * + * Created by Ralf Kistner on 16/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * Modified by Lukasz Warchol on 02/02/2010. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GLOBALHISTOGRAMBINARIZER_H_ +#define GLOBALHISTOGRAMBINARIZER_H_ + +#include +#include +#include +#include + +namespace zxing { + + class GlobalHistogramBinarizer : public Binarizer { + public: + GlobalHistogramBinarizer(Ref source); + virtual ~GlobalHistogramBinarizer(); + + virtual Ref estimateBlackRow(int y, Ref row); + virtual Ref estimateBlackMatrix(); + static int estimate(std::valarray &histogram); + }; + +} + +#endif /* GLOBALHISTOGRAMBINARIZER_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp new file mode 100644 index 000000000..06bb602c1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.cpp @@ -0,0 +1,101 @@ +/* + * GridSampler.cpp + * zxing + * + * Created by Christian Brunschen on 18/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +using namespace std; + +GridSampler GridSampler::gridSampler; + +GridSampler::GridSampler() { +} + +Ref GridSampler::sampleGrid(Ref image, int dimension, Ref transform) { + Ref bits(new BitMatrix(dimension)); + valarray points((const float)0.0f, dimension << 1); + for (int y = 0; y < dimension; y++) { + int max = points.size(); + float yValue = (float)y + 0.5f; + for (int x = 0; x < max; x += 2) { + points[x] = (float)(x >> 1) + 0.5f; + points[x + 1] = yValue; + } + transform->transformPoints(points); + checkAndNudgePoints(image, points); + for (int x = 0; x < max; x += 2) { + if (image->get((int)points[x], (int)points[x + 1])) { + bits->set(x >> 1, y); + } + } + } + return bits; +} + +Ref GridSampler::sampleGrid(Ref image, int dimension, float p1ToX, float p1ToY, float p2ToX, + float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, + float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, + p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY)); + + return sampleGrid(image, dimension, transform); + +} + +void GridSampler::checkAndNudgePoints(Ref image, valarray &points) { + int width = image->getWidth(); + int height = image->getHeight(); + + + // The Java code assumes that if the start and end points are in bounds, the rest will also be. + // However, in some unusual cases points in the middle may also be out of bounds. + // Since we can't rely on an ArrayIndexOutOfBoundsException like Java, we check every point. + + for (size_t offset = 0; offset < points.size(); offset += 2) { + int x = (int)points[offset]; + int y = (int)points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) { + ostringstream s; + s << "Transformed point out of bounds at " << x << "," << y; + throw ReaderException(s.str().c_str()); + } + + if (x == -1) { + points[offset] = 0.0f; + } else if (x == width) { + points[offset] = width - 1; + } + if (y == -1) { + points[offset + 1] = 0.0f; + } else if (y == height) { + points[offset + 1] = height - 1; + } + } + +} + +GridSampler &GridSampler::getInstance() { + return gridSampler; +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h new file mode 100644 index 000000000..3dd577dcb --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/GridSampler.h @@ -0,0 +1,44 @@ +#ifndef __GRID_SAMPLER_H__ +#define __GRID_SAMPLER_H__ + +/* + * GridSampler.h + * zxing + * + * Created by Christian Brunschen on 18/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +class GridSampler { +private: + static GridSampler gridSampler; + GridSampler(); + +public: + Ref sampleGrid(Ref image, int dimension, Ref transform); + Ref sampleGrid(Ref image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, + float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, + float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY); + static void checkAndNudgePoints(Ref image, std::valarray &points); + static GridSampler &getInstance(); +}; +} + +#endif // __GRID_SAMPLER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.cpp new file mode 100644 index 000000000..49068ca5d --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.cpp @@ -0,0 +1,31 @@ +/* + * IllegalArgumentException.cpp + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +IllegalArgumentException::IllegalArgumentException(const char *msg) : + Exception(msg) { +} +IllegalArgumentException::~IllegalArgumentException() throw() { + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.h b/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.h new file mode 100644 index 000000000..5def73636 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/IllegalArgumentException.h @@ -0,0 +1,34 @@ +#ifndef __ILLEGAL_ARGUMENT_EXCEPTION_H__ +#define __ILLEGAL_ARGUMENT_EXCEPTION_H__ + +/* + * IllegalArgumentException.h + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +class IllegalArgumentException : public zxing::Exception { +public: + IllegalArgumentException(const char *msg); + ~IllegalArgumentException() throw(); +}; +} + +#endif // __ILLEGAL_ARGUMENT_EXCEPTION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.cpp new file mode 100644 index 000000000..135902a6d --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.cpp @@ -0,0 +1,196 @@ +/* + * LocalBlockBinarizer.cpp + * zxing + * + * Created by Ralf Kistner on 17/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + +const int GLOBAL = 0; +const int THRESHOLD = 1; + +LocalBlockBinarizer::LocalBlockBinarizer(Ref source) : + Binarizer(source) { + +} + +LocalBlockBinarizer::~LocalBlockBinarizer() { +} + +Ref LocalBlockBinarizer::estimateBlackRow(int y, Ref row) { + //TODO: implement + return Ref(); +} + +// Calculates the final BitMatrix once for all requests. This could be called once from the +// constructor instead, but there are some advantages to doing it lazily, such as making +// profiling easier, and not doing heavy lifting when callers don't expect it. +Ref LocalBlockBinarizer::estimateBlackMatrix() { + Ref source = getSource(); + unsigned char* luminances = source->copyMatrix(); + int width = source->getWidth(); + int height = source->getHeight(); + // Sharpening does not really help for 2d barcodes + // sharpenRow(luminances, width, height); + + int subWidth = width >> 3; + int subHeight = height >> 3; + + unsigned char* averages = new unsigned char[subWidth * subHeight]; + unsigned char* types = new unsigned char[subWidth * subHeight]; + + calculateBlackPoints(luminances, averages, types, subWidth, subHeight, width); + + Ref matrix(new BitMatrix(width, height)); + calculateThresholdForBlock(luminances, subWidth, subHeight, width, averages, types, *matrix); + + delete[] averages; + delete[] types; + delete[] luminances; + + return matrix; +} + +// For each 8x8 block in the image, calculate the average black point using a 5x5 grid +// of the blocks around it. Also handles the corner cases, but will ignore up to 7 pixels +// on the right edge and 7 pixels at the bottom of the image if the overall dimensions are not +// multiples of eight. In practice, leaving those pixels white does not seem to be a problem. +void LocalBlockBinarizer::calculateThresholdForBlock(const unsigned char* luminances, int subWidth, int subHeight, + int stride, const unsigned char* averages, const unsigned char* types, BitMatrix& matrix) { + // Calculate global average + int global = 0; + for (int y = 0; y < subHeight; y++) { + for (int x = 0; x < subWidth; x++) { + global += averages[y * subWidth + x]; + } + } + + global /= subWidth * subHeight; + + + for (int y = 0; y < subHeight; y++) { + for (int x = 0; x < subWidth; x++) { + int left = (x > 0) ? x : 1; + left = (left < subWidth - 1) ? left : subWidth - 2; + int top = (y > 0) ? y : 1; + top = (top < subHeight - 1) ? top : subHeight - 2; + int sum = 0; + int contrast = 0; + for (int z = -1; z <= 1; z++) { +// sum += averages[(top + z) * subWidth + left - 2]; + sum += averages[(top + z) * subWidth + left - 1]; + sum += averages[(top + z) * subWidth + left]; + sum += averages[(top + z) * subWidth + left + 1]; +// sum += averages[(top + z) * subWidth + left + 2]; + +// type += types[(top + z) * subWidth + left - 2]; + contrast += types[(top + z) * subWidth + left - 1]; + contrast += types[(top + z) * subWidth + left]; + contrast += types[(top + z) * subWidth + left + 1]; +// type += types[(top + z) * subWidth + left + 2]; + } + int average = sum / 9; + + + if (contrast > 2) + threshold8x8Block(luminances, x << 3, y << 3, average, stride, matrix); +// else if(average < global) // Black +// matrix.setRegion(x << 3, y << 3, 8, 8); + // If white, we don't need to do anything - the block is already cleared. + } + } +} + +// Applies a single threshold to an 8x8 block of pixels. +void LocalBlockBinarizer::threshold8x8Block(const unsigned char* luminances, int xoffset, int yoffset, int threshold, + int stride, BitMatrix& matrix) { + for (int y = 0; y < 8; y++) { + int offset = (yoffset + y) * stride + xoffset; + for (int x = 0; x < 8; x++) { + int pixel = luminances[offset + x]; + if (pixel < threshold) { + matrix.set(xoffset + x, yoffset + y); + } + } + } +} + +// Calculates a single black point for each 8x8 block of pixels and saves it away. +void LocalBlockBinarizer::calculateBlackPoints(const unsigned char* luminances, unsigned char* averages, + unsigned char* types, int subWidth, int subHeight, int stride) { + for (int y = 0; y < subHeight; y++) { + for (int x = 0; x < subWidth; x++) { + int sum = 0; + int min = 255; + int max = 0; + for (int yy = 0; yy < 8; yy++) { + int offset = ((y << 3) + yy) * stride + (x << 3); + const unsigned char* lumo = luminances + offset; + for (int xx = 0; xx < 8; xx++) { + int pixel = lumo[xx]; + sum += pixel; + if (pixel < min) { + min = pixel; + } + if (pixel > max) { + max = pixel; + } + } + } + + // If the contrast is inadequate, we treat the block as white. + // An arbitrary value is chosen here. Higher values mean less noise, but may also reduce + // the ability to recognise some barcodes. + int average = sum >> 6; + int type; + + if (max - min > 30) + type = THRESHOLD; + else + type = GLOBAL; + // int average = (max - min > 24) ? (sum >> 6) : (min-1); + averages[y * subWidth + x] = average; + types[y * subWidth + x] = type; + } + } +} + +// Applies a simple -1 4 -1 box filter with a weight of 2 to each row. +void LocalBlockBinarizer::sharpenRow(unsigned char* luminances, int width, int height) { + for (int y = 0; y < height; y++) { + int offset = y * width; + int left = luminances[offset]; + int center = luminances[offset + 1]; + for (int x = 1; x < width - 1; x++) { + unsigned char right = luminances[offset + x + 1]; + int pixel = ((center << 2) - left - right) >> 1; + // Must clamp values to 0..255 so they will fit in a byte. + if (pixel > 255) { + pixel = 255; + } else if (pixel < 0) { + pixel = 0; + } + luminances[offset + x] = (unsigned char)pixel; + left = center; + center = right; + } + } +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.h b/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.h new file mode 100644 index 000000000..bae80bc75 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/LocalBlockBinarizer.h @@ -0,0 +1,47 @@ +/* + * LocalBlockBinarizer.h + * zxing + * + * Created by Ralf Kistner on 17/10/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOCALBLOCKBINARIZER_H_ +#define LOCALBLOCKBINARIZER_H_ + +#include +#include + +namespace zxing { +class LocalBlockBinarizer : public Binarizer { +public: + LocalBlockBinarizer(Ref source); + virtual ~LocalBlockBinarizer(); + + virtual Ref estimateBlackMatrix(); + Ref estimateBlackRow(int y, Ref row); + +private: + + void calculateThresholdForBlock(const unsigned char* luminances, int subWidth, int subHeight, + int stride, const unsigned char* averages, const unsigned char* types, BitMatrix& matrix); + void sharpenRow(unsigned char* luminances, int width, int height); + void calculateBlackPoints(const unsigned char* luminances, unsigned char* averages, unsigned char* types, int subWidth, int subHeight, int stride); + void threshold8x8Block(const unsigned char* luminances, int xoffset, int yoffset, int threshold, + int stride, BitMatrix& matrix); +}; +} + +#endif /* LOCALBLOCKBINARIZER_H_ */ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp new file mode 100644 index 000000000..44d9ddcb0 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.cpp @@ -0,0 +1,121 @@ +/* + * PerspectiveTransform.cpp + * zxing + * + * Created by Christian Brunschen on 12/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +using namespace std; + +PerspectiveTransform::PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, + float a23, float a33) { + this->a11 = a11; + this->a12 = a12; + this->a13 = a13; + this->a21 = a21; + this->a22 = a22; + this->a23 = a23; + this->a31 = a31; + this->a32 = a32; + this->a33 = a33; +} + +Ref PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, + float x3p, float y3p) { + Ref qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); + Ref sToQ = + PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); + return sToQ->times(qToS); +} + +Ref PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, + float y2, float x3, float y3) { + float dy2 = y3 - y2; + float dy3 = y0 - y1 + y2 - y3; + if (dy2 == 0.0f && dy3 == 0.0f) { + Ref result(new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, + 0.0f, 1.0f)); + return result; + } else { + float dx1 = x1 - x2; + float dx2 = x3 - x2; + float dx3 = x0 - x1 + x2 - x3; + float dy1 = y1 - y2; + float denominator = dx1 * dy2 - dx2 * dy1; + float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; + float a23 = (dx1 * dy3 - dx3 * dy1) / denominator; + Ref result(new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f)); + return result; + } +} + +Ref PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, + float y2, float x3, float y3) { + // Here, the adjoint serves as the inverse: + return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)->buildAdjoint(); +} + +Ref PerspectiveTransform::buildAdjoint() { + // Adjoint is the transpose of the cofactor matrix: + Ref result(new PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32 + - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22, + a13 * a21 - a11 * a23, a11 * a22 - a12 * a21)); + return result; +} + +Ref PerspectiveTransform::times(Ref other) { + Ref result(new PerspectiveTransform(a11 * other->a11 + a21 * other->a12 + a31 * other->a13, + a11 * other->a21 + a21 * other->a22 + a31 * other->a23, a11 * other->a31 + a21 * other->a32 + a31 + * other->a33, a12 * other->a11 + a22 * other->a12 + a32 * other->a13, a12 * other->a21 + a22 + * other->a22 + a32 * other->a23, a12 * other->a31 + a22 * other->a32 + a32 * other->a33, a13 + * other->a11 + a23 * other->a12 + a33 * other->a13, a13 * other->a21 + a23 * other->a22 + a33 + * other->a23, a13 * other->a31 + a23 * other->a32 + a33 * other->a33)); + return result; +} + +void PerspectiveTransform::transformPoints(valarray &points) { + int max = points.size(); + float a11 = this->a11; + float a12 = this->a12; + float a13 = this->a13; + float a21 = this->a21; + float a22 = this->a22; + float a23 = this->a23; + float a31 = this->a31; + float a32 = this->a32; + float a33 = this->a33; + for (int i = 0; i < max; i += 2) { + float x = points[i]; + float y = points[i + 1]; + float denominator = a13 * x + a23 * y + a33; + points[i] = (a11 * x + a21 * y + a31) / denominator; + points[i + 1] = (a12 * x + a22 * y + a32) / denominator; + } +} + +ostream& operator<<(ostream& out, PerspectiveTransform &pt) { + out << pt.a11 << ", " << pt.a12 << ", " << pt.a13 << ", \n"; + out << pt.a21 << ", " << pt.a22 << ", " << pt.a23 << ", \n"; + out << pt.a31 << ", " << pt.a32 << ", " << pt.a33 << "\n"; + return out; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h new file mode 100644 index 000000000..581f92880 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/PerspectiveTransform.h @@ -0,0 +1,50 @@ +#ifndef __PERSPECTIVE_TANSFORM_H__ +#define __PERSPECTIVE_TANSFORM_H__ + +/* + * PerspectiveTransform.h + * zxing + * + * Created by Christian Brunschen on 12/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { +class PerspectiveTransform : public Counted { +private: + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, + float a33); + +public: + static Ref + quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, + float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p); + static Ref squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + static Ref quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, + float x3, float y3); + Ref buildAdjoint(); + Ref times(Ref other); + void transformPoints(std::valarray &points); + + friend std::ostream& operator<<(std::ostream& out, PerspectiveTransform &pt); +}; +} + +#endif // __PERSPECTIVE_TANSFORM_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Point.h b/symbian/ZXingBarcodeReader/group/zxing/common/Point.h new file mode 100644 index 000000000..a391042fe --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Point.h @@ -0,0 +1,47 @@ +/* + * Point.h + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ZXING_POINT_H_ +#define ZXING_POINT_H_ + +namespace zxing { +class PointI { +public: + int x; + int y; +}; + +class Point { +public: + Point(float x_, float y_) : x(x_), y(y_) {}; + + float x; + float y; +}; + +class Line { +public: + Line(Point start_, Point end_) : start(start_), end(end_) {}; + + Point start; + Point end; +}; +} +#endif // POINT_H_ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp new file mode 100644 index 000000000..e2122dc3a --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Str.cpp @@ -0,0 +1,38 @@ +/* + * String.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +using namespace std; + +String::String(const std::string &text) : + text_(text) { +} +std::string& String::getText() { + return text_; +} + +ostream &operator<<(ostream &out, const String &s) { + out << s.text_; + return out; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/Str.h b/symbian/ZXingBarcodeReader/group/zxing/common/Str.h new file mode 100644 index 000000000..255a05531 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/Str.h @@ -0,0 +1,41 @@ +#ifndef __COMMON__STRING_H__ +#define __COMMON__STRING_H__ + +/* + * String.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + +class String : public Counted { +private: + std::string text_; +public: + String(const std::string &text); + std::string &getText(); + friend std::ostream &operator<<(std::ostream &out, const String &s); +}; + +} + +#endif // __COMMON__STRING_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp new file mode 100644 index 000000000..8add88934 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.cpp @@ -0,0 +1,140 @@ +/* + * GF256.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { +using namespace std; + +static inline ArrayRef makeArray(int value) { + ArrayRef valuesRef(new Array (value, 1)); + return valuesRef; +} + +static inline Ref refPoly(GF256 &field, int value) { + ArrayRef values(makeArray(value)); + Ref result(new GF256Poly(field, values)); + return result; +} + +GF256::GF256(int primitive) : + exp_((const int)0, 256), log_((const int)0, 256), zero_(refPoly(*this, 0)), one_(refPoly(*this, 1)) { + int x = 1; + for (int i = 0; i < 256; i++) { + exp_[i] = x; + x <<= 1; + if (x >= 0x100) { + x ^= primitive; + } + } + + // log(0) == 0, but should never be used + log_[0] = 0; + for (int i = 0; i < 255; i++) { + log_[exp_[i]] = i; + } +} + +Ref GF256::getZero() { + return zero_; +} + +Ref GF256::getOne() { + return one_; +} + +Ref GF256::buildMonomial(int degree, int coefficient) { +#ifdef DEBUG + cout << __FUNCTION__ << "\n"; +#endif + if (degree < 0) { + throw IllegalArgumentException("Degree must be non-negative"); + } + if (coefficient == 0) { + return zero_; + } + int nCoefficients = degree + 1; + ArrayRef coefficients(new Array (nCoefficients)); + coefficients[0] = coefficient; + Ref result(new GF256Poly(*this, coefficients)); + return result; +} + +int GF256::addOrSubtract(int a, int b) { + return a ^ b; +} + +int GF256::exp(int a) { + return exp_[a]; +} + +int GF256::log(int a) { + if (a == 0) { + throw IllegalArgumentException("Cannot take the logarithm of 0"); + } + return log_[a]; +} + +int GF256::inverse(int a) { + if (a == 0) { + throw IllegalArgumentException("Cannot calculate the inverse of 0"); + } + return exp_[255 - log_[a]]; +} + +int GF256::multiply(int a, int b) { + if (a == 0 || b == 0) { + return 0; + } + if (a == 1) { + return b; + } + if (b == 1) { + return a; + } + return exp_[(log_[a] + log_[b]) % 255]; +} + +GF256 GF256::QR_CODE_FIELD(0x011D); // x^8 + x^4 + x^3 + x^2 + 1 +GF256 GF256::DATA_MATRIX_FIELD(0x012D); // x^8 + x^5 + x^3 + x^2 + 1 + +ostream& operator<<(ostream& out, const GF256& field) { + out << "Field[\nexp=("; + out << field.exp_[0]; + for (int i = 1; i < 256; i++) { + out << "," << field.exp_[i]; + } + out << "),\nlog=("; + out << field.log_[0]; + for (int i = 1; i < 256; i++) { + out << "," << field.log_[i]; + } + out << ")\n]"; + return out; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h new file mode 100644 index 000000000..0930f63bf --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256.h @@ -0,0 +1,69 @@ +#ifndef __GF256_H__ +#define __GF256_H__ + +/* + * GF256.h + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +class GF256Poly; + +class GF256 { + /** + *

This class contains utility methods for performing mathematical + * operations over the Galois Field GF(256). Operations use a given + * primitive polynomial in calculations.

+ * + *

Throughout this package, elements of GF(256) are represented as an + * int for convenience and speed (but at the cost of memory). + * Only the bottom 8 bits are really used.

+ * + * @author srowen@google.com (Sean Owen) + * @author christian.brunschen@gmail.com (Christian Brunschen) + */ +private: + std::valarray exp_; + std::valarray log_; + Ref zero_; + Ref one_; + + GF256(int primitive); + +public: + Ref getZero(); + Ref getOne(); + Ref buildMonomial(int degree, int coefficient); + static int addOrSubtract(int a, int b); + int exp(int a); + int log(int a); + int inverse(int a); + int multiply(int a, int b); + + static GF256 QR_CODE_FIELD; + static GF256 DATA_MATRIX_FIELD; + + friend std::ostream& operator<<(std::ostream& out, const GF256& field); +}; +} + +#endif // __GF256_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.cpp new file mode 100644 index 000000000..2c7f4812e --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.cpp @@ -0,0 +1,198 @@ +/* + * GF256Poly.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +using namespace std; + +void GF256Poly::fixCoefficients() { + int coefficientsLength = coefficients.size(); + if (coefficientsLength > 1 && coefficients[0] == 0) { + // Leading term must be non-zero for anything except + // the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + coefficientsLength = field.getZero()->coefficients.size(); + coefficients.reset(new Array (coefficientsLength)); + *coefficients = *(field.getZero()->coefficients); + } else { + ArrayRef c(coefficients); + coefficientsLength -= firstNonZero; + coefficients.reset(new Array (coefficientsLength)); + for (int i = 0; i < coefficientsLength; i++) { + coefficients[i] = c[i + firstNonZero]; + } + } + } +} + +GF256Poly::GF256Poly(GF256 &f, ArrayRef c) : + Counted(), field(f), coefficients(c) { + fixCoefficients(); +} + +GF256Poly::~GF256Poly() { + +} + +int GF256Poly::getDegree() { + return coefficients.size() - 1; +} + +bool GF256Poly::isZero() { + return coefficients[0] == 0; +} + +int GF256Poly::getCoefficient(int degree) { + return coefficients[coefficients.size() - 1 - degree]; +} + +int GF256Poly::evaluateAt(int a) { + if (a == 0) { + return getCoefficient(0); + } + int size = coefficients.size(); + if (a == 1) { + // Just the sum of the coefficients + int result = 0; + for (int i = 0; i < size; i++) { + result = GF256::addOrSubtract(result, coefficients[i]); + } + return result; + } + int result = coefficients[0]; + for (int i = 1; i < size; i++) { + result = GF256::addOrSubtract(field.multiply(a, result), coefficients[i]); + } + return result; +} + +Ref GF256Poly::addOrSubtract(Ref b) { + if (&field != &b->field) { + throw IllegalArgumentException("Fields must be the same"); + } + if (isZero()) { + return b; + } + if (b->isZero()) { + return Ref(this); + } + + ArrayRef largerCoefficients = coefficients; + ArrayRef smallerCoefficients = b->coefficients; + if (smallerCoefficients.size() > largerCoefficients.size()) { + ArrayRef tmp(smallerCoefficients); + smallerCoefficients = largerCoefficients; + largerCoefficients = tmp; + } + + ArrayRef sumDiff(new Array (largerCoefficients.size())); + + unsigned lengthDiff = largerCoefficients.size() - smallerCoefficients.size(); + for (unsigned i = 0; i < lengthDiff; i++) { + sumDiff[i] = largerCoefficients[i]; + } + for (unsigned i = lengthDiff; i < largerCoefficients.size(); i++) { + sumDiff[i] = GF256::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); + } + return Ref(new GF256Poly(field, sumDiff)); +} + +Ref GF256Poly::multiply(Ref b) { + if (&field != &b->field) { + throw IllegalArgumentException("Fields must be the same"); + } + if (isZero() || b->isZero()) { + return field.getZero(); + } + ArrayRef aCoefficients = coefficients; + int aLength = aCoefficients.size(); + ArrayRef bCoefficients = b->coefficients; + int bLength = bCoefficients.size(); + int productLength = aLength + bLength - 1; + ArrayRef product(new Array (productLength)); + for (int i = 0; i < aLength; i++) { + int aCoeff = aCoefficients[i]; + for (int j = 0; j < bLength; j++) { + product[i + j] = GF256::addOrSubtract(product[i + j], field.multiply(aCoeff, bCoefficients[j])); + } + } + + return Ref(new GF256Poly(field, product)); +} + +Ref GF256Poly::multiply(int scalar) { + if (scalar == 0) { + return field.getZero(); + } + if (scalar == 1) { + return Ref(this); + } + int size = coefficients.size(); + ArrayRef product(new Array (size)); + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], scalar); + } + return Ref(new GF256Poly(field, product)); +} + +Ref GF256Poly::multiplyByMonomial(int degree, int coefficient) { + if (degree < 0) { + throw IllegalArgumentException("Degree must be non-negative"); + } + if (coefficient == 0) { + return field.getZero(); + } + int size = coefficients.size(); + ArrayRef product(new Array (size + degree)); + for (int i = 0; i < size; i++) { + product[i] = field.multiply(coefficients[i], coefficient); + } + return Ref(new GF256Poly(field, product)); +} + +const char *GF256Poly::description() const { + ostringstream result; + result << *this; + return result.str().c_str(); +} + +ostream& operator<<(ostream& out, const GF256Poly& p) { + GF256Poly &poly = const_cast(p); + out << "Poly[" << poly.coefficients.size() << "]"; + if (poly.coefficients.size() > 0) { + out << "(" << poly.coefficients[0]; + for (unsigned i = 1; i < poly.coefficients.size(); i++) { + out << "," << poly.coefficients[i]; + } + out << ")"; + } + return out; +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.h b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.h new file mode 100644 index 000000000..e036f29c0 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/GF256Poly.h @@ -0,0 +1,54 @@ +#ifndef __GF256_POLY_H__ +#define __GF256_POLY_H__ + +/* + * GF256Poly.h + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +class GF256; + +class GF256Poly : public Counted { +private: + GF256 &field; + ArrayRef coefficients; + void fixCoefficients(); +public: + GF256Poly(GF256 &field, ArrayRef c); + ~GF256Poly(); + + int getDegree(); + bool isZero(); + int getCoefficient(int degree); + int evaluateAt(int a); + Ref addOrSubtract(Ref other); + Ref multiply(Ref other); + Ref multiply(int scalar); + Ref multiplyByMonomial(int degree, int coefficient); + const char *description() const; + friend std::ostream& operator<<(std::ostream& out, const GF256Poly& poly); + +}; +} + +#endif // __GF256_POLY_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.cpp new file mode 100644 index 000000000..58a95a8e1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.cpp @@ -0,0 +1,193 @@ +/* + * ReedSolomonDecoder.cpp + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace zxing { + +ReedSolomonDecoder::ReedSolomonDecoder(GF256 &fld) : + field(fld) { +} + +ReedSolomonDecoder::~ReedSolomonDecoder() { +} + +void ReedSolomonDecoder::decode(ArrayRef received, int twoS) { + + Ref poly(new GF256Poly(field, received)); + + +#ifdef DEBUG + cout << "decoding with poly " << *poly << "\n"; +#endif + + ArrayRef syndromeCoefficients(new Array (twoS)); + + +#ifdef DEBUG + cout << "syndromeCoefficients array = " << + syndromeCoefficients.array_ << "\n"; +#endif + + bool noError = true; + for (int i = 0; i < twoS; i++) { + int eval = poly->evaluateAt(field.exp(i)); + syndromeCoefficients[syndromeCoefficients->size() - 1 - i] = eval; + if (eval != 0) { + noError = false; + } + } + if (noError) { + return; + } + + Ref syndrome(new GF256Poly(field, syndromeCoefficients)); + Ref monomial(field.buildMonomial(twoS, 1)); + vector > sigmaOmega(runEuclideanAlgorithm(monomial, syndrome, twoS)); + ArrayRef errorLocations = findErrorLocations(sigmaOmega[0]); + ArrayRef errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations); + for (unsigned i = 0; i < errorLocations->size(); i++) { + int position = received->size() - 1 - field.log(errorLocations[i]); + //TODO: check why the position would be invalid + if (position < 0 || (size_t)position >= received.size()) + throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)"); + received[position] = GF256::addOrSubtract(received[position], errorMagitudes[i]); + } +} + +vector > ReedSolomonDecoder::runEuclideanAlgorithm(Ref a, Ref b, int R) { + // Assume a's degree is >= b's + if (a->getDegree() < b->getDegree()) { + Ref tmp = a; + a = b; + b = tmp; + } + + Ref rLast(a); + Ref r(b); + Ref sLast(field.getOne()); + Ref s(field.getZero()); + Ref tLast(field.getZero()); + Ref t(field.getOne()); + + + // Run Euclidean algorithm until r's degree is less than R/2 + while (r->getDegree() >= R / 2) { + Ref rLastLast(rLast); + Ref sLastLast(sLast); + Ref tLastLast(tLast); + rLast = r; + sLast = s; + tLast = t; + + + // Divide rLastLast by rLast, with quotient q and remainder r + if (rLast->isZero()) { + // Oops, Euclidean algorithm already terminated? + throw ReedSolomonException("r_{i-1} was zero"); + } + r = rLastLast; + Ref q(field.getZero()); + int denominatorLeadingTerm = rLast->getCoefficient(rLast->getDegree()); + int dltInverse = field.inverse(denominatorLeadingTerm); + while (r->getDegree() >= rLast->getDegree() && !r->isZero()) { + int degreeDiff = r->getDegree() - rLast->getDegree(); + int scale = field.multiply(r->getCoefficient(r->getDegree()), dltInverse); + q = q->addOrSubtract(field.buildMonomial(degreeDiff, scale)); + r = r->addOrSubtract(rLast->multiplyByMonomial(degreeDiff, scale)); + } + + s = q->multiply(sLast)->addOrSubtract(sLastLast); + t = q->multiply(tLast)->addOrSubtract(tLastLast); + } + + int sigmaTildeAtZero = t->getCoefficient(0); + if (sigmaTildeAtZero == 0) { + throw ReedSolomonException("sigmaTilde(0) was zero"); + } + + int inverse = field.inverse(sigmaTildeAtZero); + Ref sigma(t->multiply(inverse)); + Ref omega(r->multiply(inverse)); + + +#ifdef DEBUG + cout << "t = " << *t << "\n"; + cout << "r = " << *r << "\n"; + cout << "sigma = " << *sigma << "\n"; + cout << "omega = " << *omega << "\n"; +#endif + + vector > result(2); + result[0] = sigma; + result[1] = omega; + return result; +} + +ArrayRef ReedSolomonDecoder::findErrorLocations(Ref errorLocator) { + // This is a direct application of Chien's search + int numErrors = errorLocator->getDegree(); + if (numErrors == 1) { // shortcut + ArrayRef result(1); + result[0] = errorLocator->getCoefficient(1); + return result; + } + ArrayRef result(numErrors); + int e = 0; + for (int i = 1; i < 256 && e < numErrors; i++) { + // cout << "errorLocator(" << i << ") == " << errorLocator->evaluateAt(i) << "\n"; + if (errorLocator->evaluateAt(i) == 0) { + result[e] = field.inverse(i); + e++; + } + } + if (e != numErrors) { + throw ReedSolomonException("Error locator degree does not match number of roots"); + } + return result; +} + +ArrayRef ReedSolomonDecoder::findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations) { + // This is directly applying Forney's Formula + int s = errorLocations.size(); + ArrayRef result(s); + for (int i = 0; i < s; i++) { + int xiInverse = field.inverse(errorLocations[i]); + int denominator = 1; + for (int j = 0; j < s; j++) { + if (i != j) { + denominator = field.multiply(denominator, GF256::addOrSubtract(1, field.multiply(errorLocations[j], + xiInverse))); + } + } + result[i] = field.multiply(errorEvaluator->evaluateAt(xiInverse), field.inverse(denominator)); + } + return result; +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.h b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.h new file mode 100644 index 000000000..f7c534ba7 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonDecoder.h @@ -0,0 +1,47 @@ +#ifndef __REED_SOLOMON_DECODER_H__ +#define __REED_SOLOMON_DECODER_H__ + +/* + * ReedSolomonDecoder.h + * zxing + * + * Created by Christian Brunschen on 05/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { +class GF256; +class GF256Poly; + +class ReedSolomonDecoder { +private: + GF256 &field; +public: + ReedSolomonDecoder(GF256 &fld); + ~ReedSolomonDecoder(); + void decode(ArrayRef received, int twoS); +private: + std::vector > runEuclideanAlgorithm(Ref a, Ref b, int R); + ArrayRef findErrorLocations(Ref errorLocator); + ArrayRef findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations); +}; +} + +#endif // __REED_SOLOMON_DECODER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.cpp b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.cpp new file mode 100644 index 000000000..20af025bb --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.cpp @@ -0,0 +1,30 @@ +/* + * ReedSolomonException.cpp + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +ReedSolomonException::ReedSolomonException(const char *msg) throw() : + Exception(msg) { +} +ReedSolomonException::~ReedSolomonException() throw() { +} + +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.h b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.h new file mode 100644 index 000000000..ec0df95ce --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/common/reedsolomon/ReedSolomonException.h @@ -0,0 +1,34 @@ +#ifndef __REED_SOLOMON_EXCEPTION_H__ +#define __REED_SOLOMON_EXCEPTION_H__ + +/* + * ReedSolomonException.h + * zxing + * + * Created by Christian Brunschen on 06/05/2008. + * Copyright 2008 Google UK. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +class ReedSolomonException : public Exception { +public: + ReedSolomonException(const char *msg) throw(); + ~ReedSolomonException() throw(); +}; +} + +#endif // __REED_SOLOMON_EXCEPTION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp new file mode 100644 index 000000000..943a57481 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.cpp @@ -0,0 +1,478 @@ +/* + * Code128Reader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-15. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Code128Reader.h" +#include +#include +#include +#include +#include + +namespace zxing { + namespace oned { + + const int CODE_PATTERNS_LENGHT = 107; + const int countersLenght = 6; + static const int CODE_PATTERNS[CODE_PATTERNS_LENGHT][countersLenght] = { + {2, 1, 2, 2, 2, 2}, /* 0 */ + {2, 2, 2, 1, 2, 2}, + {2, 2, 2, 2, 2, 1}, + {1, 2, 1, 2, 2, 3}, + {1, 2, 1, 3, 2, 2}, + {1, 3, 1, 2, 2, 2}, /* 5 */ + {1, 2, 2, 2, 1, 3}, + {1, 2, 2, 3, 1, 2}, + {1, 3, 2, 2, 1, 2}, + {2, 2, 1, 2, 1, 3}, + {2, 2, 1, 3, 1, 2}, /* 10 */ + {2, 3, 1, 2, 1, 2}, + {1, 1, 2, 2, 3, 2}, + {1, 2, 2, 1, 3, 2}, + {1, 2, 2, 2, 3, 1}, + {1, 1, 3, 2, 2, 2}, /* 15 */ + {1, 2, 3, 1, 2, 2}, + {1, 2, 3, 2, 2, 1}, + {2, 2, 3, 2, 1, 1}, + {2, 2, 1, 1, 3, 2}, + {2, 2, 1, 2, 3, 1}, /* 20 */ + {2, 1, 3, 2, 1, 2}, + {2, 2, 3, 1, 1, 2}, + {3, 1, 2, 1, 3, 1}, + {3, 1, 1, 2, 2, 2}, + {3, 2, 1, 1, 2, 2}, /* 25 */ + {3, 2, 1, 2, 2, 1}, + {3, 1, 2, 2, 1, 2}, + {3, 2, 2, 1, 1, 2}, + {3, 2, 2, 2, 1, 1}, + {2, 1, 2, 1, 2, 3}, /* 30 */ + {2, 1, 2, 3, 2, 1}, + {2, 3, 2, 1, 2, 1}, + {1, 1, 1, 3, 2, 3}, + {1, 3, 1, 1, 2, 3}, + {1, 3, 1, 3, 2, 1}, /* 35 */ + {1, 1, 2, 3, 1, 3}, + {1, 3, 2, 1, 1, 3}, + {1, 3, 2, 3, 1, 1}, + {2, 1, 1, 3, 1, 3}, + {2, 3, 1, 1, 1, 3}, /* 40 */ + {2, 3, 1, 3, 1, 1}, + {1, 1, 2, 1, 3, 3}, + {1, 1, 2, 3, 3, 1}, + {1, 3, 2, 1, 3, 1}, + {1, 1, 3, 1, 2, 3}, /* 45 */ + {1, 1, 3, 3, 2, 1}, + {1, 3, 3, 1, 2, 1}, + {3, 1, 3, 1, 2, 1}, + {2, 1, 1, 3, 3, 1}, + {2, 3, 1, 1, 3, 1}, /* 50 */ + {2, 1, 3, 1, 1, 3}, + {2, 1, 3, 3, 1, 1}, + {2, 1, 3, 1, 3, 1}, + {3, 1, 1, 1, 2, 3}, + {3, 1, 1, 3, 2, 1}, /* 55 */ + {3, 3, 1, 1, 2, 1}, + {3, 1, 2, 1, 1, 3}, + {3, 1, 2, 3, 1, 1}, + {3, 3, 2, 1, 1, 1}, + {3, 1, 4, 1, 1, 1}, /* 60 */ + {2, 2, 1, 4, 1, 1}, + {4, 3, 1, 1, 1, 1}, + {1, 1, 1, 2, 2, 4}, + {1, 1, 1, 4, 2, 2}, + {1, 2, 1, 1, 2, 4}, /* 65 */ + {1, 2, 1, 4, 2, 1}, + {1, 4, 1, 1, 2, 2}, + {1, 4, 1, 2, 2, 1}, + {1, 1, 2, 2, 1, 4}, + {1, 1, 2, 4, 1, 2}, /* 70 */ + {1, 2, 2, 1, 1, 4}, + {1, 2, 2, 4, 1, 1}, + {1, 4, 2, 1, 1, 2}, + {1, 4, 2, 2, 1, 1}, + {2, 4, 1, 2, 1, 1}, /* 75 */ + {2, 2, 1, 1, 1, 4}, + {4, 1, 3, 1, 1, 1}, + {2, 4, 1, 1, 1, 2}, + {1, 3, 4, 1, 1, 1}, + {1, 1, 1, 2, 4, 2}, /* 80 */ + {1, 2, 1, 1, 4, 2}, + {1, 2, 1, 2, 4, 1}, + {1, 1, 4, 2, 1, 2}, + {1, 2, 4, 1, 1, 2}, + {1, 2, 4, 2, 1, 1}, /* 85 */ + {4, 1, 1, 2, 1, 2}, + {4, 2, 1, 1, 1, 2}, + {4, 2, 1, 2, 1, 1}, + {2, 1, 2, 1, 4, 1}, + {2, 1, 4, 1, 2, 1}, /* 90 */ + {4, 1, 2, 1, 2, 1}, + {1, 1, 1, 1, 4, 3}, + {1, 1, 1, 3, 4, 1}, + {1, 3, 1, 1, 4, 1}, + {1, 1, 4, 1, 1, 3}, /* 95 */ + {1, 1, 4, 3, 1, 1}, + {4, 1, 1, 1, 1, 3}, + {4, 1, 1, 3, 1, 1}, + {1, 1, 3, 1, 4, 1}, + {1, 1, 4, 1, 3, 1}, /* 100 */ + {3, 1, 1, 1, 4, 1}, + {4, 1, 1, 1, 3, 1}, + {2, 1, 1, 4, 1, 2}, + {2, 1, 1, 2, 1, 4}, + {2, 1, 1, 2, 3, 2}, /* 105 */ + {2, 3, 3, 1, 1, 1} + }; + + + Code128Reader::Code128Reader(){ + } + + int* Code128Reader::findStartPattern(Ref row){ + int width = row->getSize(); + int rowOffset = 0; + while (rowOffset < width) { + if (row->get(rowOffset)) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int counters[countersLenght] = {0,0,0,0,0,0}; + int patternStart = rowOffset; + bool isWhite = false; + int patternLength = sizeof(counters) / sizeof(int); + + for (int i = rowOffset; i < width; i++) { + bool pixel = row->get(i); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + int bestVariance = MAX_AVG_VARIANCE; + int bestMatch = -1; + for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { + int variance = patternMatchVariance(counters, sizeof(counters)/sizeof(int), CODE_PATTERNS[startCode], MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = startCode; + } + } + if (bestMatch >= 0) { + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, false)) { + int* resultValue = new int[3]; + resultValue[0] = patternStart; + resultValue[1] = i; + resultValue[2] = bestMatch; + return resultValue; + } + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + int Code128Reader::decodeCode(Ref row, int counters[], int countersCount, int rowOffset){ + recordPattern(row, rowOffset, counters, countersCount); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + for (int d = 0; d < CODE_PATTERNS_LENGHT; d++) { + int pattern[countersLenght]; + + for(int ind = 0; ind< countersLenght; ind++){ + pattern[ind] = CODE_PATTERNS[d][ind]; + } +// memcpy(pattern, CODE_PATTERNS[d], countersLenght); + int variance = patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = d; + } + } + // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. + if (bestMatch >= 0) { + return bestMatch; + } else { + throw ReaderException(""); + } + } + + Ref Code128Reader::decodeRow(int rowNumber, Ref row){ + + int* startPatternInfo = findStartPattern(row); + int startCode = startPatternInfo[2]; + int codeSet; + switch (startCode) { + case CODE_START_A: + codeSet = CODE_CODE_A; + break; + case CODE_START_B: + codeSet = CODE_CODE_B; + break; + case CODE_START_C: + codeSet = CODE_CODE_C; + break; + default: + throw ReaderException(""); + } + + bool done = false; + bool isNextShifted = false; + + std::string tmpResultString; + + + int lastStart = startPatternInfo[0]; + int nextStart = startPatternInfo[1]; + int counters[countersLenght] = {0,0,0,0,0,0}; + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + bool lastCharacterWasPrintable = true; + + while (!done) { + + bool unshift = isNextShifted; + isNextShifted = false; + + // Save off last code + lastCode = code; + + // Decode another code from image + code = decodeCode(row, counters, sizeof(counters)/sizeof(int), nextStart); + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if (code != CODE_STOP) { + lastCharacterWasPrintable = true; + } + + // Add to checksum computation (if not CODE_STOP of course) + if (code != CODE_STOP) { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + int _countersLenght = sizeof(counters) / sizeof(int); + for (int i = 0; i < _countersLenght; i++) { + nextStart += counters[i]; + } + + // Take care of illegal start codes + switch (code) { + case CODE_START_A: + case CODE_START_B: + case CODE_START_C: + throw ReaderException(""); + } + + switch (codeSet) { + + case CODE_CODE_A: + if (code < 64) { + tmpResultString.append(1, (char) (' ' + code)); + } else if (code < 96) { + tmpResultString.append(1, (char) (code - 64)); + } else { + // Don't let CODE_STOP, which always appears, affect whether whether we think the last + // code was printable or not. + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_A: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_B; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_B: + if (code < 96) { + tmpResultString.append(1, (char) (' ' + code)); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + case CODE_FNC_2: + case CODE_FNC_3: + case CODE_FNC_4_B: + // do nothing? + break; + case CODE_SHIFT: + isNextShifted = true; + codeSet = CODE_CODE_C; + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_C; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + case CODE_CODE_C: + if (code < 100) { + if (code < 10) { + tmpResultString.append(1, '0'); + } + tmpResultString.append(1, code); + } else { + if (code != CODE_STOP) { + lastCharacterWasPrintable = false; + } + switch (code) { + case CODE_FNC_1: + // do nothing? + break; + case CODE_CODE_A: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_B; + break; + case CODE_STOP: + done = true; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) { + switch (codeSet) { + case CODE_CODE_A: + codeSet = CODE_CODE_C; + break; + case CODE_CODE_B: + codeSet = CODE_CODE_A; + break; + case CODE_CODE_C: + codeSet = CODE_CODE_B; + break; + } + } + + } + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + int width = row->getSize(); + while (nextStart < width && row->get(nextStart)) { + nextStart++; + } + if (!row->isRange(nextStart, fminl(width, nextStart + (nextStart - lastStart) / 2), false)) { + throw ReaderException(""); + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) { + throw ReaderException(""); + } + + // Need to pull out the check digits from string + int resultLength = tmpResultString.length(); + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) { + if (codeSet == CODE_CODE_C) { + tmpResultString.erase(resultLength - 2, resultLength); + } else { + tmpResultString.erase(resultLength - 1, resultLength); + } + } + + Ref resultString(new String(tmpResultString)); +// String resultString(tmpResultString); + + if (tmpResultString.length() == 0) { + // Almost surely a false positive + throw ReaderException(""); + } + + float left = (float) (startPatternInfo[1] + startPatternInfo[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + delete [] startPatternInfo; + startPatternInfo = NULL; + + Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_CODE_128)); + return res; + } + + void Code128Reader::append(char* s, char c){ + int len = strlen(s); + s[len] = c; + s[len + 1] = '\0'; + } + + Code128Reader::~Code128Reader(){ + } + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h new file mode 100644 index 000000000..ad191aa0d --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code128Reader.h @@ -0,0 +1,61 @@ +/* + * Code128Reader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-15. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + class Code128Reader : public OneDReader { + + private: + static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f); + static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); + + static const int CODE_SHIFT = 98; + + static const int CODE_CODE_C = 99; + static const int CODE_CODE_B = 100; + static const int CODE_CODE_A = 101; + + static const int CODE_FNC_1 = 102; + static const int CODE_FNC_2 = 97; + static const int CODE_FNC_3 = 96; + static const int CODE_FNC_4_A = 101; + static const int CODE_FNC_4_B = 100; + + static const int CODE_START_A = 103; + static const int CODE_START_B = 104; + static const int CODE_START_C = 105; + static const int CODE_STOP = 106; + + static int* findStartPattern(Ref row); + static int decodeCode(Ref row, int counters[], int countersCount, int rowOffset); + + void append(char* s, char c); + public: + Ref decodeRow(int rowNumber, Ref row); + Code128Reader(); + ~Code128Reader(); + }; + } +} + diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp new file mode 100644 index 000000000..cb03dd9ac --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.cpp @@ -0,0 +1,340 @@ +/* + * Code39Reader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Code39Reader.h" +#include +#include +#include +#include +#include + +namespace zxing { + namespace oned { + + static const char* ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"; + + + /** + * These represent the encodings of characters, as patterns of wide and narrow bars. + * The 9 least-significant bits of each int correspond to the pattern of wide and narrow, + * with 1s representing "wide" and 0s representing narrow. + */ + const int CHARACTER_ENCODINGS_LEN = 44; + static int CHARACTER_ENCODINGS[CHARACTER_ENCODINGS_LEN] = { + 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9 + 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J + 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T + 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-* + 0x0A8, 0x0A2, 0x08A, 0x02A // $-% + }; + + static int ASTERISK_ENCODING = 0x094; + + + + /** + * Creates a reader that assumes all encoded data is data, and does not treat the final + * character as a check digit. It will not decoded "extended Code 39" sequences. + */ + Code39Reader::Code39Reader(){ + ALPHABET_STRING = new std::string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"); + usingCheckDigit = false; + extendedMode = false; + } + + /** + * Creates a reader that can be configured to check the last character as a check digit. + * It will not decoded "extended Code 39" sequences. + * + * @param usingCheckDigit if true, treat the last data character as a check digit, not + * data, and verify that the checksum passes. + */ + Code39Reader::Code39Reader(bool usingCheckDigit_){ + ALPHABET_STRING = new std::string("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"); + usingCheckDigit = usingCheckDigit_; + extendedMode = false; + } + + + + Ref Code39Reader::decodeRow(int rowNumber, Ref row){ + int* start = findAsteriskPattern(row); + int nextStart = start[1]; + int end = row->getSize(); + + // Read off white space + while (nextStart < end && !row->get(nextStart)) { + nextStart++; + } + + std::string tmpResultString; + + int countersLen = 9; + int* counters = new int[countersLen]; + for (int i=0; iget(nextStart)) { + nextStart++; + } + } while (decodedChar != '*'); + tmpResultString.erase(tmpResultString.length()-1, 1);// remove asterisk + + // Look for whitespace after pattern: + int lastPatternSize = 0; + for (int i = 0; i < countersLen; i++) { + lastPatternSize += counters[i]; + } + int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; + // If 50% of last pattern size, following last pattern, is not whitespace, fail + // (but if it's whitespace to the very end of the image, that's OK) + if (nextStart != end && whiteSpaceAfterEnd / 2 < lastPatternSize) { + throw ReaderException("too short end white space"); + } + + if (usingCheckDigit) { + int max = tmpResultString.length() - 1; + int total = 0; + for (int i = 0; i < max; i++) { + total += ALPHABET_STRING->find_first_of(tmpResultString[i], 0); + } + if (total % 43 != ALPHABET_STRING->find_first_of(tmpResultString[max], 0)) { + throw ReaderException(""); + } + tmpResultString.erase(max, 1); + } + + + + + Ref resultString(new String(tmpResultString)); + if (extendedMode) { + delete resultString; + resultString = decodeExtended(tmpResultString); + } + + if (tmpResultString.length() == 0) { + // Almost surely a false positive + throw ReaderException(""); + } + + float left = (float) (start[1] + start[0]) / 2.0f; + float right = (float) (nextStart + lastStart) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + delete [] start; + + Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_CODE_39)); + return res; + } + + int* Code39Reader::findAsteriskPattern(Ref row){ + int width = row->getSize(); + int rowOffset = 0; + while (rowOffset < width) { + if (row->get(rowOffset)) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int countersLen = 9; + int* counters = new int[countersLen]; + for (int i=0; iget(i); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (toNarrowWidePattern(counters, countersLen) == ASTERISK_ENCODING) { + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (row->isRange(fmaxl(0, patternStart - (i - patternStart) / 2), patternStart, false)) { + int* resultValue = new int[2]; + resultValue[0] = patternStart; + resultValue[1] = i; + return resultValue; + } + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + // For efficiency, returns -1 on failure. Not throwing here saved as many as 700 exceptions + // per image when using some of our blackbox images. + int Code39Reader::toNarrowWidePattern(int counters[], int countersLen){ + int numCounters = countersLen; + int maxNarrowCounter = 0; + int wideCounters; + do { + int minCounter = INT_MAX; + for (int i = 0; i < numCounters; i++) { + int counter = counters[i]; + if (counter < minCounter && counter > maxNarrowCounter) { + minCounter = counter; + } + } + maxNarrowCounter = minCounter; + wideCounters = 0; + int totalWideCountersWidth = 0; + int pattern = 0; + for (int i = 0; i < numCounters; i++) { + int counter = counters[i]; + if (counters[i] > maxNarrowCounter) { + pattern |= 1 << (numCounters - 1 - i); + wideCounters++; + totalWideCountersWidth += counter; + } + } + if (wideCounters == 3) { + // Found 3 wide counters, but are they close enough in width? + // We can perform a cheap, conservative check to see if any individual + // counter is more than 1.5 times the average: + for (int i = 0; i < numCounters && wideCounters > 0; i++) { + int counter = counters[i]; + if (counters[i] > maxNarrowCounter) { + wideCounters--; + // totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average + if ((counter << 1) >= totalWideCountersWidth) { + return -1; + } + } + } + return pattern; + } + } while (wideCounters > 3); + return -1; + } + + char Code39Reader::patternToChar(int pattern){ + for (int i = 0; i < CHARACTER_ENCODINGS_LEN; i++) { + if (CHARACTER_ENCODINGS[i] == pattern) { + return ALPHABET[i]; + } + } + throw ReaderException(""); + } + + Ref Code39Reader::decodeExtended(std::string encoded){ + int length = encoded.length(); + std::string tmpDecoded; + for (int i = 0; i < length; i++) { + char c = encoded[i]; + if (c == '+' || c == '$' || c == '%' || c == '/') { + char next = encoded[i + 1]; + char decodedChar = '\0'; + switch (c) { + case '+': + // +A to +Z map to a to z + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next + 32); + } else { + throw ReaderException(""); + } + break; + case '$': + // $A to $Z map to control codes SH to SB + if (next >= 'A' && next <= 'Z') { + decodedChar = (char) (next - 64); + } else { + throw ReaderException(""); + } + break; + case '%': + // %A to %E map to control codes ESC to US + if (next >= 'A' && next <= 'E') { + decodedChar = (char) (next - 38); + } else if (next >= 'F' && next <= 'W') { + decodedChar = (char) (next - 11); + } else { + throw ReaderException(""); + } + break; + case '/': + // /A to /O map to ! to , and /Z maps to : + if (next >= 'A' && next <= 'O') { + decodedChar = (char) (next - 32); + } else if (next == 'Z') { + decodedChar = ':'; + } else { + throw ReaderException(""); + } + break; + } + tmpDecoded.append(1, decodedChar); + // bump up i again since we read two characters + i++; + } else { + tmpDecoded.append(1, c); + } + } + Ref decoded(new String(tmpDecoded)); + return decoded; + } + + + Code39Reader::~Code39Reader(){ + delete ALPHABET_STRING; + } + + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h new file mode 100644 index 000000000..1846761a6 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/Code39Reader.h @@ -0,0 +1,57 @@ +/* + * Code39Reader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + + /** + *

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

+ * Ported form Java (author Sean Owen) + * @author Lukasz Warchol + */ + class Code39Reader : public OneDReader { + + private: + std::string* ALPHABET_STRING; + + bool usingCheckDigit; + bool extendedMode; + + static int* findAsteriskPattern(Ref row); //throws ReaderException + static int toNarrowWidePattern(int counters[], int countersLen); + static char patternToChar(int pattern); //throws ReaderException + static Ref decodeExtended(std::string encoded); //throws ReaderException + + void append(char* s, char c); + public: + Code39Reader(); + Code39Reader(bool usingCheckDigit_); + + Ref decodeRow(int rowNumber, Ref row); + + ~Code39Reader(); + }; + } +} + diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp new file mode 100644 index 000000000..0e3de9731 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.cpp @@ -0,0 +1,95 @@ +/* + * EAN13Reader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-22. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EAN13Reader.h" +#include + +namespace zxing { + namespace oned { + + static const int FIRST_DIGIT_ENCODINGS[10] = {0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}; + + + EAN13Reader::EAN13Reader(){ + decodeMiddleCounters = new int[4]; + for (int i=0; i<4; i++) { + decodeMiddleCounters[i] = 0; + } + } + + int EAN13Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + int countersLen = 4; + int* counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + + + int end = row->getSize(); + int rowOffset = startRange[1]; + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + determineFirstDigit(resultString, lgPatternFound); + + int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); + rowOffset = middleRange[1]; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + return rowOffset; + } + + void EAN13Reader::determineFirstDigit(std::string& resultString, int lgPatternFound){ + for (int d = 0; d < 10; d++) { + if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { + resultString.insert((size_t)0, (size_t)1, (char) ('0' + d)); + return; + } + } + throw ReaderException("determineFirstDigit"); + } + + BarcodeFormat EAN13Reader::getBarcodeFormat(){ + return BarcodeFormat_EAN_13; + } + EAN13Reader::~EAN13Reader(){ + delete [] decodeMiddleCounters; + } + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h new file mode 100644 index 000000000..8ef6fe38b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN13Reader.h @@ -0,0 +1,41 @@ +/* + * EAN13Reader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-22. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + class EAN13Reader : public UPCEANReader { + + private: + int* decodeMiddleCounters; + static void determineFirstDigit(std::string& resultString, int lgPatternFound); //throws ReaderException + + public: + EAN13Reader(); + + int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException + + BarcodeFormat getBarcodeFormat(); + ~EAN13Reader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp new file mode 100644 index 000000000..52d09fe99 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.cpp @@ -0,0 +1,75 @@ +/* + * EAN8Reader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EAN8Reader.h" +#include + +namespace zxing { + namespace oned { + + EAN8Reader::EAN8Reader(){ + decodeMiddleCounters = new int[4]; + for (int i=0; i<4; i++) { + decodeMiddleCounters[i] = 0; + } + } + + int EAN8Reader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + int countersLen = 4; + int* counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + + + int end = row->getSize(); + int rowOffset = startRange[1]; + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + int* middleRange = findGuardPattern(row, rowOffset, true, (int*)getMIDDLE_PATTERN(), getMIDDLE_PATTERN_LEN()); + rowOffset = middleRange[1]; + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + } + + return rowOffset; + } + + BarcodeFormat EAN8Reader::getBarcodeFormat(){ + return BarcodeFormat_EAN_8; + } + EAN8Reader::~EAN8Reader(){ + delete [] decodeMiddleCounters; + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h new file mode 100644 index 000000000..3e4f3d67e --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/EAN8Reader.h @@ -0,0 +1,40 @@ +/* + * EAN8Reader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + class EAN8Reader : public UPCEANReader { + + private: + int* decodeMiddleCounters; + + public: + EAN8Reader(); + + int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException + + BarcodeFormat getBarcodeFormat(); + ~EAN8Reader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp new file mode 100644 index 000000000..e38ab2160 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.cpp @@ -0,0 +1,353 @@ +/* + * ITFReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ITFReader.h" +#include +#include +#include +#include + +namespace zxing { + namespace oned { + + static const int W = 3; // Pixel width of a wide line + static const int N = 1; // Pixed width of a narrow line + + const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 }; + + /** + * Start/end guard pattern. + * + * Note: The end pattern is reversed because the row is reversed before + * searching for the END_PATTERN + */ + static const int START_PATTERN_LEN = 4; + static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N}; + + static const int END_PATTERN_REVERSED_LEN = 3; + static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W}; + + /** + * Patterns of Wide / Narrow lines to indicate each digit + */ + static const int PATTERNS_LEN = 10; + static const int PATTERNS[PATTERNS_LEN][5] = { + {N, N, W, W, N}, // 0 + {W, N, N, N, W}, // 1 + {N, W, N, N, W}, // 2 + {W, W, N, N, N}, // 3 + {N, N, W, N, W}, // 4 + {W, N, W, N, N}, // 5 + {N, W, W, N, N}, // 6 + {N, N, N, W, W}, // 7 + {W, N, N, W, N}, // 8 + {N, W, N, W, N} // 9 + }; + + + ITFReader::ITFReader(){ + narrowLineWidth = -1; + } + + + Ref ITFReader::decodeRow(int rowNumber, Ref row){ + // Find out where the Middle section (payload) starts & ends + int* startRange = decodeStart(row); + int* endRange = decodeEnd(row); + + std::string tmpResult; + decodeMiddle(row, startRange[1], endRange[0], tmpResult); + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be 6, 10 or 14 digits. + int length = tmpResult.length(); + bool lengthOK = false; + if (length == 6 || length == 10 || length == 14) { + lengthOK = true; + } + if (!lengthOK) { + throw ReaderException("not enought characters count"); + } + + Ref resultString(new String(tmpResult)); + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + delete [] startRange; + delete [] endRange; + + Ref res(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF)); + return res; + } + + /** + * @param row row of black/white values to search + * @param payloadStart offset of start pattern + * @param resultString {@link StringBuffer} to append decoded chars to + * @throws ReaderException if decoding could not complete successfully + */ + void ITFReader::decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString){ + // Digits are interleaved in pairs - 5 black lines for one digit, and the + // 5 + // interleaved white lines for the second digit. + // Therefore, need to scan 10 lines and then + // split these into two arrays + int counterDigitPairLen = 10; + int* counterDigitPair = new int[counterDigitPairLen]; + for (int i=0; i row){ + int endStart = skipWhiteSpace(row); +/// static int* findGuardPattern(Ref row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen); + int* startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN); + + // Determine the width of a narrow line in pixels. We can do this by + // getting the width of the start pattern and dividing by 4 because its + // made up of 4 narrow lines. + narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2; + + validateQuietZone(row, startPattern[0]); + + return startPattern; + } + + /** + * Identify where the end of the middle / payload section ends. + * + * @param row row of black/white values to search + * @return Array, containing index of start of 'end block' and end of 'end + * block' + * @throws ReaderException + */ + + int* ITFReader::decodeEnd(Ref row){ + // For convenience, reverse the row and then + // search from 'the start' for the end block + row->reverse(); + try { + int endStart = skipWhiteSpace(row); + int* endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN); + + // The start & end patterns must be pre/post fixed by a quiet zone. This + // zone must be at least 10 times the width of a narrow line. + // ref: http://www.barcode-1.net/i25code.html + validateQuietZone(row, endPattern[0]); + + // Now recalculate the indices of where the 'endblock' starts & stops to + // accommodate + // the reversed nature of the search + int temp = endPattern[0]; + endPattern[0] = row->getSize() - endPattern[1]; + endPattern[1] = row->getSize() - temp; + + return endPattern; + }catch (Exception e) { + row->reverse(); + throw e; + } + } + + /** + * The start & end patterns must be pre/post fixed by a quiet zone. This + * zone must be at least 10 times the width of a narrow line. Scan back until + * we either get to the start of the barcode or match the necessary number of + * quiet zone pixels. + * + * Note: Its assumed the row is reversed when using this method to find + * quiet zone after the end pattern. + * + * ref: http://www.barcode-1.net/i25code.html + * + * @param row bit array representing the scanned barcode. + * @param startPattern index into row of the start or end pattern. + * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown. + */ + void ITFReader::validateQuietZone(Ref row, int startPattern){ +#pragma mark needs some corrections +// int quietCount = narrowLineWidth * 10; // expect to find this many pixels of quiet zone +// +// for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { +// if (row->get(i)) { +// break; +// } +// quietCount--; +// } +// if (quietCount != 0) { +// // Unable to find the necessary number of quiet zone pixels. +// throw ReaderException("Unable to find the necessary number of quiet zone pixels"); +// } + } + + /** + * Skip all whitespace until we get to the first black line. + * + * @param row row of black/white values to search + * @return index of the first black line. + * @throws ReaderException Throws exception if no black lines are found in the row + */ + int ITFReader::skipWhiteSpace(Ref row){ + int width = row->getSize(); + int endStart = 0; + while (endStart < width) { + if (row->get(endStart)) { + break; + } + endStart++; + } + if (endStart == width) { + throw ReaderException(""); + } + return endStart; + } + + /** + * @param row row of black/white values to search + * @param rowOffset position to start search + * @param pattern pattern of counts of number of black and white pixels that are + * being searched for as a pattern + * @return start/end horizontal offset of guard pattern, as an array of two + * ints + * @throws ReaderException if pattern is not found + */ + + int* ITFReader::findGuardPattern(Ref row, int rowOffset, const int pattern[], int patternLen){ + // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be + // merged to a single method. + int patternLength = patternLen; + int* counters = new int[patternLength]; + for (int i=0; igetSize(); + bool isWhite = false; + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + bool pixel = row->get(x); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, patternLength, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + int* resultValue = new int[2]; + resultValue[0] = patternStart; + resultValue[1] = x; + return resultValue; + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException(""); + } + + /** + * Attempts to decode a sequence of ITF black/white lines into single + * digit. + * + * @param counters the counts of runs of observed black/white/black/... values + * @return The decoded digit + * @throws ReaderException if digit cannot be decoded + */ + int ITFReader::decodeDigit(int counters[], int countersLen){ + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int ind = 0; ind= 0) { + return bestMatch; + } else { + throw ReaderException("digit didint found"); + } + } + + + ITFReader::~ITFReader(){ + } + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.h new file mode 100644 index 000000000..759d84144 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/ITFReader.h @@ -0,0 +1,53 @@ +/* + * ITFReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + class ITFReader : public OneDReader { + + private: + static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); + static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f); + + // Stores the actual narrow line width of the image being decoded. + int narrowLineWidth; + + int* decodeStart(Ref row); //throws ReaderException + int* decodeEnd(Ref row); //throws ReaderException + static void decodeMiddle(Ref row, int payloadStart, int payloadEnd, std::string& resultString); //throws ReaderException + void validateQuietZone(Ref row, int startPattern); //throws ReaderException + static int skipWhiteSpace(Ref row); //throws ReaderException + + static int* findGuardPattern(Ref row, int rowOffset, const int pattern[], int patternLen); //throws ReaderException + static int decodeDigit(int counters[], int countersLen); //throws ReaderException + + void append(char* s, char c); + public: + Ref decodeRow(int rowNumber, Ref row); ///throws ReaderException + ITFReader(); + ~ITFReader(); + }; + } +} + diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.cpp new file mode 100644 index 000000000..1338a56f4 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.cpp @@ -0,0 +1,55 @@ +/* + * MultiFormatOneDReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MultiFormatOneDReader.h" + +#include +#include +#include +#include +#include + +namespace zxing { + namespace oned { + MultiFormatOneDReader::MultiFormatOneDReader(){ + readers = new std::vector(); + readers->push_back(new MultiFormatUPCEANReader()); + readers->push_back(new Code39Reader()); + readers->push_back(new Code128Reader()); + readers->push_back(new ITFReader()); + } + + Ref MultiFormatOneDReader::decodeRow(int rowNumber, Ref row){ + int size = readers->size(); + for (int i = 0; i < size; i++) { + OneDReader* reader = (*readers)[i]; + try { + return reader->decodeRow(rowNumber, row); + } catch (ReaderException re) { + // continue + } + } + throw ReaderException("No code detected"); + } + MultiFormatOneDReader::~MultiFormatOneDReader(){ + delete readers; + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h new file mode 100644 index 000000000..9fcc6fbb2 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatOneDReader.h @@ -0,0 +1,39 @@ +/* + * MultiFormatOneDReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { + namespace oned { + class MultiFormatOneDReader : public OneDReader { + + private: + std::vector* readers; + public: + MultiFormatOneDReader(); + + Ref decodeRow(int rowNumber, Ref row); + + ~MultiFormatOneDReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp new file mode 100644 index 000000000..61011f0ff --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.cpp @@ -0,0 +1,79 @@ +/* + * MultiFormatUPCEANReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "MultiFormatUPCEANReader.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + namespace oned { + + MultiFormatUPCEANReader::MultiFormatUPCEANReader(){ + readers = new std::vector(); + readers->push_back(new EAN13Reader()); + // UPC-A is covered by EAN-13 + readers->push_back(new EAN8Reader()); + readers->push_back(new UPCEReader()); + } + + Ref MultiFormatUPCEANReader::decodeRow(int rowNumber, Ref row){ + // Compute this location once and reuse it on multiple implementations + int size = readers->size(); + for (int i = 0; i < size; i++) { + OneDReader* reader = (*readers)[i]; + Ref result; + try { + result = reader->decodeRow(rowNumber, row);//decodeRow(rowNumber, row, startGuardPattern); + } catch (ReaderException re) { + continue; + } + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" + // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, + // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". + // Individually these are correct and their readers will both read such a code + // and correctly call it EAN-13, or UPC-A, respectively. + // + // In this case, if we've been looking for both types, we'd like to call it + // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read + // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A + // result if appropriate. + if (result->getBarcodeFormat() == BarcodeFormat_EAN_13) { + std::string& text = (result->getText())->getText(); + if (text[0] == '0') { + Ref resultString(new String(text.substr(1))); + Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); + return res; + } + } + return result; + } + throw ReaderException("No EAN code detected"); + } + + MultiFormatUPCEANReader::~MultiFormatUPCEANReader(){ + delete readers; + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h new file mode 100644 index 000000000..706f9c431 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/MultiFormatUPCEANReader.h @@ -0,0 +1,41 @@ +/* + * MultiFormatUPCEANReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#include +#include +#include + +namespace zxing { + namespace oned { + class MultiFormatUPCEANReader : public OneDReader { + + private: + std::vector* readers; + public: + MultiFormatUPCEANReader(); + + Ref decodeRow(int rowNumber, Ref row); + + ~MultiFormatUPCEANReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp new file mode 100644 index 000000000..21526f57f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.cpp @@ -0,0 +1,194 @@ +/* + * OneDReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-15. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OneDReader.h" +#include +#include +#include + +namespace zxing { + namespace oned { + using namespace std; + + OneDReader::OneDReader() { + } + + Ref OneDReader::decode(Ref image) { + try { + return doDecode(image); + }catch (ReaderException re) { + if (false /*tryHarder && image.isRotateSupported()*/) { + /* + BinaryBitmap rotatedImage = image.rotateCounterClockwise(); + Result result = doDecode(rotatedImage, hints); + // Record that we found it rotated 90 degrees CCW / 270 degrees CW + Hashtable metadata = result.getResultMetadata(); + int orientation = 270; + if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) { + // But if we found it reversed in doDecode(), add in that result here: + orientation = (orientation + + ((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360; + } + result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation)); + // Update result points + ResultPoint[] points = result.getResultPoints(); + int height = rotatedImage.getHeight(); + for (int i = 0; i < points.length; i++) { + points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX()); + } + return result; + */ + } else { + throw re; + } + } + } + + Ref OneDReader::doDecode(Ref image){ + int width = image->getWidth(); + int height = image->getHeight(); + Ref row(new BitArray(width)); +// BitArray row = new BitArray(width); + + int middle = height >> 1; + bool tryHarder = true;//hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); + int rowStep = (int)fmax(1, height >> (tryHarder ? 7 : 4)); + int maxLines; + if (tryHarder) { + maxLines = height; // Look at the whole image, not just the center + } else { + maxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image + } + + for (int x = 0; x < maxLines; x++) { + + // Scanning from the middle out. Determine which row we're looking at next: + int rowStepsAboveOrBelow = (x + 1) >> 1; + bool isAbove = (x & 0x01) == 0; // i.e. is x even? + int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + if (rowNumber < 0 || rowNumber >= height) { + // Oops, if we run off the top or bottom, stop + break; + } + + // Estimate black point for this row and load it: + try { + row = image->getBlackRow(rowNumber, row); + }catch (ReaderException re) { + continue; + } + + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to + // handle decoding upside down barcodes. + for (int attempt = 0; attempt < 2; attempt++) { + if (attempt == 1) { // trying again? + row->reverse(); // reverse the row and continue + } + try { + // Look for a barcode + Ref result = decodeRow(rowNumber, row); + // We found our barcode + if (attempt == 1) { + // // But it was upside down, so note that + // result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180)); + // // And remember to flip the result points horizontally. + // ResultPoint[] points = result.getResultPoints(); + // points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY()); + // points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY()); + } + return result; + } catch (ReaderException re) { + // continue -- just couldn't decode this row + } + } + } + throw ReaderException(""); + } + + int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) { + int numCounters = countersSize; + int total = 0; + int patternLength = 0; + for (int i = 0; i < numCounters; i++) { + total += counters[i]; + patternLength += pattern[i]; + } + if (total < patternLength) { + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + return INT_MAX; + } + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits" + int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength; + maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT; + + int totalVariance = 0; + for (int x = 0; x < numCounters; x++) { + int counter = counters[x] << INTEGER_MATH_SHIFT; + int scaledPattern = pattern[x] * unitBarWidth; + int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) { + return INT_MAX; + } + totalVariance += variance; + } + return totalVariance / total; + } + + void OneDReader::recordPattern(Ref row, int start, int counters[], int countersCount){ + int numCounters = countersCount;//sizeof(counters) / sizeof(int); + for (int i = 0; i < numCounters; i++) { + counters[i] = 0; + } + int end = row->getSize(); + if (start >= end) { + throw ReaderException("recordPattern: start >= end"); + } + bool isWhite = !row->get(start); + int counterPosition = 0; + int i = start; + while (i < end) { + bool pixel = row->get(i); + if (pixel ^ isWhite) { // that is, exactly one is true + counters[counterPosition]++; + } else { + counterPosition++; + if (counterPosition == numCounters) { + break; + } else { + counters[counterPosition] = 1; + isWhite ^= true; // isWhite = !isWhite; + } + } + i++; + } + // If we read fully the last section of pixels and filled up our counters -- or filled + // the last counter but ran off the side of the image, OK. Otherwise, a problem. + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { + throw ReaderException("recordPattern"); + } + } + + OneDReader::~OneDReader() { + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h new file mode 100644 index 000000000..a029f9cb1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDReader.h @@ -0,0 +1,46 @@ +/* + * OneDReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-15. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace zxing { + namespace oned { + class OneDReader : public Reader { + private: + static const int INTEGER_MATH_SHIFT = 8; + + Ref doDecode(Ref image); + public: + static const int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT; + + OneDReader(); + virtual Ref decode(Ref image); + virtual Ref decodeRow(int rowNumber, Ref row) = 0; + + static int patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance); + static void recordPattern(Ref row, int start, int counters[], int countersCount); + virtual ~OneDReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp new file mode 100644 index 000000000..272319dbf --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.cpp @@ -0,0 +1,39 @@ +/* + * OneDResultPoint.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-20. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OneDResultPoint.h" + +namespace zxing { + namespace oned { + + using namespace std; + + OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY){ + } + + float OneDResultPoint::getX() { + return posX_; + } + + float OneDResultPoint::getY() { + return posY_; + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h new file mode 100644 index 000000000..1b07b772c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/OneDResultPoint.h @@ -0,0 +1,37 @@ +/* + * OneDResultPoint.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-20. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +namespace zxing { + namespace oned { + + class OneDResultPoint : public ResultPoint { + private: + float posX_; + float posY_; + + public: + OneDResultPoint(float posX, float posY); + float getX(); + float getY(); + }; + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp new file mode 100644 index 000000000..e46c2b76f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.cpp @@ -0,0 +1,64 @@ +/* + * UPCAReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UPCAReader.h" +#include +#include + +namespace zxing { + namespace oned { + UPCAReader::UPCAReader(){ + ean13Reader = new EAN13Reader(); + } + + Ref UPCAReader::decodeRow(int rowNumber, Ref row){ + return maybeReturnResult(ean13Reader->decodeRow(rowNumber, row)); + } + Ref UPCAReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]){ + return maybeReturnResult(ean13Reader->decodeRow(rowNumber, row, startGuardRange)); + } + Ref UPCAReader::decode(Ref image){ + return maybeReturnResult(ean13Reader->decode(image)); + } + + int UPCAReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + return ean13Reader->decodeMiddle(row, startRange, startRangeLen, resultString); + } + + Ref UPCAReader::maybeReturnResult(Ref result){ + std::string& text = (result->getText())->getText(); + if (text[0] == '0') { + Ref resultString(new String(text.substr(1))); + Ref res(new Result(resultString, result->getRawBytes(), result->getResultPoints(), BarcodeFormat_UPC_A)); + return res; + } else { + throw ReaderException("Not UPC-A barcode."); + } + } + + + BarcodeFormat UPCAReader::getBarcodeFormat(){ + return BarcodeFormat_UPC_A; + } + UPCAReader::~UPCAReader(){ + delete ean13Reader; + } + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h new file mode 100644 index 000000000..217184b84 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCAReader.h @@ -0,0 +1,45 @@ +/* + * UPCAReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-25. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + class UPCAReader : public UPCEANReader { + + private: + UPCEANReader* ean13Reader; + static Ref maybeReturnResult(Ref result); //throws ReaderException + + public: + UPCAReader(); + + int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException + + Ref decodeRow(int rowNumber, Ref row); //throws ReaderException + Ref decodeRow(int rowNumber, Ref row, int startGuardRange[]); //throws ReaderException + Ref decode(Ref image); + + BarcodeFormat getBarcodeFormat(); + ~UPCAReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp new file mode 100644 index 000000000..5345cad9b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.cpp @@ -0,0 +1,310 @@ +/* + * UPCEANReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-21. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UPCEANReader.h" +#include +#include +namespace zxing { + namespace oned { + + /** + * Start/end guard pattern. + */ + static const int START_END_PATTERN[3] = {1, 1, 1}; + + /** + * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + */ + static const int MIDDLE_PATTERN_LEN = 5; + static const int MIDDLE_PATTERN[MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1}; + + /** + * "Odd", or "L" patterns used to encode UPC/EAN digits. + */ + const int L_PATTERNS_LEN = 10; + const int L_PATTERNS_SUB_LEN = 4; + const int L_PATTERNS[10][4] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2} // 9 + }; + + /** + * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + */ + const int L_AND_G_PATTERNS_LEN = 20; + const int L_AND_G_PATTERNS_SUB_LEN = 4; + const int L_AND_G_PATTERNS[L_AND_G_PATTERNS_LEN][L_AND_G_PATTERNS_SUB_LEN] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2}, // 9 + {1, 1, 2, 3}, // 10 reversed 0 + {1, 2, 2, 2}, // 11 reversed 1 + {2, 2, 1, 2}, // 12 reversed 2 + {1, 1, 4, 1}, // 13 reversed 3 + {2, 3, 1, 1}, // 14 reversed 4 + {1, 3, 2, 1}, // 15 reversed 5 + {4, 1, 1, 1}, // 16 reversed 6 + {2, 1, 3, 1}, // 17 reversed 7 + {3, 1, 2, 1}, // 18 reversed 8 + {2, 1, 1, 3} // 19 reversed 9 + }; + + + const int UPCEANReader::getMIDDLE_PATTERN_LEN(){ + return MIDDLE_PATTERN_LEN; + } + const int* UPCEANReader::getMIDDLE_PATTERN(){ + return MIDDLE_PATTERN; + } + + UPCEANReader::UPCEANReader(){ + } + + + Ref UPCEANReader::decodeRow(int rowNumber, Ref row){ + return decodeRow(rowNumber, row, findStartGuardPattern(row)); + } + Ref UPCEANReader::decodeRow(int rowNumber, Ref row, int startGuardRange[]){ + + std::string tmpResultString; + std::string& tmpResultStringRef = tmpResultString; + int endStart = decodeMiddle(row, startGuardRange, 2 /*reference findGuardPattern*/ , tmpResultStringRef); + + int* endRange = decodeEnd(row, endStart); + +#pragma mark QuietZone needs some change + // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The + // spec might want more whitespace, but in practice this is the maximum we can count on. +// int end = endRange[1]; +// int quietEnd = end + (end - endRange[0]); +// if (quietEnd >= row->getSize() || !row->isRange(end, quietEnd, false)) { +// throw ReaderException("Quiet zone asserrt fail."); +// } + + if (!checkChecksum(tmpResultString)) { + throw ReaderException("Checksum fail."); + } + + Ref resultString(new String(tmpResultString)); + + float left = (float) (startGuardRange[1] + startGuardRange[0]) / 2.0f; + float right = (float) (endRange[1] + endRange[0]) / 2.0f; + + std::vector< Ref > resultPoints(2); + Ref resultPoint1(new OneDResultPoint(left, (float) rowNumber)); + Ref resultPoint2(new OneDResultPoint(right, (float) rowNumber)); + resultPoints[0] = resultPoint1; + resultPoints[1] = resultPoint2; + + ArrayRef resultBytes(1); + + if (startGuardRange!=NULL) { + delete [] startGuardRange; + startGuardRange = NULL; + } + if (endRange!=NULL) { + delete [] endRange; + endRange = NULL; + } + + Ref res(new Result(resultString, resultBytes, resultPoints, getBarcodeFormat())); + return res; + } + + int* UPCEANReader::findStartGuardPattern(Ref row){ + bool foundStart = false; + + int* startRange = NULL; + int nextStart = 0; + while (!foundStart) { + startRange = findGuardPattern(row, nextStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int)); + int start = startRange[0]; + nextStart = startRange[1]; + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + int quietStart = start - (nextStart - start); + if (quietStart >= 0) { + foundStart = row->isRange(quietStart, start, false); + } + } + return startRange; + } + + int* UPCEANReader::findGuardPattern(Ref row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen){ + int patternLength = patternLen; + + int counters[patternLength]; + int countersCount = sizeof(counters)/sizeof(int); + for (int i=0; igetSize(); + bool isWhite = false; + while (rowOffset < width) { + isWhite = !row->get(rowOffset); + if (whiteFirst == isWhite) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + bool pixel = row->get(x); + if (pixel ^ isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if (patternMatchVariance(counters, countersCount, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { + int* resultValue = new int[2]; + resultValue[0] = patternStart; + resultValue[1] = x; + return resultValue; + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + throw ReaderException("findGuardPattern"); + } + + int* UPCEANReader::decodeEnd(Ref row, int endStart){ + return findGuardPattern(row, endStart, false, START_END_PATTERN, sizeof(START_END_PATTERN)/sizeof(int)); + } + +// int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, int** patterns/*[][]*/, int paterns1Len, int paterns2Len) + int UPCEANReader::decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS paternType){ + recordPattern(row, rowOffset, counters, countersLen); + int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + + int max = 0; + switch (paternType) { + case UPC_EAN_PATTERNS_L_PATTERNS: + max = L_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int j = 0; j< countersLen; j++){ + pattern[j] = L_PATTERNS[i][j]; + } + + int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + case UPC_EAN_PATTERNS_L_AND_G_PATTERNS: + max = L_AND_G_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[countersLen]; + for(int j = 0; j< countersLen; j++){ + pattern[j] = L_AND_G_PATTERNS[i][j]; + } + + int variance = patternMatchVariance(counters, countersLen, pattern, MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + default: + break; + } + if (bestMatch >= 0) { + return bestMatch; + } else { + throw ReaderException("UPCEANReader::decodeDigit: No best mach"); + } + } + + + /** + * @return {@link #checkStandardUPCEANChecksum(String)} + */ + bool UPCEANReader::checkChecksum(std::string s){ + return checkStandardUPCEANChecksum(s); + } + + /** + * Computes the UPC/EAN checksum on a string of digits, and reports + * whether the checksum is correct or not. + * + * @param s string of digits to check + * @return true iff string of digits passes the UPC/EAN checksum algorithm + * @throws ReaderException if the string does not contain only digits + */ + bool UPCEANReader::checkStandardUPCEANChecksum(std::string s){ + int length = s.length(); + if (length == 0) { + return false; + } + + int sum = 0; + for (int i = length - 2; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + throw ReaderException("checkStandardUPCEANChecksum"); + } + sum += digit; + } + sum *= 3; + for (int i = length - 1; i >= 0; i -= 2) { + int digit = (int) s[i] - (int) '0'; + if (digit < 0 || digit > 9) { + throw ReaderException("checkStandardUPCEANChecksum"); + } + sum += digit; + } + return sum % 10 == 0; + } + UPCEANReader::~UPCEANReader(){ + } + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h new file mode 100644 index 000000000..8f825c26c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEANReader.h @@ -0,0 +1,65 @@ +/* + * UPCEANReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-21. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +typedef enum UPC_EAN_PATTERNS { + UPC_EAN_PATTERNS_L_PATTERNS = 0, + UPC_EAN_PATTERNS_L_AND_G_PATTERNS +} UPC_EAN_PATTERNS; +namespace zxing { + namespace oned { + class UPCEANReader : public OneDReader { + + private: + static const int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f); + static const int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f); + + static int* findStartGuardPattern(Ref row); //throws ReaderException + + int* decodeEnd(Ref row, int endStart); //throws ReaderException + + static bool checkStandardUPCEANChecksum(std::string s); //throws ReaderException + protected: + static int* findGuardPattern(Ref row, int rowOffset, bool whiteFirst, const int pattern[], int patternLen); //throws ReaderException + + virtual const int getMIDDLE_PATTERN_LEN(); + virtual const int* getMIDDLE_PATTERN(); + + public: + UPCEANReader(); + + virtual int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString) = 0; //throws ReaderException + + Ref decodeRow(int rowNumber, Ref row); + Ref decodeRow(int rowNumber, Ref row, int startGuardRange[]); + + static int decodeDigit(Ref row, int counters[], int countersLen, int rowOffset, UPC_EAN_PATTERNS paternType); //throws ReaderException + + bool checkChecksum(std::string s); //throws ReaderException + + virtual BarcodeFormat getBarcodeFormat() = 0; + virtual ~UPCEANReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp new file mode 100644 index 000000000..3738d4c6b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.cpp @@ -0,0 +1,150 @@ +/* + * UPCEReader.cpp + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UPCEReader.h" +#include + +namespace zxing { + namespace oned { + + /** + * The pattern that marks the middle, and end, of a UPC-E pattern. + * There is no "second half" to a UPC-E barcode. + */ + static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1}; + + /** + * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of + * even-odd parity encodings of digits that imply both the number system (0 or 1) + * used, and the check digit. + */ + static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = { + {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, + {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} + }; + + UPCEReader::UPCEReader(){ + decodeMiddleCounters = new int[4]; + for (int i=0; i<4; i++) { + decodeMiddleCounters[i] = 0; + } + } + + int UPCEReader::decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString){ + int countersLen = 4; + int* counters = decodeMiddleCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + + + int end = row->getSize(); + int rowOffset = startRange[1]; + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = decodeDigit(row, counters, countersLen, rowOffset, UPC_EAN_PATTERNS_L_AND_G_PATTERNS); + resultString.append(1, (char) ('0' + bestMatch % 10)); + for (int i = 0; i < countersLen; i++) { + rowOffset += counters[i]; + } + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + determineNumSysAndCheckDigit(resultString, lgPatternFound); + + return rowOffset; + } + + int* UPCEReader::decodeEnd(Ref row, int endStart){ + return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN, sizeof(MIDDLE_END_PATTERN)/sizeof(int)); + } + + bool UPCEReader::checkChecksum(std::string s){ + return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s)); + } + + + void UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound){ + for (int numSys = 0; numSys <= 1; numSys++) { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { + resultString.insert((size_t)0, (size_t)1, (char) ('0' + numSys)); + resultString.append(1, (char) ('0' + d)); + return; + } + } + } + throw ReaderException("determineNumSysAndCheckDigit exception"); + } + + /** + * Expands a UPC-E value back into its full, equivalent UPC-A code value. + * + * @param upce UPC-E code as string of digits + * @return equivalent UPC-A code as string of digits + */ + std::string& UPCEReader::convertUPCEtoUPCA(std::string upce) { + std::string result; + result.append(1, upce[0]); + char lastChar = upce[6]; + switch (lastChar) { + case '0': + case '1': + case '2': + result.append(upce.substr(1,2)); + result.append(1, lastChar); + result.append("0000"); + result.append(upce.substr(3,3)); + break; + case '3': + result.append(upce.substr(1,3)); + result.append("00000"); + result.append(upce.substr(4,2)); + break; + case '4': + result.append(upce.substr(1,4)); + result.append("00000"); + result.append(1, upce[5]); + break; + default: + result.append(upce.substr(1,5)); + result.append("0000"); + result.append(1, lastChar); + break; + } + result.append(1, upce[7]); + std::string& returnResult = result; + return returnResult; + } + + + BarcodeFormat UPCEReader::getBarcodeFormat(){ + return BarcodeFormat_UPC_E; + } + UPCEReader::~UPCEReader(){ + delete [] decodeMiddleCounters; + } + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h new file mode 100644 index 000000000..a26e2ec62 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/oned/UPCEReader.h @@ -0,0 +1,45 @@ +/* + * UPCEReader.h + * ZXing + * + * Created by Lukasz Warchol on 10-01-26. + * Copyright 2010 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace oned { + class UPCEReader : public UPCEANReader { + + private: + int* decodeMiddleCounters; + static void determineFirstDigit(std::string& resultString, int lgPatternFound); //throws ReaderException + static void determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound); //throws ReaderException + protected: + int* decodeEnd(Ref row, int endStart); //throws ReaderException + bool checkChecksum(std::string s); //throws ReaderException + public: + UPCEReader(); + + int decodeMiddle(Ref row, int startRange[], int startRangeLen, std::string& resultString); //throws ReaderException + static std::string& convertUPCEtoUPCA(std::string upce); + + BarcodeFormat getBarcodeFormat(); + ~UPCEReader(); + }; + } +} \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp new file mode 100644 index 000000000..9c610b526 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.cpp @@ -0,0 +1,49 @@ +/* + * ErrorCorrectionLevel.cpp + * zxing + * + * Created by Christian Brunschen on 15/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +namespace qrcode { + +ErrorCorrectionLevel::ErrorCorrectionLevel(int ordinal) : + ordinal_(ordinal) { +} + +int ErrorCorrectionLevel::ordinal() { + return ordinal_; +} + +ErrorCorrectionLevel& ErrorCorrectionLevel::forBits(int bits) { + if (bits < 0 || bits >= N_LEVELS) { + throw ReaderException("Ellegal error correction level bits"); + } + return *FOR_BITS[bits]; +} + +ErrorCorrectionLevel ErrorCorrectionLevel::L(0); +ErrorCorrectionLevel ErrorCorrectionLevel::M(1); +ErrorCorrectionLevel ErrorCorrectionLevel::Q(2); +ErrorCorrectionLevel ErrorCorrectionLevel::H(3); +ErrorCorrectionLevel *ErrorCorrectionLevel::FOR_BITS[] = { &M, &L, &H, &Q }; +int ErrorCorrectionLevel::N_LEVELS = 4; + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h new file mode 100644 index 000000000..426d204cf --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/ErrorCorrectionLevel.h @@ -0,0 +1,47 @@ +#ifndef __ERROR_CORRECTION_LEVEL_H__ +#define __ERROR_CORRECTION_LEVEL_H__ + +/* + * ErrorCorrectionLevel.h + * zxing + * + * Created by Christian Brunschen on 15/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +namespace qrcode { + +class ErrorCorrectionLevel { +private: + int ordinal_; + ErrorCorrectionLevel(int ordinal); + static ErrorCorrectionLevel *FOR_BITS[]; + static int N_LEVELS; +public: + static ErrorCorrectionLevel L; + static ErrorCorrectionLevel M; + static ErrorCorrectionLevel Q; + static ErrorCorrectionLevel H; + + int ordinal(); + static ErrorCorrectionLevel& forBits(int bits); +}; +} +} + +#endif // __ERROR_CORRECTION_LEVEL_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.cpp new file mode 100644 index 000000000..41332fb0f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.cpp @@ -0,0 +1,108 @@ +/* + * FormatInformation.cpp + * zxing + * + * Created by Christian Brunschen on 18/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +int FormatInformation::FORMAT_INFO_MASK_QR = 0x5412; +int FormatInformation::FORMAT_INFO_DECODE_LOOKUP[][2] = { { 0x5412, 0x00 }, { 0x5125, 0x01 }, { 0x5E7C, 0x02 }, { + 0x5B4B, 0x03 }, { 0x45F9, 0x04 }, { 0x40CE, 0x05 }, { 0x4F97, 0x06 }, { 0x4AA0, 0x07 }, { 0x77C4, 0x08 }, { + 0x72F3, 0x09 }, { 0x7DAA, 0x0A }, { 0x789D, 0x0B }, { 0x662F, 0x0C }, { 0x6318, 0x0D }, { 0x6C41, 0x0E }, { + 0x6976, 0x0F }, { 0x1689, 0x10 }, { 0x13BE, 0x11 }, { 0x1CE7, 0x12 }, { 0x19D0, 0x13 }, { 0x0762, 0x14 }, { + 0x0255, 0x15 }, { 0x0D0C, 0x16 }, { 0x083B, 0x17 }, { 0x355F, 0x18 }, { 0x3068, 0x19 }, { 0x3F31, 0x1A }, { + 0x3A06, 0x1B }, { 0x24B4, 0x1C }, { 0x2183, 0x1D }, { 0x2EDA, 0x1E }, { 0x2BED, 0x1F }, +}; +int FormatInformation::N_FORMAT_INFO_DECODE_LOOKUPS = 32; + +int FormatInformation::BITS_SET_IN_HALF_BYTE[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +FormatInformation::FormatInformation(int formatInfo) : + errorCorrectionLevel_(ErrorCorrectionLevel::forBits((formatInfo >> 3) & 0x03)), dataMask_( + (unsigned char)(formatInfo & 0x07)) { +} + +ErrorCorrectionLevel& FormatInformation::getErrorCorrectionLevel() { + return errorCorrectionLevel_; +} + +unsigned char FormatInformation::getDataMask() { + return dataMask_; +} + +int FormatInformation::numBitsDiffering(unsigned int a, unsigned int b) { + a ^= b; + return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(a >> 4 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 8 + & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 12 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 16 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 20 & 0x0F)] + BITS_SET_IN_HALF_BYTE[(a >> 24 & 0x0F)] + + BITS_SET_IN_HALF_BYTE[(a >> 28 & 0x0F)]; +} + +Ref FormatInformation::decodeFormatInformation(int rawFormatInfo) { + Ref result(doDecodeFormatInformation(rawFormatInfo)); + if (result != 0) { + return result; + } + return doDecodeFormatInformation(rawFormatInfo ^ FORMAT_INFO_MASK_QR); +} +Ref FormatInformation::doDecodeFormatInformation(int rawFormatInfo) { + // Unmask: + int unmaskedFormatInfo = rawFormatInfo ^ FORMAT_INFO_MASK_QR; + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + int bestDifference = numeric_limits::max(); + int bestFormatInfo = 0; + for (int i = 0; i < N_FORMAT_INFO_DECODE_LOOKUPS; i++) { + int* decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; + int targetInfo = decodeInfo[0]; + if (targetInfo == unmaskedFormatInfo) { + // Found an exact match + Ref result(new FormatInformation(decodeInfo[1])); + return result; + } + int bitsDifference = numBitsDiffering(unmaskedFormatInfo, targetInfo); + if (bitsDifference < bestDifference) { + bestFormatInfo = decodeInfo[1]; + bestDifference = bitsDifference; + } + } + if (bestDifference <= 3) { + Ref result(new FormatInformation(bestFormatInfo)); + return result; + } + Ref result; + return result; +} + +bool operator==(const FormatInformation &a, const FormatInformation &b) { + return &(a.errorCorrectionLevel_) == &(b.errorCorrectionLevel_) && a.dataMask_ == b.dataMask_; +} + +ostream& operator<<(ostream& out, const FormatInformation& fi) { + const FormatInformation *fip = &fi; + out << "FormatInformation @ " << fip; + return out; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.h new file mode 100644 index 000000000..cad027a01 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/FormatInformation.h @@ -0,0 +1,55 @@ +#ifndef __FORMAT_INFORMATION_H__ +#define __FORMAT_INFORMATION_H__ + +/* + * FormatInformation.h + * zxing + * + * Created by Christian Brunschen on 18/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class FormatInformation : public Counted { +private: + static int FORMAT_INFO_MASK_QR; + static int FORMAT_INFO_DECODE_LOOKUP[][2]; + static int N_FORMAT_INFO_DECODE_LOOKUPS; + static int BITS_SET_IN_HALF_BYTE[]; + + ErrorCorrectionLevel &errorCorrectionLevel_; + unsigned char dataMask_; + + FormatInformation(int formatInfo); + +public: + static int numBitsDiffering(unsigned int a, unsigned int b); + static Ref decodeFormatInformation(int rawFormatInfo); + static Ref doDecodeFormatInformation(int rawFormatInfo); + ErrorCorrectionLevel &getErrorCorrectionLevel(); + unsigned char getDataMask(); + friend bool operator==(const FormatInformation &a, const FormatInformation &b); + friend std::ostream& operator<<(std::ostream& out, const FormatInformation& fi); +}; +} +} + +#endif // __FORMAT_INFORMATION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.cpp new file mode 100644 index 000000000..656b6f9bf --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.cpp @@ -0,0 +1,82 @@ +/* + * QRCodeReader.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +namespace zxing { + namespace qrcode { + + using namespace std; + + QRCodeReader::QRCodeReader() :decoder_() { + } + + Ref QRCodeReader::decode(Ref image) { +#ifdef DEBUG + cout << "decoding image " << image.object_ << ":\n" << flush; +#endif + + Detector detector(image->getBlackMatrix()); + + +#ifdef DEBUG + cout << "(1) created detector " << &detector << "\n" << flush; +#endif + + Ref detectorResult(detector.detect()); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush; +#endif + + std::vector > points(detectorResult->getPoints()); + + +#ifdef DEBUG + cout << "(3) extracted points " << &points << "\n" << flush; + cout << "found " << points->size() << " points:\n"; + for (size_t i = 0; i < points->size(); i++) { + cout << " " << points[i]->getX() << "," << points[i]->getY() << "\n"; + } + cout << "bits:\n"; + cout << *(detectorResult->getBits()) << "\n"; +#endif + + Ref decoderResult(decoder_.decode(detectorResult->getBits())); +#ifdef DEBUG + cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush; +#endif + + Ref result( + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE)); +#ifdef DEBUG + cout << "(5) created result " << result.object_ << ", returning\n" << flush; +#endif + + return result; + } + + QRCodeReader::~QRCodeReader() { + } + + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.h new file mode 100644 index 000000000..8257c7a39 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/QRCodeReader.h @@ -0,0 +1,43 @@ +#ifndef __QR_CODE_READER_H__ +#define __QR_CODE_READER_H__ + +/* + * QRCodeReader.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class QRCodeReader : public Reader { + private: + Decoder decoder_; + + public: + QRCodeReader(); + virtual Ref decode(Ref image); + virtual ~QRCodeReader(); + + }; + } +} + +#endif // __QR_CODE_READER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp new file mode 100644 index 000000000..5e63c8271 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.cpp @@ -0,0 +1,559 @@ +/* + * Version.cpp + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { +using namespace std; + +ECB::ECB(int count, int dataCodewords) : + count_(count), dataCodewords_(dataCodewords) { +} + +int ECB::getCount() { + return count_; +} + +int ECB::getDataCodewords() { + return dataCodewords_; +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) : + ecCodewords_(ecCodewords) { + ecBlocks_.push_back(ecBlocks); +} + +ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) : + ecCodewords_(ecCodewords) { + ecBlocks_.push_back(ecBlocks1); + ecBlocks_.push_back(ecBlocks2); +} + +int ECBlocks::getECCodewords() { + return ecCodewords_; +} + +std::vector& ECBlocks::getECBlocks() { + return ecBlocks_; +} + +ECBlocks::~ECBlocks() { + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +unsigned int Version::VERSION_DECODE_INFO[] = { 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, + 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, + 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, + 0x27541, 0x28C69 + }; +int Version::N_VERSION_DECODE_INFOS = 34; +vector > Version::VERSIONS; +static int N_VERSIONS = Version::buildVersions(); + +int Version::getVersionNumber() { + return versionNumber_; +} + +valarray &Version::getAlignmentPatternCenters() { + return alignmentPatternCenters_; +} + +int Version::getTotalCodewords() { + return totalCodewords_; +} + +int Version::getDimensionForVersion() { + return 17 + 4 * versionNumber_; +} + +ECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) { + return *ecBlocks_[ecLevel.ordinal()]; +} + +Version *Version::getProvisionalVersionForDimension(int dimension) { + if (dimension % 4 != 1) { + throw ReaderException("Dimension must be 1 mod 4"); + } + return Version::getVersionForNumber((dimension - 17) >> 2); +} + +Version *Version::getVersionForNumber(int versionNumber) { + if (versionNumber < 1 || versionNumber > 40) { + throw ReaderException("versionNumber must be between 1 and 40"); + } + + return VERSIONS[versionNumber - 1]; +} + +Version::Version(int versionNumber, valarray *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, + ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) : + versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4) { + ecBlocks_[0] = ecBlocks1; + ecBlocks_[1] = ecBlocks2; + ecBlocks_[2] = ecBlocks3; + ecBlocks_[3] = ecBlocks4; + + int total = 0; + int ecCodewords = ecBlocks1->getECCodewords(); + vector &ecbArray = ecBlocks1->getECBlocks(); + for (size_t i = 0; i < ecbArray.size(); i++) { + ECB *ecBlock = ecbArray[i]; + total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords); + } + totalCodewords_ = total; +} + +Version::~Version() { + delete &alignmentPatternCenters_; + for (size_t i = 0; i < ecBlocks_.size(); i++) { + delete ecBlocks_[i]; + } +} + +Version *Version::decodeVersionInformation(unsigned int versionBits) { + int bestDifference = numeric_limits::max(); + size_t bestVersion = 0; + for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) { + unsigned targetVersion = VERSION_DECODE_INFO[i]; + // Do the version info bits match exactly? done. + if (targetVersion == versionBits) { + return getVersionForNumber(i + 7); + } + // Otherwise see if this is the closest to a real version info bit + // string we have seen so far + int bitsDifference = FormatInformation::numBitsDiffering(versionBits, targetVersion); + if (bitsDifference < bestDifference) { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + // We can tolerate up to 3 bits of error since no two version info codewords will + // differ in less than 4 bits. + if (bestDifference <= 3) { + return getVersionForNumber(bestVersion); + } + // If we didn't find a close enough match, fail + return 0; +} + +Ref Version::buildFunctionPattern() { + int dimension = getDimensionForVersion(); + Ref functionPattern(new BitMatrix(dimension)); + + + // Top left finder pattern + separator + format + functionPattern->setRegion(0, 0, 9, 9); + // Top right finder pattern + separator + format + functionPattern->setRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + functionPattern->setRegion(0, dimension - 8, 9, 8); + + + // Alignment patterns + size_t max = alignmentPatternCenters_.size(); + for (size_t x = 0; x < max; x++) { + int i = alignmentPatternCenters_[x] - 2; + for (size_t y = 0; y < max; y++) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + // No alignment patterns near the three finder patterns + continue; + } + functionPattern->setRegion(alignmentPatternCenters_[y] - 2, i, 5, 5); + } + } + + // Vertical timing pattern + functionPattern->setRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + functionPattern->setRegion(9, 6, dimension - 17, 1); + + if (versionNumber_ > 6) { + // Version info, top right + functionPattern->setRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + functionPattern->setRegion(0, dimension - 11, 6, 3); + } + + + //#ifdef DEBUG + // cout << "version " << versionNumber_ << " built function pattern:\n"; + // cout << *functionPattern; + //#endif + + return functionPattern; +} + +static valarray *intArray(size_t n...) { + va_list ap; + va_start(ap, n); + valarray *result = new valarray(n); + for (size_t i = 0; i < n; i++) { + (*result)[i] = va_arg(ap, int); + } + va_end(ap); + return result; +} + +int Version::buildVersions() { + VERSIONS.push_back(Ref(new Version(1, intArray(0), + new ECBlocks(7, new ECB(1, 19)), + new ECBlocks(10, new ECB(1, 16)), + new ECBlocks(13, new ECB(1, 13)), + new ECBlocks(17, new ECB(1, 9))))); + VERSIONS.push_back(Ref(new Version(2, intArray(2, 6, 18), + new ECBlocks(10, new ECB(1, 34)), + new ECBlocks(16, new ECB(1, 28)), + new ECBlocks(22, new ECB(1, 22)), + new ECBlocks(28, new ECB(1, 16))))); + VERSIONS.push_back(Ref(new Version(3, intArray(2, 6, 22), + new ECBlocks(15, new ECB(1, 55)), + new ECBlocks(26, new ECB(1, 44)), + new ECBlocks(18, new ECB(2, 17)), + new ECBlocks(22, new ECB(2, 13))))); + VERSIONS.push_back(Ref(new Version(4, intArray(2, 6, 26), + new ECBlocks(20, new ECB(1, 80)), + new ECBlocks(18, new ECB(2, 32)), + new ECBlocks(26, new ECB(2, 24)), + new ECBlocks(16, new ECB(4, 9))))); + VERSIONS.push_back(Ref(new Version(5, intArray(2, 6, 30), + new ECBlocks(26, new ECB(1, 108)), + new ECBlocks(24, new ECB(2, 43)), + new ECBlocks(18, new ECB(2, 15), + new ECB(2, 16)), + new ECBlocks(22, new ECB(2, 11), + new ECB(2, 12))))); + VERSIONS.push_back(Ref(new Version(6, intArray(2, 6, 34), + new ECBlocks(18, new ECB(2, 68)), + new ECBlocks(16, new ECB(4, 27)), + new ECBlocks(24, new ECB(4, 19)), + new ECBlocks(28, new ECB(4, 15))))); + VERSIONS.push_back(Ref(new Version(7, intArray(3, 6, 22, 38), + new ECBlocks(20, new ECB(2, 78)), + new ECBlocks(18, new ECB(4, 31)), + new ECBlocks(18, new ECB(2, 14), + new ECB(4, 15)), + new ECBlocks(26, new ECB(4, 13), + new ECB(1, 14))))); + VERSIONS.push_back(Ref(new Version(8, intArray(3, 6, 24, 42), + new ECBlocks(24, new ECB(2, 97)), + new ECBlocks(22, new ECB(2, 38), + new ECB(2, 39)), + new ECBlocks(22, new ECB(4, 18), + new ECB(2, 19)), + new ECBlocks(26, new ECB(4, 14), + new ECB(2, 15))))); + VERSIONS.push_back(Ref(new Version(9, intArray(3, 6, 26, 46), + new ECBlocks(30, new ECB(2, 116)), + new ECBlocks(22, new ECB(3, 36), + new ECB(2, 37)), + new ECBlocks(20, new ECB(4, 16), + new ECB(4, 17)), + new ECBlocks(24, new ECB(4, 12), + new ECB(4, 13))))); + VERSIONS.push_back(Ref(new Version(10, intArray(3, 6, 28, 50), + new ECBlocks(18, new ECB(2, 68), + new ECB(2, 69)), + new ECBlocks(26, new ECB(4, 43), + new ECB(1, 44)), + new ECBlocks(24, new ECB(6, 19), + new ECB(2, 20)), + new ECBlocks(28, new ECB(6, 15), + new ECB(2, 16))))); + VERSIONS.push_back(Ref(new Version(11, intArray(3, 6, 30, 54), + new ECBlocks(20, new ECB(4, 81)), + new ECBlocks(30, new ECB(1, 50), + new ECB(4, 51)), + new ECBlocks(28, new ECB(4, 22), + new ECB(4, 23)), + new ECBlocks(24, new ECB(3, 12), + new ECB(8, 13))))); + VERSIONS.push_back(Ref(new Version(12, intArray(3, 6, 32, 58), + new ECBlocks(24, new ECB(2, 92), + new ECB(2, 93)), + new ECBlocks(22, new ECB(6, 36), + new ECB(2, 37)), + new ECBlocks(26, new ECB(4, 20), + new ECB(6, 21)), + new ECBlocks(28, new ECB(7, 14), + new ECB(4, 15))))); + VERSIONS.push_back(Ref(new Version(13, intArray(3, 6, 34, 62), + new ECBlocks(26, new ECB(4, 107)), + new ECBlocks(22, new ECB(8, 37), + new ECB(1, 38)), + new ECBlocks(24, new ECB(8, 20), + new ECB(4, 21)), + new ECBlocks(22, new ECB(12, 11), + new ECB(4, 12))))); + VERSIONS.push_back(Ref(new Version(14, intArray(4, 6, 26, 46, 66), + new ECBlocks(30, new ECB(3, 115), + new ECB(1, 116)), + new ECBlocks(24, new ECB(4, 40), + new ECB(5, 41)), + new ECBlocks(20, new ECB(11, 16), + new ECB(5, 17)), + new ECBlocks(24, new ECB(11, 12), + new ECB(5, 13))))); + VERSIONS.push_back(Ref(new Version(15, intArray(4, 6, 26, 48, 70), + new ECBlocks(22, new ECB(5, 87), + new ECB(1, 88)), + new ECBlocks(24, new ECB(5, 41), + new ECB(5, 42)), + new ECBlocks(30, new ECB(5, 24), + new ECB(7, 25)), + new ECBlocks(24, new ECB(11, 12), + new ECB(7, 13))))); + VERSIONS.push_back(Ref(new Version(16, intArray(4, 6, 26, 50, 74), + new ECBlocks(24, new ECB(5, 98), + new ECB(1, 99)), + new ECBlocks(28, new ECB(7, 45), + new ECB(3, 46)), + new ECBlocks(24, new ECB(15, 19), + new ECB(2, 20)), + new ECBlocks(30, new ECB(3, 15), + new ECB(13, 16))))); + VERSIONS.push_back(Ref(new Version(17, intArray(4, 6, 30, 54, 78), + new ECBlocks(28, new ECB(1, 107), + new ECB(5, 108)), + new ECBlocks(28, new ECB(10, 46), + new ECB(1, 47)), + new ECBlocks(28, new ECB(1, 22), + new ECB(15, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(17, 15))))); + VERSIONS.push_back(Ref(new Version(18, intArray(4, 6, 30, 56, 82), + new ECBlocks(30, new ECB(5, 120), + new ECB(1, 121)), + new ECBlocks(26, new ECB(9, 43), + new ECB(4, 44)), + new ECBlocks(28, new ECB(17, 22), + new ECB(1, 23)), + new ECBlocks(28, new ECB(2, 14), + new ECB(19, 15))))); + VERSIONS.push_back(Ref(new Version(19, intArray(4, 6, 30, 58, 86), + new ECBlocks(28, new ECB(3, 113), + new ECB(4, 114)), + new ECBlocks(26, new ECB(3, 44), + new ECB(11, 45)), + new ECBlocks(26, new ECB(17, 21), + new ECB(4, 22)), + new ECBlocks(26, new ECB(9, 13), + new ECB(16, 14))))); + VERSIONS.push_back(Ref(new Version(20, intArray(4, 6, 34, 62, 90), + new ECBlocks(28, new ECB(3, 107), + new ECB(5, 108)), + new ECBlocks(26, new ECB(3, 41), + new ECB(13, 42)), + new ECBlocks(30, new ECB(15, 24), + new ECB(5, 25)), + new ECBlocks(28, new ECB(15, 15), + new ECB(10, 16))))); + VERSIONS.push_back(Ref(new Version(21, intArray(5, 6, 28, 50, 72, 94), + new ECBlocks(28, new ECB(4, 116), + new ECB(4, 117)), + new ECBlocks(26, new ECB(17, 42)), + new ECBlocks(28, new ECB(17, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(19, 16), + new ECB(6, 17))))); + VERSIONS.push_back(Ref(new Version(22, intArray(5, 6, 26, 50, 74, 98), + new ECBlocks(28, new ECB(2, 111), + new ECB(7, 112)), + new ECBlocks(28, new ECB(17, 46)), + new ECBlocks(30, new ECB(7, 24), + new ECB(16, 25)), + new ECBlocks(24, new ECB(34, 13))))); + VERSIONS.push_back(Ref(new Version(23, intArray(5, 6, 30, 54, 74, 102), + new ECBlocks(30, new ECB(4, 121), + new ECB(5, 122)), + new ECBlocks(28, new ECB(4, 47), + new ECB(14, 48)), + new ECBlocks(30, new ECB(11, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(16, 15), + new ECB(14, 16))))); + VERSIONS.push_back(Ref(new Version(24, intArray(5, 6, 28, 54, 80, 106), + new ECBlocks(30, new ECB(6, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(6, 45), + new ECB(14, 46)), + new ECBlocks(30, new ECB(11, 24), + new ECB(16, 25)), + new ECBlocks(30, new ECB(30, 16), + new ECB(2, 17))))); + VERSIONS.push_back(Ref(new Version(25, intArray(5, 6, 32, 58, 84, 110), + new ECBlocks(26, new ECB(8, 106), + new ECB(4, 107)), + new ECBlocks(28, new ECB(8, 47), + new ECB(13, 48)), + new ECBlocks(30, new ECB(7, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(13, 16))))); + VERSIONS.push_back(Ref(new Version(26, intArray(5, 6, 30, 58, 86, 114), + new ECBlocks(28, new ECB(10, 114), + new ECB(2, 115)), + new ECBlocks(28, new ECB(19, 46), + new ECB(4, 47)), + new ECBlocks(28, new ECB(28, 22), + new ECB(6, 23)), + new ECBlocks(30, new ECB(33, 16), + new ECB(4, 17))))); + VERSIONS.push_back(Ref(new Version(27, intArray(5, 6, 34, 62, 90, 118), + new ECBlocks(30, new ECB(8, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(22, 45), + new ECB(3, 46)), + new ECBlocks(30, new ECB(8, 23), + new ECB(26, 24)), + new ECBlocks(30, new ECB(12, 15), + new ECB(28, 16))))); + VERSIONS.push_back(Ref(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122), + new ECBlocks(30, new ECB(3, 117), + new ECB(10, 118)), + new ECBlocks(28, new ECB(3, 45), + new ECB(23, 46)), + new ECBlocks(30, new ECB(4, 24), + new ECB(31, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(31, 16))))); + VERSIONS.push_back(Ref(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126), + new ECBlocks(30, new ECB(7, 116), + new ECB(7, 117)), + new ECBlocks(28, new ECB(21, 45), + new ECB(7, 46)), + new ECBlocks(30, new ECB(1, 23), + new ECB(37, 24)), + new ECBlocks(30, new ECB(19, 15), + new ECB(26, 16))))); + VERSIONS.push_back(Ref(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130), + new ECBlocks(30, new ECB(5, 115), + new ECB(10, 116)), + new ECBlocks(28, new ECB(19, 47), + new ECB(10, 48)), + new ECBlocks(30, new ECB(15, 24), + new ECB(25, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(25, 16))))); + VERSIONS.push_back(Ref(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134), + new ECBlocks(30, new ECB(13, 115), + new ECB(3, 116)), + new ECBlocks(28, new ECB(2, 46), + new ECB(29, 47)), + new ECBlocks(30, new ECB(42, 24), + new ECB(1, 25)), + new ECBlocks(30, new ECB(23, 15), + new ECB(28, 16))))); + VERSIONS.push_back(Ref(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138), + new ECBlocks(30, new ECB(17, 115)), + new ECBlocks(28, new ECB(10, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(10, 24), + new ECB(35, 25)), + new ECBlocks(30, new ECB(19, 15), + new ECB(35, 16))))); + VERSIONS.push_back(Ref(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142), + new ECBlocks(30, new ECB(17, 115), + new ECB(1, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(21, 47)), + new ECBlocks(30, new ECB(29, 24), + new ECB(19, 25)), + new ECBlocks(30, new ECB(11, 15), + new ECB(46, 16))))); + VERSIONS.push_back(Ref(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146), + new ECBlocks(30, new ECB(13, 115), + new ECB(6, 116)), + new ECBlocks(28, new ECB(14, 46), + new ECB(23, 47)), + new ECBlocks(30, new ECB(44, 24), + new ECB(7, 25)), + new ECBlocks(30, new ECB(59, 16), + new ECB(1, 17))))); + VERSIONS.push_back(Ref(new Version(35, intArray(7, 6, 30, 54, 78, + 102, 126, 150), + new ECBlocks(30, new ECB(12, 121), + new ECB(7, 122)), + new ECBlocks(28, new ECB(12, 47), + new ECB(26, 48)), + new ECBlocks(30, new ECB(39, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(22, 15), + new ECB(41, 16))))); + VERSIONS.push_back(Ref(new Version(36, intArray(7, 6, 24, 50, 76, + 102, 128, 154), + new ECBlocks(30, new ECB(6, 121), + new ECB(14, 122)), + new ECBlocks(28, new ECB(6, 47), + new ECB(34, 48)), + new ECBlocks(30, new ECB(46, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(2, 15), + new ECB(64, 16))))); + VERSIONS.push_back(Ref(new Version(37, intArray(7, 6, 28, 54, 80, + 106, 132, 158), + new ECBlocks(30, new ECB(17, 122), + new ECB(4, 123)), + new ECBlocks(28, new ECB(29, 46), + new ECB(14, 47)), + new ECBlocks(30, new ECB(49, 24), + new ECB(10, 25)), + new ECBlocks(30, new ECB(24, 15), + new ECB(46, 16))))); + VERSIONS.push_back(Ref(new Version(38, intArray(7, 6, 32, 58, 84, + 110, 136, 162), + new ECBlocks(30, new ECB(4, 122), + new ECB(18, 123)), + new ECBlocks(28, new ECB(13, 46), + new ECB(32, 47)), + new ECBlocks(30, new ECB(48, 24), + new ECB(14, 25)), + new ECBlocks(30, new ECB(42, 15), + new ECB(32, 16))))); + VERSIONS.push_back(Ref(new Version(39, intArray(7, 6, 26, 54, 82, + 110, 138, 166), + new ECBlocks(30, new ECB(20, 117), + new ECB(4, 118)), + new ECBlocks(28, new ECB(40, 47), + new ECB(7, 48)), + new ECBlocks(30, new ECB(43, 24), + new ECB(22, 25)), + new ECBlocks(30, new ECB(10, 15), + new ECB(67, 16))))); + VERSIONS.push_back(Ref(new Version(40, intArray(7, 6, 30, 58, 86, + 114, 142, 170), + new ECBlocks(30, new ECB(19, 118), + new ECB(6, 119)), + new ECBlocks(28, new ECB(18, 47), + new ECB(31, 48)), + new ECBlocks(30, new ECB(34, 24), + new ECB(34, 25)), + new ECBlocks(30, new ECB(20, 15), + new ECB(61, 16))))); + return VERSIONS.size(); +} +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h new file mode 100644 index 000000000..181bd98fe --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/Version.h @@ -0,0 +1,87 @@ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +/* + * Version.h + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class ECB { +private: + int count_; + int dataCodewords_; +public: + ECB(int count, int dataCodewords); + int getCount(); + int getDataCodewords(); +}; + +class ECBlocks { +private: + int ecCodewords_; + std::vector ecBlocks_; +public: + ECBlocks(int ecCodewords, ECB *ecBlocks); + ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2); + int getECCodewords(); + std::vector& getECBlocks(); + ~ECBlocks(); +}; + +class Version : public Counted { + +private: + int versionNumber_; + std::valarray &alignmentPatternCenters_; + std::vector ecBlocks_; + int totalCodewords_; + Version(int versionNumber, std::valarray *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2, + ECBlocks *ecBlocks3, ECBlocks *ecBlocks4); + +public: + static unsigned int VERSION_DECODE_INFO[]; + static int N_VERSION_DECODE_INFOS; + static std::vector > VERSIONS; + + ~Version(); + int getVersionNumber(); + std::valarray &getAlignmentPatternCenters(); + int getTotalCodewords(); + int getDimensionForVersion(); + ECBlocks &getECBlocksForLevel(ErrorCorrectionLevel &ecLevel); + static Version *getProvisionalVersionForDimension(int dimension); + static Version *getVersionForNumber(int versionNumber); + static Version *decodeVersionInformation(unsigned int versionBits); + Ref buildFunctionPattern(); + static int buildVersions(); +}; +} +} + +#endif // __VERSION_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp new file mode 100644 index 000000000..e4ef5e2d8 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.cpp @@ -0,0 +1,191 @@ +/* + * BitMatrixParser.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + + +namespace zxing { +namespace qrcode { + +int BitMatrixParser::copyBit(size_t x, size_t y, int versionBits) { + return bitMatrix_->get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1; +} + +BitMatrixParser::BitMatrixParser(Ref bitMatrix) : + bitMatrix_(bitMatrix), parsedVersion_(0), parsedFormatInfo_() { + size_t dimension = bitMatrix->getDimension(); + if ((dimension < 21) || (dimension & 0x03) != 1) { + throw ReaderException("Dimension must be 1 mod 4 and >= 21"); + } +} + +Ref BitMatrixParser::readFormatInformation() { + if (parsedFormatInfo_ != 0) { + return parsedFormatInfo_; + } + + // Read top-left format info bits + int formatInfoBits = 0; + for (int x = 0; x < 6; x++) { + formatInfoBits = copyBit(x, 8, formatInfoBits); + } + // .. and skip a bit in the timing pattern ... + formatInfoBits = copyBit(7, 8, formatInfoBits); + formatInfoBits = copyBit(8, 8, formatInfoBits); + formatInfoBits = copyBit(8, 7, formatInfoBits); + // .. and skip a bit in the timing pattern ... + for (int y = 5; y >= 0; y--) { + formatInfoBits = copyBit(8, y, formatInfoBits); + } + + parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits); + if (parsedFormatInfo_ != 0) { + return parsedFormatInfo_; + } + + // Hmm, failed. Try the top-right/bottom-left pattern + int dimension = bitMatrix_->getDimension(); + formatInfoBits = 0; + int yMin = dimension - 8; + for (int y = dimension - 1; y >= yMin; y--) { + formatInfoBits = copyBit(8, y, formatInfoBits); + } + for (int x = dimension - 7; x < dimension; x++) { + formatInfoBits = copyBit(x, 8, formatInfoBits); + } + + parsedFormatInfo_ = FormatInformation::decodeFormatInformation(formatInfoBits); + if (parsedFormatInfo_ != 0) { + return parsedFormatInfo_; + } + throw ReaderException("Could not decode format information"); +} + +Version *BitMatrixParser::readVersion() { + if (parsedVersion_ != 0) { + return parsedVersion_; + } + + size_t dimension = bitMatrix_->getDimension(); + + int provisionalVersion = (dimension - 17) >> 2; + if (provisionalVersion <= 6) { + return Version::getVersionForNumber(provisionalVersion); + } + + // Read top-right version info: 3 wide by 6 tall + int versionBits = 0; + for (int y = 5; y >= 0; y--) { + int xMin = dimension - 11; + for (int x = dimension - 9; x >= xMin; x--) { + versionBits = copyBit(x, y, versionBits); + } + } + + parsedVersion_ = Version::decodeVersionInformation(versionBits); + if (parsedVersion_ != 0) { + return parsedVersion_; + } + + // Hmm, failed. Try bottom left: 6 wide by 3 tall + versionBits = 0; + for (int x = 5; x >= 0; x--) { + int yMin = dimension - 11; + for (int y = dimension - 9; y >= yMin; y--) { + versionBits = copyBit(x, y, versionBits); + } + } + + parsedVersion_ = Version::decodeVersionInformation(versionBits); + if (parsedVersion_ != 0) { + return parsedVersion_; + } + throw ReaderException("Could not decode version"); +} + +ArrayRef BitMatrixParser::readCodewords() { + Ref formatInfo = readFormatInformation(); + Version *version = readVersion(); + + + // cerr << *bitMatrix_ << endl; + // cerr << bitMatrix_->getDimension() << endl; + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + DataMask &dataMask = DataMask::forReference((int)formatInfo->getDataMask()); + // cout << (int)formatInfo->getDataMask() << endl; + int dimension = bitMatrix_->getDimension(); + dataMask.unmaskBitMatrix(*bitMatrix_, dimension); + + + // cerr << *bitMatrix_ << endl; + // cerr << version->getTotalCodewords() << endl; + + Ref functionPattern = version->buildFunctionPattern(); + + + // cout << *functionPattern << endl; + + bool readingUp = true; + ArrayRef result(version->getTotalCodewords()); + int resultOffset = 0; + int currentByte = 0; + int bitsRead = 0; + // Read columns in pairs, from right to left + for (int x = dimension - 1; x > 0; x -= 2) { + if (x == 6) { + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + x--; + } + // Read alternatingly from bottom to top then top to bottom + for (int count = 0; count < dimension; count++) { + int y = readingUp ? dimension - 1 - count : count; + for (int col = 0; col < 2; col++) { + // Ignore bits covered by the function pattern + if (!functionPattern->get(x - col, y)) { + // Read a bit + bitsRead++; + currentByte <<= 1; + if (bitMatrix_->get(x - col, y)) { + currentByte |= 1; + } + // If we've made a whole byte, save it off + if (bitsRead == 8) { + result[resultOffset++] = (unsigned char)currentByte; + bitsRead = 0; + currentByte = 0; + } + } + } + } + readingUp = !readingUp; // switch directions + } + + if (resultOffset != version->getTotalCodewords()) { + throw ReaderException("Did not read all codewords"); + } + return result; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h new file mode 100644 index 000000000..824556b93 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/BitMatrixParser.h @@ -0,0 +1,52 @@ +#ifndef __BIT_MATRIX_PARSER_H__ +#define __BIT_MATRIX_PARSER_H__ + +/* + * BitMatrixParser.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class BitMatrixParser : public Counted { +private: + Ref bitMatrix_; + Version *parsedVersion_; + Ref parsedFormatInfo_; + + int copyBit(size_t x, size_t y, int versionBits); + +public: + BitMatrixParser(Ref bitMatrix); + Ref readFormatInformation(); + Version *readVersion(); + ArrayRef readCodewords(); +}; + +} +} + +#endif // __BIT_MATRIX_PARSER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.cpp new file mode 100644 index 000000000..1ea6602d7 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.cpp @@ -0,0 +1,118 @@ +/* + * DataBlock.cpp + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +DataBlock::DataBlock(int numDataCodewords, ArrayRef codewords) : + numDataCodewords_(numDataCodewords), codewords_(codewords) { +} + +int DataBlock::getNumDataCodewords() { + return numDataCodewords_; +} + +ArrayRef DataBlock::getCodewords() { + return codewords_; +} + + +std::vector > DataBlock::getDataBlocks(ArrayRef rawCodewords, Version *version, + ErrorCorrectionLevel &ecLevel) { + + + // Figure out the number and size of data blocks used by this version and + // error correction level + ECBlocks &ecBlocks = version->getECBlocksForLevel(ecLevel); + + + // First count the total number of data blocks + int totalBlocks = 0; + vector ecBlockArray = ecBlocks.getECBlocks(); + for (size_t i = 0; i < ecBlockArray.size(); i++) { + totalBlocks += ecBlockArray[i]->getCount(); + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + std::vector > result(totalBlocks); + int numResultBlocks = 0; + for (size_t j = 0; j < ecBlockArray.size(); j++) { + ECB *ecBlock = ecBlockArray[j]; + for (int i = 0; i < ecBlock->getCount(); i++) { + int numDataCodewords = ecBlock->getDataCodewords(); + int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords; + ArrayRef buffer(numBlockCodewords); + Ref blockRef(new DataBlock(numDataCodewords, buffer)); + result[numResultBlocks++] = blockRef; + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + int shorterBlocksTotalCodewords = result[0]->codewords_.size(); + int longerBlocksStartAt = result.size() - 1; + while (longerBlocksStartAt >= 0) { + int numCodewords = result[longerBlocksStartAt]->codewords_.size(); + if (numCodewords == shorterBlocksTotalCodewords) { + break; + } + if (numCodewords != shorterBlocksTotalCodewords + 1) { + throw IllegalArgumentException("Data block sizes differ by more than 1"); + } + longerBlocksStartAt--; + } + longerBlocksStartAt++; + + int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords(); + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { + for (int j = 0; j < numResultBlocks; j++) { + result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { + result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; + } + // Now add in error correction blocks + int max = result[0]->codewords_.size(); + for (int i = shorterBlocksNumDataCodewords; i < max; i++) { + for (int j = 0; j < numResultBlocks; j++) { + int iOffset = j < longerBlocksStartAt ? i : i + 1; + result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++]; + } + } + + if ((size_t)rawCodewordsOffset != rawCodewords.size()) { + throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); + } + + return result; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h new file mode 100644 index 000000000..df536f4d6 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataBlock.h @@ -0,0 +1,52 @@ +#ifndef __DATA_BLOCK_H__ +#define __DATA_BLOCK_H__ + +/* + * DataBlock.h + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class DataBlock : public Counted { +private: + int numDataCodewords_; + ArrayRef codewords_; + + DataBlock(int numDataCodewords, ArrayRef codewords); + +public: + static std::vector > + getDataBlocks(ArrayRef rawCodewords, Version *version, ErrorCorrectionLevel &ecLevel); + + int getNumDataCodewords(); + ArrayRef getCodewords(); +}; + +} +} + +#endif // __DATA_BLOCK_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.cpp new file mode 100644 index 000000000..9b293b13c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.cpp @@ -0,0 +1,159 @@ +/* + * DataMask.cpp + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +DataMask::DataMask() { +} + +DataMask::~DataMask() { +} + +vector > DataMask::DATA_MASKS; +static int N_DATA_MASKS = DataMask::buildDataMasks(); + +DataMask &DataMask::forReference(int reference) { + if (reference < 0 || reference > 7) { + throw IllegalArgumentException("reference must be between 0 and 7"); + } + return *DATA_MASKS[reference]; +} + +void DataMask::unmaskBitMatrix(BitMatrix& bits, size_t dimension) { + for (size_t y = 0; y < dimension; y++) { + for (size_t x = 0; x < dimension; x++) { + // TODO: check why the coordinates have to be swapped + if (isMasked(y, x)) { + bits.flip(x, y); + } + } + } +} + +/** + * 000: mask bits for which (x + y) mod 2 == 0 + */ +class DataMask000 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return ((x + y) & 0x01) == 0; + return ((x + y) % 2) == 0; + } +}; + +/** + * 001: mask bits for which x mod 2 == 0 + */ +class DataMask001 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return (x & 0x01) == 0; + return (x % 2) == 0; + } +}; + +/** + * 010: mask bits for which y mod 3 == 0 + */ +class DataMask010 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + return y % 3 == 0; + } +}; + +/** + * 011: mask bits for which (x + y) mod 3 == 0 + */ +class DataMask011 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + return (x + y) % 3 == 0; + } +}; + +/** + * 100: mask bits for which (x/2 + y/3) mod 2 == 0 + */ +class DataMask100 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return (((x >> 1) + (y / 3)) & 0x01) == 0; + return (((x >> 1) + (y / 3)) % 2) == 0; + } +}; + +/** + * 101: mask bits for which xy mod 2 + xy mod 3 == 0 + */ +class DataMask101 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + size_t temp = x * y; + // return (temp & 0x01) + (temp % 3) == 0; + return (temp % 2) + (temp % 3) == 0; + + } +}; + +/** + * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + */ +class DataMask110 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + size_t temp = x * y; + // return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; + return (((temp % 2) + (temp % 3)) % 2) == 0; + } +}; + +/** + * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + */ +class DataMask111 : public DataMask { +public: + bool isMasked(size_t x, size_t y) { + // return ((((x + y) & 0x01) + ((x * y) % 3)) & 0x01) == 0; + return ((((x + y) % 2) + ((x * y) % 3)) % 2) == 0; + } +}; + +int DataMask::buildDataMasks() { + DATA_MASKS.push_back(Ref (new DataMask000())); + DATA_MASKS.push_back(Ref (new DataMask001())); + DATA_MASKS.push_back(Ref (new DataMask010())); + DATA_MASKS.push_back(Ref (new DataMask011())); + DATA_MASKS.push_back(Ref (new DataMask100())); + DATA_MASKS.push_back(Ref (new DataMask101())); + DATA_MASKS.push_back(Ref (new DataMask110())); + DATA_MASKS.push_back(Ref (new DataMask111())); + return DATA_MASKS.size(); +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.h new file mode 100644 index 000000000..c4a3e0ccf --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DataMask.h @@ -0,0 +1,51 @@ +#ifndef __DATA_MASK_H__ +#define __DATA_MASK_H__ + +/* + * DataMask.h + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +namespace zxing { +namespace qrcode { + +class DataMask : public Counted { +private: + static std::vector > DATA_MASKS; + +protected: + +public: + static int buildDataMasks(); + DataMask(); + virtual ~DataMask(); + void unmaskBitMatrix(BitMatrix& matrix, size_t dimension); + virtual bool isMasked(size_t x, size_t y) = 0; + static DataMask& forReference(int reference); +}; + +} +} + +#endif // __DATA_MASK_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp new file mode 100644 index 000000000..ab32b2e8c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.cpp @@ -0,0 +1,282 @@ +/* + * DecodedBitStreamParser.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +// Required for compatibility. TODO: test on Symbian +#ifdef ZXING_ICONV_CONST +#undef ICONV_CONST +#define ICONV_CONST const +#endif + +#ifndef ICONV_CONST +#define ICONV_CONST /**/ +#endif + +using namespace zxing; + +namespace zxing { +namespace qrcode { + +using namespace std; + +const char DecodedBitStreamParser::ALPHANUMERIC_CHARS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' + }; + +const char *DecodedBitStreamParser::ASCII = "ASCII"; +const char *DecodedBitStreamParser::ISO88591 = "ISO-8859-1"; +const char *DecodedBitStreamParser::UTF8 = "UTF-8"; +const char *DecodedBitStreamParser::SHIFT_JIS = "SHIFT_JIS"; +const char *DecodedBitStreamParser::EUC_JP = "EUC-JP"; + +void DecodedBitStreamParser::append(ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src) { + if (nIn == 0) { + return; + } + + iconv_t cd = iconv_open(UTF8, src); + const int maxOut = 4 * nIn + 1; + unsigned char* bufOut = new unsigned char[maxOut]; + + ICONV_CONST char *fromPtr = (ICONV_CONST char *)bufIn; + size_t nFrom = nIn; + char *toPtr = (char *)bufOut; + size_t nTo = maxOut; + + while (nFrom > 0) { + size_t oneway = iconv(cd, (const char**)&fromPtr, &nFrom, &toPtr, &nTo); + if (oneway == (size_t)(-1)) { + iconv_close(cd); + delete[] bufOut; + throw ReaderException("error converting characters"); + } + } + iconv_close(cd); + + int nResult = maxOut - nTo; + bufOut[nResult] = '\0'; + + ost << bufOut; + delete[] bufOut; +} + +void DecodedBitStreamParser::decodeKanjiSegment(Ref bits, ostringstream &result, int count) { + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + size_t nBytes = 2 * count; + unsigned char* buffer = new unsigned char[nBytes]; + int offset = 0; + while (count > 0) { + // Each 13 bits encodes a 2-byte character + + int twoBytes = bits->readBits(13); + int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); + if (assembledTwoBytes < 0x01F00) { + // In the 0x8140 to 0x9FFC range + assembledTwoBytes += 0x08140; + } else { + // In the 0xE040 to 0xEBBF range + assembledTwoBytes += 0x0C140; + } + buffer[offset] = (unsigned char)(assembledTwoBytes >> 8); + buffer[offset + 1] = (unsigned char)assembledTwoBytes; + offset += 2; + count--; + } + + append(result, buffer, nBytes, SHIFT_JIS); + delete[] buffer; +} + +void DecodedBitStreamParser::decodeByteSegment(Ref bits, ostringstream &result, int count) { + int nBytes = count; + unsigned char* readBytes = new unsigned char[nBytes]; + if (count << 3 > bits->available()) { + ostringstream s; + s << "Count too large: " << count; + delete[] readBytes; + throw ReaderException(s.str().c_str()); + } + for (int i = 0; i < count; i++) { + readBytes[i] = (unsigned char)bits->readBits(8); + } + // The spec isn't clear on this mode; see + // section 6.4.5: t does not say which encoding to assuming + // upon decoding. I have seen ISO-8859-1 used as well as + // Shift_JIS -- without anything like an ECI designator to + // give a hint. + const char *encoding = guessEncoding(readBytes, nBytes); + append(result, readBytes, nBytes, encoding); + delete[] readBytes; +} + +void DecodedBitStreamParser::decodeNumericSegment(Ref bits, ostringstream &result, int count) { + int nBytes = count; + unsigned char* bytes = new unsigned char[nBytes]; + int i = 0; + // Read three digits at a time + while (count >= 3) { + // Each 10 bits encodes three digits + int threeDigitsBits = bits->readBits(10); + if (threeDigitsBits >= 1000) { + ostringstream s; + s << "Illegal value for 3-digit unit: " << threeDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits / 100]; + bytes[i++] = ALPHANUMERIC_CHARS[(threeDigitsBits / 10) % 10]; + bytes[i++] = ALPHANUMERIC_CHARS[threeDigitsBits % 10]; + count -= 3; + } + if (count == 2) { + // Two digits left over to read, encoded in 7 bits + int twoDigitsBits = bits->readBits(7); + if (twoDigitsBits >= 100) { + ostringstream s; + s << "Illegal value for 2-digit unit: " << twoDigitsBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits / 10]; + bytes[i++] = ALPHANUMERIC_CHARS[twoDigitsBits % 10]; + } else if (count == 1) { + // One digit left over to read + int digitBits = bits->readBits(4); + if (digitBits >= 10) { + ostringstream s; + s << "Illegal value for digit unit: " << digitBits; + delete[] bytes; + throw ReaderException(s.str().c_str()); + } + bytes[i++] = ALPHANUMERIC_CHARS[digitBits]; + } + append(result, bytes, nBytes, ASCII); + delete[] bytes; +} + +void DecodedBitStreamParser::decodeAlphanumericSegment(Ref bits, ostringstream &result, int count) { + int nBytes = count; + unsigned char* bytes = new unsigned char[nBytes]; + int i = 0; + // Read two characters at a time + while (count > 1) { + int nextTwoCharsBits = bits->readBits(11); + bytes[i++] = ALPHANUMERIC_CHARS[nextTwoCharsBits / 45]; + bytes[i++] = ALPHANUMERIC_CHARS[nextTwoCharsBits % 45]; + count -= 2; + } + if (count == 1) { + bytes[i++] = ALPHANUMERIC_CHARS[bits->readBits(6)]; + } + append(result, bytes, nBytes, ASCII); + delete[] bytes; +} + +const char * +DecodedBitStreamParser::guessEncoding(unsigned char *bytes, int length) { + // Does it start with the UTF-8 byte order mark? then guess it's UTF-8 + if (length > 3 && bytes[0] == (unsigned char)0xEF && bytes[1] == (unsigned char)0xBB && bytes[2] + == (unsigned char)0xBF) { + return UTF8; + } + // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, + // which should be by far the most common encodings. ISO-8859-1 + // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS + // uses this as a first byte of a two-byte character. If we see this + // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS. + // If we see something else in that second byte, we'll make the risky guess + // that it's UTF-8. + bool canBeISO88591 = true; + bool lastWasPossibleDoubleByteStart = false; + for (int i = 0; i < length; i++) { + int value = bytes[i] & 0xFF; + if (value >= 0x80 && value <= 0x9F && i < length - 1) { + canBeISO88591 = false; + // ISO-8859-1 shouldn't use this, but before we decide it is Shift_JIS, + // just double check that it is followed by a byte that's valid in + // the Shift_JIS encoding + if (lastWasPossibleDoubleByteStart) { + // If we just checked this and the last byte for being a valid double-byte + // char, don't check starting on this byte. If the this and the last byte + // formed a valid pair, then this shouldn't be checked to see if it starts + // a double byte pair of course. + lastWasPossibleDoubleByteStart = false; + } else { + // ... otherwise do check to see if this plus the next byte form a valid + // double byte pair encoding a character. + lastWasPossibleDoubleByteStart = true; + int nextValue = bytes[i + 1] & 0xFF; + if ((value & 0x1) == 0) { + // if even, next value should be in [0x9F,0xFC] + // if not, we'll guess UTF-8 + if (nextValue < 0x9F || nextValue > 0xFC) { + return UTF8; + } + } else { + // if odd, next value should be in [0x40,0x9E] + // if not, we'll guess UTF-8 + if (nextValue < 0x40 || nextValue > 0x9E) { + return UTF8; + } + } + } + } + } + return canBeISO88591 ? ISO88591 : SHIFT_JIS; +} + +string DecodedBitStreamParser::decode(ArrayRef bytes, Version *version) { + ostringstream result; + Ref bits(new BitSource(bytes)); + Mode *mode = &Mode::TERMINATOR; + do { + // While still another segment to read... + if (bits->available() < 4) { + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + mode = &Mode::TERMINATOR; + } else { + mode = &Mode::forBits(bits->readBits(4)); // mode is encoded by 4 bits + } + if (mode != &Mode::TERMINATOR) { + // How many characters will follow, encoded in this mode? + int count = bits->readBits(mode->getCharacterCountBits(version)); + if (mode == &Mode::NUMERIC) { + decodeNumericSegment(bits, result, count); + } else if (mode == &Mode::ALPHANUMERIC) { + decodeAlphanumericSegment(bits, result, count); + } else if (mode == &Mode::BYTE) { + decodeByteSegment(bits, result, count); + } else if (mode == &Mode::KANJI) { + decodeKanjiSegment(bits, result, count); + } else { + throw ReaderException("Unsupported mode indicator"); + } + } + } while (mode != &Mode::TERMINATOR); + return result.str(); +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h new file mode 100644 index 000000000..8c4ab9bb3 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/DecodedBitStreamParser.h @@ -0,0 +1,60 @@ +#ifndef __DECODED_BIT_STREAM_PARSER_H__ +#define __DECODED_BIT_STREAM_PARSER_H__ + +/* + * DecodedBitStreamParser.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + + + +namespace zxing { +namespace qrcode { + +class DecodedBitStreamParser { +private: + static const char ALPHANUMERIC_CHARS[]; + + static const char *ASCII; + static const char *ISO88591; + static const char *UTF8; + static const char *SHIFT_JIS; + static const char *EUC_JP; + + static void decodeKanjiSegment(Ref bits, std::ostringstream &result, int count); + static void decodeByteSegment(Ref bits, std::ostringstream &result, int count); + static void decodeAlphanumericSegment(Ref bits, std::ostringstream &result, int count); + static void decodeNumericSegment(Ref bits, std::ostringstream &result, int count); + static const char *guessEncoding(unsigned char *bytes, int length); + static void append(std::ostream &ost, const unsigned char *bufIn, size_t nIn, const char *src); + +public: + static std::string decode(ArrayRef bytes, Version *version); +}; + +} +} + +#endif // __DECODED_BIT_STREAM_PARSER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.cpp new file mode 100644 index 000000000..13023131d --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.cpp @@ -0,0 +1,103 @@ +/* + * Decoder.cpp + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +Decoder::Decoder() : + rsDecoder_(GF256::QR_CODE_FIELD) { +} + +void Decoder::correctErrors(ArrayRef codewordBytes, int numDataCodewords) { + int numCodewords = codewordBytes->size(); + ArrayRef codewordInts(numCodewords); + for (int i = 0; i < numCodewords; i++) { + codewordInts[i] = codewordBytes[i] & 0xff; + } + int numECCodewords = numCodewords - numDataCodewords; + + try { + rsDecoder_.decode(codewordInts, numECCodewords); + } catch (ReedSolomonException ex) { + ReaderException rex(ex.what()); + throw rex; + } + + for (int i = 0; i < numDataCodewords; i++) { + codewordBytes[i] = (unsigned char)codewordInts[i]; + } +} + +Ref Decoder::decode(Ref bits) { + // Construct a parser and read version, error-correction level + BitMatrixParser parser(bits); + + Version *version = parser.readVersion(); + ErrorCorrectionLevel &ecLevel = parser.readFormatInformation()->getErrorCorrectionLevel(); + + + // Read codewords + ArrayRef codewords(parser.readCodewords()); + + + // Separate into data blocks + std::vector > dataBlocks(DataBlock::getDataBlocks(codewords, version, ecLevel)); + + + // Count total number of data bytes + int totalBytes = 0; + for (size_t i = 0; i < dataBlocks.size(); i++) { + totalBytes += dataBlocks[i]->getNumDataCodewords(); + } + ArrayRef resultBytes(totalBytes); + int resultOffset = 0; + + + // Error-correct and copy data blocks together into a stream of bytes + for (size_t j = 0; j < dataBlocks.size(); j++) { + Ref dataBlock(dataBlocks[j]); + ArrayRef codewordBytes = dataBlock->getCodewords(); + int numDataCodewords = dataBlock->getNumDataCodewords(); + correctErrors(codewordBytes, numDataCodewords); + for (int i = 0; i < numDataCodewords; i++) { + resultBytes[resultOffset++] = codewordBytes[i]; + } + } + + // Decode the contents of that stream of bytes + Ref text(new String(DecodedBitStreamParser::decode(resultBytes, version))); + + Ref result(new DecoderResult(resultBytes, text)); + return result; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h new file mode 100644 index 000000000..96e1dc0cc --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Decoder.h @@ -0,0 +1,49 @@ +#ifndef __DECODER_H__ +#define __DECODER_H__ + +/* + * Decoder.h + * zxing + * + * Created by Christian Brunschen on 20/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class Decoder { +private: + ReedSolomonDecoder rsDecoder_; + + void correctErrors(ArrayRef bytes, int numDataCodewords); + +public: + Decoder(); + Ref decode(Ref bits); +}; + +} +} + +#endif // __DECODER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.cpp new file mode 100644 index 000000000..5a6eb4aa5 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.cpp @@ -0,0 +1,73 @@ +/* + * Mode.cpp + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { +using namespace std; + +Mode Mode::TERMINATOR(0, 0, 0); +Mode Mode::NUMERIC(10, 12, 14); +Mode Mode::ALPHANUMERIC(9, 11, 13); +Mode Mode::BYTE(8, 16, 16); +Mode Mode::KANJI(8, 10, 12); + +Mode::Mode(int cbv0_9, int cbv10_26, int cbv27) : + characterCountBitsForVersions0To9_(cbv0_9), characterCountBitsForVersions10To26_(cbv10_26), + characterCountBitsForVersions27AndHigher_(cbv27) { +} + +Mode& Mode::forBits(int bits) { + switch (bits) { + case 0x0: + return TERMINATOR; + case 0x1: + return NUMERIC; + case 0x2: + return ALPHANUMERIC; + case 0x4: + return BYTE; + case 0x8: + return KANJI; + default: + ostringstream s; + s << "Illegal mode bits: " << bits; + throw ReaderException(s.str().c_str()); + } +} + +int Mode::getCharacterCountBits(Version *version) { + int number = version->getVersionNumber(); + if (number <= 9) { + return characterCountBitsForVersions0To9_; + } else if (number <= 26) { + return characterCountBitsForVersions10To26_; + } else { + return characterCountBitsForVersions27AndHigher_; + } +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.h new file mode 100644 index 000000000..28708a94b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/decoder/Mode.h @@ -0,0 +1,51 @@ +#ifndef __MODE_H__ +#define __MODE_H__ + +/* + * Mode.h + * zxing + * + * Created by Christian Brunschen on 19/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { +namespace qrcode { + +class Mode { +private: + int characterCountBitsForVersions0To9_; + int characterCountBitsForVersions10To26_; + int characterCountBitsForVersions27AndHigher_; + + Mode(int cbv0_9, int cbv10_26, int cbv27); + +public: + static Mode TERMINATOR; + static Mode NUMERIC; + static Mode ALPHANUMERIC; + static Mode BYTE; + static Mode KANJI; + + static Mode& forBits(int bits); + int getCharacterCountBits(Version *version); +}; +} +} + +#endif // __MODE_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp new file mode 100644 index 000000000..0f6ee592b --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.cpp @@ -0,0 +1,46 @@ +/* + * AlignmentPattern.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) : + posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize) { +} + +float AlignmentPattern::getX() { + return posX_; +} + +float AlignmentPattern::getY() { + return posY_; +} + +bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) { + return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_) + <= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f); +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h new file mode 100644 index 000000000..56a683f95 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPattern.h @@ -0,0 +1,46 @@ +#ifndef __ALIGNMENT_PATTERN_H__ +#define __ALIGNMENT_PATTERN_H__ + +/* + * AlignmentPattern.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class AlignmentPattern : public ResultPoint { + private: + float posX_; + float posY_; + float estimatedModuleSize_; + + public: + AlignmentPattern(float posX, float posY, float estimatedModuleSize); + float getX(); + float getY(); + bool aboutEquals(float moduleSize, float i, float j); + }; + + } +} + +#endif // __ALIGNMENT_PATTERN_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp new file mode 100644 index 000000000..b3d92d40c --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.cpp @@ -0,0 +1,204 @@ +/* + * AlignmentPatternFinder.cpp + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AlignmentPatternFinder.h" +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +float AlignmentPatternFinder::centerFromEnd(valarray &stateCount, int end) { + return (float)(end - stateCount[2]) - stateCount[1] / 2.0f; +} + +bool AlignmentPatternFinder::foundPatternCross(valarray &stateCount) { + float maxVariance = moduleSize_ / 2.0f; + for (size_t i = 0; i < 3; i++) { + if (abs(moduleSize_ - stateCount[i]) >= maxVariance) { + return false; + } + } + return true; +} + +float AlignmentPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, + int originalStateCountTotal) { + int maxI = image_->getHeight(); + valarray stateCount(0, 3); + + + // Start counting up from center + int i = startI; + while (i >= 0 && image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (i >= 0 && !image_->get(centerJ, i) && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i++; + } + if (i == maxI || stateCount[1] > maxCount) { + return NAN; + } + while (i < maxI && !image_->get(centerJ, i) && stateCount[2] <= maxCount) { + stateCount[2]++; + i++; + } + if (stateCount[2] > maxCount) { + return NAN; + } + + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN; +} + +Ref AlignmentPatternFinder::handlePossibleCenter(valarray &stateCount, size_t i, size_t j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (int)centerJ, 2 * stateCount[1], stateCountTotal); + if (!isnan(centerI)) { + float estimatedModuleSize = (float)(stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; + int max = possibleCenters_->size(); + for (int index = 0; index < max; index++) { + Ref center((*possibleCenters_)[index]); + // Look for about the same center and module size: + if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) { + Ref result(new AlignmentPattern(centerJ, centerI, estimatedModuleSize)); + return result; + } + } + AlignmentPattern *tmp = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); + // Hadn't found this before; save it + tmp->retain(); + possibleCenters_->push_back(tmp); + } + Ref result; + return result; +} + +AlignmentPatternFinder::AlignmentPatternFinder(Ref image, size_t startX, size_t startY, size_t width, + size_t height, float moduleSize) : + image_(image), possibleCenters_(new vector ()), startX_(startX), startY_(startY), + width_(width), height_(height), moduleSize_(moduleSize) { +} + +AlignmentPatternFinder::~AlignmentPatternFinder() { + for (size_t i = 0; i < possibleCenters_->size(); i++) { + (*possibleCenters_)[i]->release(); + (*possibleCenters_)[i] = 0; + } + delete possibleCenters_; +} + +Ref AlignmentPatternFinder::find() { + size_t maxJ = startX_ + width_; + size_t middleI = startY_ + (height_ >> 1); + // Ref luminanceRow(new BitArray(width_)); + // We are looking for black/white/black modules in 1:1:1 ratio; + // this tracks the number of black/white/black modules seen so far + valarray stateCount(0, 3); + for (size_t iGen = 0; iGen < height_; iGen++) { + // Search from middle outwards + size_t i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1)); + // image_->getBlackRow(i, luminanceRow, startX_, width_); + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + size_t j = startX_; + // Burn off leading white pixels before anything else; if we start in the middle of + // a white run, it doesn't make sense to count its length, since we don't know if the + // white run continued to the left of the start point + while (j < maxJ && !image_->get(j, i)) { + j++; + } + int currentState = 0; + while (j < maxJ) { + if (image_->get(j, i)) { + // Black pixel + if (currentState == 1) { // Counting black pixels + stateCount[currentState]++; + } else { // Counting white pixels + if (currentState == 2) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + Ref confirmed(handlePossibleCenter(stateCount, i, j)); + if (confirmed != 0) { + return confirmed; + } + } + stateCount[0] = stateCount[2]; + stateCount[1] = 1; + stateCount[2] = 0; + currentState = 1; + } else { + stateCount[++currentState]++; + } + } + } else { // White pixel + if (currentState == 1) { // Counting black pixels + currentState++; + } + stateCount[currentState]++; + } + j++; + } + if (foundPatternCross(stateCount)) { + Ref confirmed(handlePossibleCenter(stateCount, i, maxJ)); + if (confirmed != 0) { + return confirmed; + } + } + + } + + // Hmm, nothing we saw was observed and confirmed twice. If we had + // any guess at all, return it. + if (possibleCenters_->size() > 0) { + Ref center((*possibleCenters_)[0]); + return center; + } + + throw zxing::ReaderException("Could not find alignment pattern"); +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h new file mode 100644 index 000000000..266364316 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/AlignmentPatternFinder.h @@ -0,0 +1,62 @@ +#ifndef __ALIGNMENT_PATTERN_FINDER_H__ +#define __ALIGNMENT_PATTERN_FINDER_H__ + +/* + * AlignmentPatternFinder.h + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AlignmentPattern.h" +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class AlignmentPatternFinder : public Counted { +private: + static int CENTER_QUORUM; + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector *possibleCenters_; + size_t startX_; + size_t startY_; + size_t width_; + size_t height_; + float moduleSize_; + + static float centerFromEnd(std::valarray &stateCount, int end); + bool foundPatternCross(std::valarray &stateCount); + + float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); + + Ref handlePossibleCenter(std::valarray &stateCount, size_t i, size_t j); + +public: + AlignmentPatternFinder(Ref image, size_t startX, size_t startY, size_t width, size_t height, + float moduleSize); + ~AlignmentPatternFinder(); + Ref find(); +}; +} +} + +#endif // __ALIGNMENT_PATTERN_FINDER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp new file mode 100644 index 000000000..9dbc29754 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.cpp @@ -0,0 +1,265 @@ +/* + * Detector.cpp + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +Detector::Detector(Ref image) : + image_(image) { +} + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect() { + FinderPatternFinder finder(image_); + Ref info(finder.find()); + + Ref topLeft(info->getTopLeft()); + Ref topRight(info->getTopRight()); + Ref bottomLeft(info->getBottomLeft()); + + float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); + int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); + Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension); + int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7; + + Ref alignmentPattern; + // Anything above version 1 has an alignment pattern + if (provisionalVersion->getAlignmentPatternCenters().size() > 0) { + + + // Guess where a "bottom right" finder pattern would have been + float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX(); + float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY(); + + + // Estimate that alignment pattern is closer by 3 modules + // from "bottom right" to known top left location + float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; + int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX())); + int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY())); + + + // Kind of arbitrary -- expand search radius before giving up + for (int i = 4; i <= 16; i <<= 1) { + try { + alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); + break; + } catch (zxing::ReaderException re) { + // try next round + } + } + if (alignmentPattern == 0) { + // Try anyway + } + + } + + Ref transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + Ref bits(sampleGrid(image_, dimension, transform)); + std::vector > points(alignmentPattern == 0 ? 3 : 4); + points[0].reset(bottomLeft); + points[1].reset(topLeft); + points[2].reset(topRight); + if (alignmentPattern != 0) { + points[3].reset(alignmentPattern); + } + + Ref result(new DetectorResult(bits, points, transform)); + return result; +} + +Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + float dimMinusThree = (float)dimension - 3.5f; + float bottomRightX; + float bottomRightY; + float sourceBottomRightX; + float sourceBottomRightY; + if (alignmentPattern != 0) { + bottomRightX = alignmentPattern->getX(); + bottomRightY = alignmentPattern->getY(); + sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; + } else { + // Don't have an alignment pattern, just make up the bottom-right point + bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX(); + bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY(); + sourceBottomRightX = sourceBottomRightY = dimMinusThree; + } + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, + sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(), + topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY())); + + return transform; +} + +Ref Detector::sampleGrid(Ref image, int dimension, Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimension, transform); +} + +int Detector::computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize) { + int tltrCentersDimension = lround(FinderPatternFinder::distance(topLeft, topRight) / moduleSize); + int tlblCentersDimension = lround(FinderPatternFinder::distance(topLeft, bottomLeft) / moduleSize); + int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; + switch (dimension & 0x03) { // mod 4 + case 0: + dimension++; + break; + // 1? do nothing + case 2: + dimension--; + break; + case 3: + ostringstream s; + s << "Bad dimension: " << dimension; + throw zxing::ReaderException(s.str().c_str()); + } + return dimension; +} + +float Detector::calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft) { + // Take the average + return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; +} + +float Detector::calculateModuleSizeOneWay(Ref pattern, Ref otherPattern) { + float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(), + (int)otherPattern->getX(), (int)otherPattern->getY()); + float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(), + (int)pattern->getX(), (int)pattern->getY()); + if (isnan(moduleSizeEst1)) { + return moduleSizeEst2; + } + if (isnan(moduleSizeEst2)) { + return moduleSizeEst1; + } + // Average them, and divide by 7 since we've counted the width of 3 black modules, + // and 1 white and 1 black module on either side. Ergo, divide sum by 14. + return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; +} + +float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) { + + float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); + + + // Now count other way -- don't run off image though of course + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { + // "to" should the be the first value not included, so, the first value off + // the edge is -1 + otherToX = -1; + } else if (otherToX >= (int)image_->getWidth()) { + otherToX = image_->getWidth(); + } + int otherToY = fromY - (toY - fromY); + if (otherToY < 0) { + otherToY = -1; + } else if (otherToY >= (int)image_->getHeight()) { + otherToY = image_->getHeight(); + } + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + return result - 1.0f; // -1 because we counted the middle pixel twice +} + +float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) { + // Mild variant of Bresenham's algorithm; + // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? 1 : -1; + int xstep = fromX < toX ? 1 : -1; + int state = 0; // In black pixels, looking for white, first or second time + for (int x = fromX, y = fromY; x != toX; x += xstep) { + + int realX = steep ? y : x; + int realY = steep ? x : y; + if (state == 1) { // In white pixels, looking for black + if (image_->get(realX, realY)) { + state++; + } + } else { + if (!image_->get(realX, realY)) { + state++; + } + } + + if (state == 3) { // Found black, white, black, and stumbled back onto white; done + int diffX = x - fromX; + int diffY = y - fromY; + return (float)sqrt((double)(diffX * diffX + diffY * diffY)); + } + error += dy; + if (error > 0) { + y += ystep; + error -= dx; + } + } + int diffX = toX - fromX; + int diffY = toY - fromY; + return (float)sqrt((double)(diffX * diffX + diffY * diffY)); +} + +Ref Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor) { + // Look for an alignment pattern (3 modules in size) around where it + // should be + int allowance = (int)(allowanceFactor * overallEstModuleSize); + int alignmentAreaLeftX = max(0, estAlignmentX - allowance); + int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance); + int alignmentAreaTopY = max(0, estAlignmentY - allowance); + int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); + + AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX + - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize); + return alignmentFinder.find(); +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.h new file mode 100644 index 000000000..98eed51e9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/Detector.h @@ -0,0 +1,60 @@ +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class Detector : public Counted { +private: + Ref image_; + +protected: + Ref getImage(); + + static Ref sampleGrid(Ref image, int dimension, Ref); + static int computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize); + float calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft); + float calculateModuleSizeOneWay(Ref pattern, Ref otherPattern); + float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY); + float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); + Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor); +public: + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + + Detector(Ref image); + Ref detect(); +}; +} +} + +#endif // __DETECTOR_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp new file mode 100644 index 000000000..531d4e2a1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.cpp @@ -0,0 +1,58 @@ +/* + * FinderPattern.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { + namespace qrcode { + + using namespace std; + + FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) : + posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), counter_(1) { + } + + float FinderPattern::getX() { + return posX_; + } + + float FinderPattern::getY() { + return posY_; + } + + int FinderPattern::getCount() { + return counter_; + } + + float FinderPattern::getEstimatedModuleSize() { + return estimatedModuleSize_; + } + + void FinderPattern::incrementCount() { + counter_++; + } + + bool FinderPattern::aboutEquals(float moduleSize, float i, float j) { + return abs(i - posY_) <= moduleSize && abs(j - posX_) <= moduleSize && (abs(moduleSize - estimatedModuleSize_) + <= 1.0f || abs(moduleSize - estimatedModuleSize_) / estimatedModuleSize_ <= 0.1f); + } + + } +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h new file mode 100644 index 000000000..0b6615c81 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPattern.h @@ -0,0 +1,49 @@ +#ifndef __FINDER_PATTERN_H__ +#define __FINDER_PATTERN_H__ + +/* + * FinderPattern.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace zxing { + namespace qrcode { + + class FinderPattern : public ResultPoint { + private: + float posX_; + float posY_; + float estimatedModuleSize_; + int counter_; + + public: + FinderPattern(float posX, float posY, float estimatedModuleSize); + float getX(); + float getY(); + int getCount(); + float getEstimatedModuleSize(); + void incrementCount(); + bool aboutEquals(float moduleSize, float i, float j); + }; + } +} + +#endif // __FINDER_PATTERN_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp new file mode 100644 index 000000000..666c4f210 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.cpp @@ -0,0 +1,501 @@ +/* + * FinderPatternFinder.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +using namespace std; + +class ClosestToAverageComparator { +private: + float averageModuleSize_; +public: + ClosestToAverageComparator(float averageModuleSize) : + averageModuleSize_(averageModuleSize) { + } + int operator()(Ref a, Ref b) { + float dA = abs(a->getEstimatedModuleSize() - averageModuleSize_); + float dB = abs(b->getEstimatedModuleSize() - averageModuleSize_); + return dA < dB ? -1 : dA > dB ? 1 : 0; + } +}; + +class CenterComparator { +public: + int operator()(Ref a, Ref b) { + return b->getCount() - a->getCount(); + } +}; + +int FinderPatternFinder::CENTER_QUORUM = 2; +int FinderPatternFinder::MIN_SKIP = 3; +int FinderPatternFinder::MAX_MODULES = 57; + +float FinderPatternFinder::centerFromEnd(int* stateCount, int end) { + return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; +} + +bool FinderPatternFinder::foundPatternCross(int* stateCount) { + int totalModuleSize = 0; + for (int i = 0; i < 5; i++) { + if (stateCount[i] == 0) { + return false; + } + totalModuleSize += stateCount[i]; + } + if (totalModuleSize < 7) { + return false; + } + float moduleSize = (float)totalModuleSize / 7.0f; + float maxVariance = moduleSize / 2.0f; + // Allow less than 50% variance from 1-1-3-1-1 proportions + return abs(moduleSize - stateCount[0]) < maxVariance && abs(moduleSize - stateCount[1]) < maxVariance && abs(3.0f + * moduleSize - stateCount[2]) < 3.0f * maxVariance && abs(moduleSize - stateCount[3]) < maxVariance && abs( + moduleSize - stateCount[4]) < maxVariance; +} + +float FinderPatternFinder::crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal) { + + int maxI = image_->getHeight(); + int stateCount[5]; + for (int i = 0; i < 5; i++) + stateCount[i] = 0; + + + // Start counting up from center + int i = startI; + while (i >= 0 && image_->get(centerJ, i)) { + stateCount[2]++; + i--; + } + if (i < 0) { + return NAN; + } + while (i >= 0 && !image_->get(centerJ, i) && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + // If already too many modules in this state or ran off the edge: + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (i >= 0 && image_->get(centerJ, i) && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + // Now also count down from center + i = startI + 1; + while (i < maxI && image_->get(centerJ, i)) { + stateCount[2]++; + i++; + } + if (i == maxI) { + return NAN; + } + while (i < maxI && !image_->get(centerJ, i) && stateCount[3] < maxCount) { + stateCount[3]++; + i++; + } + if (i == maxI || stateCount[3] >= maxCount) { + return NAN; + } + while (i < maxI && image_->get(centerJ, i) && stateCount[4] < maxCount) { + stateCount[4]++; + i++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is more than 40% different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : NAN; +} + +float FinderPatternFinder::crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, + int originalStateCountTotal) { + + int maxJ = image_->getWidth(); + int stateCount[5]; + for (int i = 0; i < 5; i++) + stateCount[i] = 0; + + int j = startJ; + while (j >= 0 && image_->get(j, centerI)) { + stateCount[2]++; + j--; + } + if (j < 0) { + return NAN; + } + while (j >= 0 && !image_->get(j, centerI) && stateCount[1] <= maxCount) { + stateCount[1]++; + j--; + } + if (j < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (j >= 0 && image_->get(j, centerI) && stateCount[0] <= maxCount) { + stateCount[0]++; + j--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + j = startJ + 1; + while (j < maxJ && image_->get(j, centerI)) { + stateCount[2]++; + j++; + } + if (j == maxJ) { + return NAN; + } + while (j < maxJ && !image_->get(j, centerI) && stateCount[3] < maxCount) { + stateCount[3]++; + j++; + } + if (j == maxJ || stateCount[3] >= maxCount) { + return NAN; + } + while (j < maxJ && image_->get(j, centerI) && stateCount[4] < maxCount) { + stateCount[4]++; + j++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + // If we found a finder-pattern-like section, but its size is significantly different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return NAN; + } + + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : NAN; +} + +bool FinderPatternFinder::handlePossibleCenter(int* stateCount, size_t i, size_t j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + float centerJ = centerFromEnd(stateCount, j); + float centerI = crossCheckVertical(i, (size_t)centerJ, stateCount[2], stateCountTotal); + if (!isnan(centerI)) { + // Re-cross check + centerJ = crossCheckHorizontal((size_t)centerJ, (size_t)centerI, stateCount[2], stateCountTotal); + if (!isnan(centerJ)) { + float estimatedModuleSize = (float)stateCountTotal / 7.0f; + bool found = false; + size_t max = possibleCenters_.size(); + for (size_t index = 0; index < max; index++) { + Ref center = possibleCenters_[index]; + // Look for about the same center and module size: + if (center->aboutEquals(estimatedModuleSize, centerI, centerJ)) { + center->incrementCount(); + found = true; + break; + } + } + if (!found) { + Ref newPattern(new FinderPattern(centerJ, centerI, estimatedModuleSize)); + possibleCenters_.push_back(newPattern); + } + return true; + } + } + return false; +} + +int FinderPatternFinder::findRowSkip() { + size_t max = possibleCenters_.size(); + if (max <= 1) { + return 0; + } + Ref firstConfirmedCenter; + for (size_t i = 0; i < max; i++) { + Ref center = possibleCenters_[i]; + if (center->getCount() >= CENTER_QUORUM) { + if (firstConfirmedCenter == 0) { + firstConfirmedCenter = center; + } else { + // We have two confirmed centers + // How far down can we skip before resuming looking for the next + // pattern? In the worst case, only the difference between the + // difference in the x / y coordinates of the two centers. + // This is the case where you find top left first. Draw it out. + hasSkipped_ = true; + return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY() + - center->getY())); + } + } + } + return 0; +} + +bool FinderPatternFinder::haveMultiplyConfirmedCenters() { + int confirmedCount = 0; + float totalModuleSize = 0.0f; + size_t max = possibleCenters_.size(); + for (size_t i = 0; i < max; i++) { + Ref pattern = possibleCenters_[i]; + if (pattern->getCount() >= CENTER_QUORUM) { + confirmedCount++; + totalModuleSize += pattern->getEstimatedModuleSize(); + } + } + if (confirmedCount < 3) { + return false; + } + // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" + // and that we need to keep looking. We detect this by asking if the estimated module sizes + // vary too much. We arbitrarily say that when the total deviation from average exceeds + // 15% of the total module size estimates, it's too much. + float average = totalModuleSize / max; + float totalDeviation = 0.0f; + for (size_t i = 0; i < max; i++) { + Ref pattern = possibleCenters_[i]; + totalDeviation += abs(pattern->getEstimatedModuleSize() - average); + } + return totalDeviation <= 0.15f * totalModuleSize; +} + +vector > FinderPatternFinder::selectBestPatterns() { + sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator()); + size_t size = 0; + size_t max = possibleCenters_.size(); + while (size < max) { + if (possibleCenters_[size]->getCount() < CENTER_QUORUM) { + break; + } + size++; + } + + if (size < 3) { + // Couldn't find enough finder patterns + throw zxing::ReaderException("Could not find three finder patterns"); + } + + if (size == 3) { + // Found just enough -- hope these are good! + vector > result(3); + result[0] = possibleCenters_[0]; + result[1] = possibleCenters_[1]; + result[2] = possibleCenters_[2]; + return result; + } + + // Hmm, multiple found. We need to pick the best three. Find the most + // popular ones whose module size is nearest the average + // This does not work for multiple qr codes in the same image + float averageModuleSize = 0.0f; + for (size_t i = 0; i < size; i++) { + averageModuleSize += possibleCenters_[i]->getEstimatedModuleSize(); + } + averageModuleSize /= (float)size; + + sort(possibleCenters_.begin(), possibleCenters_.end(), ClosestToAverageComparator(averageModuleSize)); + + vector > result(3); + result[0] = possibleCenters_[0]; + result[1] = possibleCenters_[1]; + result[2] = possibleCenters_[2]; + return result; +} + +vector > FinderPatternFinder::orderBestPatterns(vector > patterns) { + // Find distances between pattern centers + float abDistance = distance(patterns[0], patterns[1]); + float bcDistance = distance(patterns[1], patterns[2]); + float acDistance = distance(patterns[0], patterns[2]); + + Ref topLeft; + Ref topRight; + Ref bottomLeft; + // Assume one closest to other two is top left; + // topRight and bottomLeft will just be guesses below at first + if (bcDistance >= abDistance && bcDistance >= acDistance) { + topLeft = patterns[0]; + topRight = patterns[1]; + bottomLeft = patterns[2]; + } else if (acDistance >= bcDistance && acDistance >= abDistance) { + topLeft = patterns[1]; + topRight = patterns[0]; + bottomLeft = patterns[2]; + } else { + topLeft = patterns[2]; + topRight = patterns[0]; + bottomLeft = patterns[1]; + } + + // Use cross product to figure out which of other1/2 is the bottom left + // pattern. The vector "top-left -> bottom-left" x "top-left -> top-right" + // should yield a vector with positive z component + if ((bottomLeft->getY() - topLeft->getY()) * (topRight->getX() - topLeft->getX()) < (bottomLeft->getX() + - topLeft->getX()) * (topRight->getY() - topLeft->getY())) { + Ref temp = topRight; + topRight = bottomLeft; + bottomLeft = temp; + } + + vector > results(3); + results[0] = bottomLeft; + results[1] = topLeft; + results[2] = topRight; + return results; +} + +float FinderPatternFinder::distance(Ref p1, Ref p2) { + float dx = p1->getX() - p2->getX(); + float dy = p1->getY() - p2->getY(); + return (float)sqrt(dx * dx + dy * dy); +} + +FinderPatternFinder::FinderPatternFinder(Ref image) : + image_(image), possibleCenters_(), hasSkipped_(false) { +} + +Ref FinderPatternFinder::find() { + size_t maxI = image_->getHeight(); + size_t maxJ = image_->getWidth(); + + + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // As this is used often, we use an integer array instead of valarray + int stateCount[5]; + bool done = false; + + + // Let's assume that the maximum version QR Code we support takes up 1/4 + // the height of the image, and then account for the center being 3 + // modules in size. This gives the smallest number of pixels the center + // could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + size_t iSkip = MIN_SKIP; + + // This is slightly faster than using the Ref. Efficiency is important here + BitMatrix& matrix = *image_; + + for (size_t i = iSkip - 1; i < maxI && !done; i += iSkip) { + // Get a row of black/white values + + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (size_t j = 0; j < maxJ; j++) { + if (matrix.get(j, i)) { + // Black pixel + if ((currentState & 1) == 1) { // Counting white pixels + currentState++; + } + stateCount[currentState]++; + } else { // White pixel + if ((currentState & 1) == 0) { // Counting black pixels + if (currentState == 4) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + bool confirmed = handlePossibleCenter(stateCount, i, j); + if (confirmed) { + iSkip = 1; // Go back to examining each line + if (hasSkipped_) { + done = haveMultiplyConfirmedCenters(); + } else { + int rowSkip = findRowSkip(); + if (rowSkip > stateCount[2]) { + // Skip rows between row of lower confirmed center + // and top of presumed third confirmed center + // but back up a bit to get a full chance of detecting + // it, entire width of center of finder pattern + + // Skip by rowSkip, but back off by stateCount[2] (size + // of last center of pattern we saw) to be conservative, + // and also back off by iSkip which is about to be + // re-added + i += rowSkip - stateCount[2] - iSkip; + j = maxJ - 1; + } + } + } else { + // Advance to next black pixel + do { + j++; + } while (j < maxJ && !image_->get(j, i)); + j--; // back up to that last white pixel + } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { // No, shift counts back by two + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { // Counting white pixels + stateCount[currentState]++; + } + } + } + if (foundPatternCross(stateCount)) { + bool confirmed = handlePossibleCenter(stateCount, i, maxJ); + if (confirmed) { + iSkip = stateCount[0]; + if (hasSkipped_) { + // Found a third one + done = haveMultiplyConfirmedCenters(); + } + } + } + } + + vector > patternInfo = selectBestPatterns(); + patternInfo = orderBestPatterns(patternInfo); + + Ref result(new FinderPatternInfo(patternInfo)); + return result; +} +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.h new file mode 100644 index 000000000..e1fc9ce7f --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternFinder.h @@ -0,0 +1,65 @@ +#ifndef __FINDER_PATTERN_FINDER_H__ +#define __FINDER_PATTERN_FINDER_H__ + +/* + * FinderPatternFinder.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class FinderPatternFinder { +private: + static int CENTER_QUORUM; + static int MIN_SKIP; + static int MAX_MODULES; + + Ref image_; + std::vector > possibleCenters_; + bool hasSkipped_; + + /** stateCount must be int[5] */ + static float centerFromEnd(int* stateCount, int end); + static bool foundPatternCross(int* stateCount); + + float crossCheckVertical(size_t startI, size_t centerJ, int maxCount, int originalStateCountTotal); + float crossCheckHorizontal(size_t startJ, size_t centerI, int maxCount, int originalStateCountTotal); + + /** stateCount must be int[5] */ + bool handlePossibleCenter(int* stateCount, size_t i, size_t j); + int findRowSkip(); + bool haveMultiplyConfirmedCenters(); + std::vector > selectBestPatterns(); + static std::vector > orderBestPatterns(std::vector > patterns); + +public: + static float distance(Ref p1, Ref p2); + FinderPatternFinder(Ref image); + Ref find(); +}; +} +} + +#endif // __FINDER_PATTERN_FINDER_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.cpp new file mode 100644 index 000000000..088a0e760 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.cpp @@ -0,0 +1,41 @@ +/* + * FinderPatternInfo.cpp + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace zxing { +namespace qrcode { + +FinderPatternInfo::FinderPatternInfo(std::vector > patternCenters) : + bottomLeft_(patternCenters[0]), topLeft_(patternCenters[1]), topRight_(patternCenters[2]) { +} + +Ref FinderPatternInfo::getBottomLeft() { + return bottomLeft_; +} +Ref FinderPatternInfo::getTopLeft() { + return topLeft_; +} +Ref FinderPatternInfo::getTopRight() { + return topRight_; +} + +} +} diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.h new file mode 100644 index 000000000..287a8d17d --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/FinderPatternInfo.h @@ -0,0 +1,48 @@ +#ifndef __FINDER_PATTERN_INFO_H__ +#define __FINDER_PATTERN_INFO_H__ + +/* + * FinderPatternInfo.h + * zxing + * + * Created by Christian Brunschen on 13/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +namespace zxing { +namespace qrcode { + +class FinderPatternInfo : public Counted { +private: + Ref bottomLeft_; + Ref topLeft_; + Ref topRight_; + +public: + FinderPatternInfo(std::vector > patternCenters); + + Ref getBottomLeft(); + Ref getTopLeft(); + Ref getTopRight(); +}; +} +} + +#endif // __FINDER_PATTERN_INFO_H__ diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp new file mode 100644 index 000000000..18affe6e1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.cpp @@ -0,0 +1,168 @@ +/* + * QREdgeDetector.cpp + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +using namespace std; + +namespace zxing { +namespace qrcode { + +static const float patternEdgeThreshold = 2; +static const int patternEdgeWidth = 3; +static const float patternEdgeSearchRatio = 1.1; +static const int patternEdgeSkip = 2; + +static const float accurateEdgeThreshold = 3.3; +static const int accurateEdgeWidth = 7; +static const int accurateEdgeSkip = 2; + +static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) { + return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y); +} + +static Point rp(Ref rp) { + return Point(rp->getX(), rp->getY()); +} + +QREdgeDetector::QREdgeDetector(Ref image) : Detector(image) { } + +Ref QREdgeDetector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + if(alignmentPattern == NULL) { + Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension); + return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension); + } else { + return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + } +} + + + + +Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) { + Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft); + + Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false); + Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true); + + //return EdgeDetector::intersection(bottomEst, rightEst); + + Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + + + return EdgeDetector::intersection(bottom, right); +} + +Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) { + Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite); + + float dx = pattern.x - start.x; + float dy = pattern.y - start.y; + float dist = sqrt(dx*dx + dy*dy); + + float dirX = direction.x - pattern.x; + float dirY = direction.y - pattern.y; + float dirSize = sqrt(dirX*dirX + dirY*dirY); + + float nx = dirX/dirSize; + float ny = dirY/dirSize; + + float search = dist * patternEdgeSearchRatio; + Point a(start.x + nx*search, start.y + ny*search); + Point b(start.x - nx*search, start.y - ny*search); + + return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip); +} + + +Ref QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) { + float dimMinusThree = (float) dimension - 3.5f; + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension, + dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x, + topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y)); + + return transform; +} + +// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector +Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) { + int fromX = (int)from.x; + int fromY = (int)from.y; + int toX = (int)to.x; + int toY = (int)to.y; + + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? -1 : 1; + int xstep = fromX < toX ? -1 : 1; + int state = 0; // In black pixels, looking for white, first or second time + + // In case there are no points, prepopulate to from + int realX = fromX; + int realY = fromY; + for (int x = fromX, y = fromY; x != toX; x += xstep) { + realX = steep ? y : x; + realY = steep ? x : y; + + if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight()) + break; + + if (state == 1) { // In white pixels, looking for black + if (image.get(realX, realY)) { + state++; + } + } else { + if (!image.get(realX, realY)) { + state++; + } + } + + if (state == 3) { // Found black, white, black, and stumbled back onto white; done + return Point(realX, realY); + } + error += dy; + if (error > 0) { + y += ystep; + error -= dx; + } + } + + // B-W-B run not found, return the last point visited. + return Point(realX, realY); +} + +} // namespace qrcode +} // namespace zxing diff --git a/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.h b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.h new file mode 100644 index 000000000..f5cdc89e3 --- /dev/null +++ b/symbian/ZXingBarcodeReader/group/zxing/qrcode/detector/QREdgeDetector.h @@ -0,0 +1,48 @@ +/* + * QREdgeDetector.h + * zxing + * + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef QREDGEDETECTOR_H_ +#define QREDGEDETECTOR_H_ + +#include +#include + +namespace zxing { +namespace qrcode { + +class QREdgeDetector : public Detector { +public: + QREdgeDetector(Ref image); + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + +private: + Point findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension); + Line findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert); + + Point endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to); + + Ref get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension); +}; + +} +} +#endif // QREDGEDETECTOR_H_ diff --git a/symbian/ZXingBarcodeReader/inc/CameraImage.h b/symbian/ZXingBarcodeReader/inc/CameraImage.h new file mode 100644 index 000000000..a91950407 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraImage.h @@ -0,0 +1,31 @@ +#ifndef CAMERAIMAGE_H +#define CAMERAIMAGE_H + +#include +#include +#include + +using namespace zxing; +using namespace std; + +class CameraImage : public LuminanceSource +{ +public: + CameraImage(); + CameraImage(CameraImage& otherInstance); + ~CameraImage(); + + int getWidth(); + int getHeight(); + + unsigned char getPixel(int x, int y); + + void setImage(CFbsBitmap* newImage); + + CFbsBitmap* getImage(); + +private: + CFbsBitmap* image; +}; + +#endif //CAMERAIMAGE_H diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.hrh b/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.hrh new file mode 100644 index 000000000..806b0cce1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.hrh @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLE_HRH__ +#define __CAMERAWRAPPEREXAMPLE_HRH__ + +#define _UID3 0xEF24C10A + +// CameraWrapperExample enumerate command codes +enum TCameraWrapperExampleIds + { + ECommand1 = 0x6001, // start value must not be 0 + ECommand2, + EHelp, + EAbout + }; + +#endif // __CAMERAWRAPPEREXAMPLE_HRH__ diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.pan b/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.pan new file mode 100644 index 000000000..052c69166 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExample.pan @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLE_PAN__ +#define __CAMERAWRAPPEREXAMPLE_PAN__ + +enum TCameraWrapperExamplePanics + { + ECameraWrapperExampleUi = 1 + // add further panics here + }; + +inline void Panic (TCameraWrapperExamplePanics aReason ) + { + _LIT (applicationName, "ZXingBarcodeReader" ); + User::Panic (applicationName, aReason ); + } + +#endif // __CAMERAWRAPPEREXAMPLE_PAN__ diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppUi.h b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppUi.h new file mode 100644 index 000000000..1efab6724 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppUi.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLEAPPUI_h__ +#define __CAMERAWRAPPEREXAMPLEAPPUI_h__ + +// INCLUDES +#include + +//#define EKeyZoomIn EKeyApplicationC +//#define EKeyZoomOut EKeyApplicationD +//#define EKeyVolumeUp EKeyIncVolume +//#define EKeyVolumeDown EKeyDecVolume + + +#ifdef ENABLE_CAMERA_SHUTTER +// Focus key events (shutter key pressed half-way down) +const TInt KStdKeyCameraFocus = 0xe2; +const TInt KStdKeyCameraFocus2 = 0xeb; // S60 3.2 and onwards + +// All known event codes used for the camera shutter key on S60 3.x devices +const TUint KKeyCameraShutter1 = 0xf883; +const TUint KKeyCameraShutter2 = 0xf849; // S60 3.2 +const TUint KKeyCameraNseries1 = 0xf881; // S60 3.2 Nseries +const TUint KKeyCameraNseries2 = 0xf88c; + +const TUint KCameraShutterKeyEventCodes[6] = { + EKeyCamera, // general camera key + KKeyCameraShutter1, + KKeyCameraShutter2, + KKeyCameraNseries1, + KKeyCameraNseries2, + 0 }; +#endif + + +// FORWARD DECLARATIONS +class CCameraWrapperExampleAppView; + +// CLASS DECLARATION +class CCameraWrapperExampleAppUi : public CAknAppUi, + public MCoeForegroundObserver + { + public: + // Constructors and destructor + void ConstructL (); + CCameraWrapperExampleAppUi (); + virtual ~CCameraWrapperExampleAppUi (); + + private: + TKeyResponse HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); + void HandleCommandL (TInt aCommand ); + void HandleResourceChangeL(TInt aType); + + #ifdef ENABLE_CAMERA_SHUTTER + void CaptureCameraShutter(TBool aEnable); + #endif + + public: + void UseOptionsExitCbaL(); + void UseOptionsBackCbaL(); + TBool IsBackCBA(); + + private: // From MCoeForegroundObserver + void HandleGainingForeground(); + void HandleLosingForeground(); + + private: + // Data + CCameraWrapperExampleAppView* iAppView; + RArray iShutterKeyHandles; + TBool iCameraKeyCaptured; + + }; + +#endif // __CAMERAWRAPPEREXAMPLEAPPUI_h__ + +// End of File diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppView.h b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppView.h new file mode 100644 index 000000000..be7f36455 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleAppView.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLEAPPVIEW_h__ +#define __CAMERAWRAPPEREXAMPLEAPPVIEW_h__ + +// INCLUDES +#include +#include + +#include +#include +#include +#include +#include + +class CCameraWrapperExampleAppUi; + +// CLASS DECLARATION +class CCameraWrapperExampleAppView : +public CCoeControl, public MCameraEngineObserver + { + public: + // Constructors + static CCameraWrapperExampleAppView* NewL (const TRect& aRect ); + static CCameraWrapperExampleAppView* NewLC (const TRect& aRect ); + virtual ~CCameraWrapperExampleAppView (); + + private: + // Functions from base classes + void Draw (const TRect& aRect ) const; + void DrawTexts(CWindowGc& gc) const; + void SizeChanged (); + void HandlePointerEventL (const TPointerEvent& aPointerEvent ); + void SetTitle(const TDesC& aTitle); + void SetError( const TDesC& aMsg, TInt aVal ); + void SetError( const TDesC& aMsg, TInt aVal1, TInt aVal2 ); + void StartFocusing(); + void StorePicture( TDesC8* aData ); + + public: + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); + CCameraEngine* CameraEngine(){return iCameraWrapper;}; + void CancelCapturedPicture(TBool aCleanTexts=ETrue); + void Capture(); + + private: // From MCameraEngineObserver + void MceoCameraReady(); + void MceoFocusComplete(); + void MceoCapturedDataReady( TDesC8* aData ); + void MceoCapturedBitmapReady( CFbsBitmap* aBitmap ); + void MceoViewFinderFrameReady( CFbsBitmap& aFrame ); + void MceoHandleError( TCameraEngineError aErrorType, TInt aError ); + void MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ); + + private: + // Constructors + void ConstructL (const TRect& aRect ); + CCameraWrapperExampleAppView (); + + public: + void decodeBackbufferImage(); + + private: + void CreateBackBufferL(); + void ReleaseBackBuffer(); + void ShowResultL(TDesC16& message); + + //timer + void StartTimer(); + static TInt Tick(TAny* aObject); + + private: + // Data + + CCameraWrapperExampleAppUi* iAppUi; + + // CameraWrapper class + CCameraEngine* iCameraWrapper; + + TSize iViewFinderSize; + TSize iCaptureSize; + + CFbsBitmap* iBackBuffer; + CFbsBitmapDevice* iBackBufferDevice; + CFbsBitGc* iBackBufferContext; + + const CFont* iTitleFont; + TBuf<50> iTitle; + TRect iFocusRect; + + // Is new picture focused whit camera shutter key + TBool iCameraShutterFocusing; + + HBufC8* iData; + + +// Set the note as the member variable of your application view (for example, CAknView) +private: + CAknInfoPopupNoteController* iNote; + CPeriodic* iPeriodic; + + }; + +#endif // __CAMERAWRAPPEREXAMPLEAPPVIEW_h__ + +// End of File diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleApplication.h b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleApplication.h new file mode 100644 index 000000000..3b6d4a6df --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleApplication.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLEAPPLICATION_H__ +#define __CAMERAWRAPPEREXAMPLEAPPLICATION_H__ + +// INCLUDES +#include +#include "CameraWrapperExample.hrh" + +// UID for the application; +// this should correspond to the uid defined in the mmp file +const TUid KUidCameraWrapperExampleApp = + { + _UID3 + }; + +// CLASS DECLARATION + +class CCameraWrapperExampleApplication : public CAknApplication + { + public: + // Functions from base classes + TUid AppDllUid () const; + + protected: + // Functions from base classes + CApaDocument* CreateDocumentL (); + }; + +#endif // __CAMERAWRAPPEREXAMPLEAPPLICATION_H__ + +// End of File diff --git a/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleDocument.h b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleDocument.h new file mode 100644 index 000000000..e0f2c3a97 --- /dev/null +++ b/symbian/ZXingBarcodeReader/inc/CameraWrapperExampleDocument.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef __CAMERAWRAPPEREXAMPLEDOCUMENT_h__ +#define __CAMERAWRAPPEREXAMPLEDOCUMENT_h__ + +// INCLUDES +#include + +// FORWARD DECLARATIONS +class CCameraWrapperExampleAppUi; +class CEikApplication; + +// CLASS DECLARATION +class CCameraWrapperExampleDocument : public CAknDocument + { + public: + // Constructors and destructor + static CCameraWrapperExampleDocument* NewL (CEikApplication& aApp ); + static CCameraWrapperExampleDocument* NewLC (CEikApplication& aApp ); + virtual ~CCameraWrapperExampleDocument (); + + public: + // Functions from base classes + CEikAppUi* CreateAppUiL (); + + private: + // Constructors + void ConstructL (); + CCameraWrapperExampleDocument (CEikApplication& aApp ); + + private: + // Data + + }; + +#endif // __CAMERAWRAPPEREXAMPLEDOCUMENT_h__ + +// End of File diff --git a/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.pkg b/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.pkg new file mode 100644 index 000000000..eea513658 --- /dev/null +++ b/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.pkg @@ -0,0 +1,27 @@ +;Language - standard language definitions +&EN + +; standard SIS file header +#{"ZXingBarcodeReader"},(0xEF24C10A),1,0,0 + +;Localised Vendor name +%{"Forum Nokia"} + +;Unique Vendor name +:"Forum Nokia" + +;Supports S60 3rd Edition +[0x101F7961], 0, 0, 0, {"Series60ProductID"} + +;Supports S60 5th Edition +[0x1028315F], 0, 0, 0, {"S60ProductID"} + +;Files to install +"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\ZXingBarcodeReader_0xEF24C10A.exe" -"!:\sys\bin\ZXingBarcodeReader_0xEF24C10A.exe" +"$(EPOCROOT)Epoc32\data\z\resource\apps\ZXingBarcodeReader_0xEF24C10A.rsc" -"!:\resource\apps\ZXingBarcodeReader_0xEF24C10A.rsc" +"$(EPOCROOT)Epoc32\data\z\private\10003a3f\apps\ZXingBarcodeReader_0xEF24C10A_reg.rsc" -"!:\private\10003a3f\import\apps\ZXingBarcodeReader_0xEF24C10A_reg.rsc" +"$(EPOCROOT)Epoc32\data\z\resource\apps\ZXingBarcodeReader_0xEF24C10A.mif" -"!:\resource\apps\ZXingBarcodeReader_0xEF24C10A.mif" + +;CameraWrapper +@"$(EPOCROOT)Epoc32\InstallToDevice\CameraWrapper\sis\camerawrapper.sisx", (0x2001ec5f) + diff --git a/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx b/symbian/ZXingBarcodeReader/sis/ZXingBarcodeReader_S60.sisx new file mode 100644 index 0000000000000000000000000000000000000000..fc5a9290036cb317ad0a4373b788d68e4d3d240e GIT binary patch literal 175388 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 k#!1-c2BrT zHCOa-6;p73_#CGSA*A*6<%x4SW-9oWsg~sJ<_~qBHRULMm62P;CPu}@38uQ` z1^2(_rK%ThTQ?7?kO>y$Wu}&z2v!Vi|AEWG)tnP(>#_3EXBY8T{4nLyO3kR|k`_(| z{|`*Q7b6pCJzI|Tn8|%I#*>-@3o*28?(+GvQaTNDb>h7m4LdkHI~3q1BkV$O6_%ns zp}Et18Tb9(*BQMyMSsIcC+jKV2!YL4imbpnNDbz&rSSFtNX>C$?+S{nANqKb9D;Q{ zW`BMj9debtIb^B!tw1BLh1I_=JuK%-IRAKi;1_kLNyqEYX!Z0#JSFww1r>#a{ch+t z_88EJh;(}prTeF4Ty;Wqq9taVS*&yF5^(@|4`x#C!msWHZ(eit$ zDaK$-{9TIj6X&B&`Jn32@zg5U>{Z9RoylvGvX0O57M^zJ{Z=1PAHa;?t}=U7M%eb? z*?Bm__Lx!r)BH5~0oQ2x)316ZE$5Ye6RJ1X`U_cI*2Alk15c)seUp*t;P}<^6G2nf zAkh=Tu<~yFBKeSI$cuWs{j@i)B!9rzDYm1;BPA-imGkMWi?z1Tv6=f;XMcssoaDOX zt$O8Btt!D#p{2CPXt+$L418_AdUdCsZ55=$xX;j`zI!{f-1nyGi?!8Pdqt?IY0ns0 z!&>K0froKZDRo1=OUVvTb(1ElKEG%bScsdxz*$uG^`VJe=>*>8i&|!aY{8r2dBeVJ zBO|bcM2eE+bn2M;f_i`I^_>5*b&=h9WV{Pajq#>zjt3m1Ww7c02&yzH;s7fjL!L`Q9p zL_15yXu}W*wz?)y{Cu-#>o^9E8glnVCLym73bRuftRH+6AP8z zO!BzuP`0H?@7Wt*E6X9I-CenCEG z^V1hHRGzUukYY(GJ7Q#9V?x~D>@;3bS3u+PlwH5Q&f`2WpD`qC(pnk-BbO~(b$rUj ztXSVrU-2(itqbV%cleq+h(QO=ZZ>>Te}BL~wOY61xnr{0I&TCr_Xq!Zb$nV$ zOT9UCLOhHM$^25}et>Ni-t}(m*X*zPU(4O!7T+&SwvS$f+${-$9h8wQ`RnUh93 z(^Ebm&858VnJFyY6;{``a&ho>j;XzWOt)#>HPSWK)j%b?R?-^nWZPHW&H^0lvFNGJ z!r>9;GDYv?=13Jljdgc<7E8cd0OxXve6IcXOx_c6TE(dY)UVWm5lS0G59><|gj(@% zy8US!fAGnPCMzJyhgUB1^r{@cQ0F7-W90MB=cB6ihn!fn#~^8tlA!v-OJlvI0weq? zK~XpB*1grz`Qe#7!vtONcn&dj@yrw`WNO4>#QEu$&0C7KS(>K~m39WOgWyT*6nF|d zjhz9{f$I@|A3C$_hT_=^WnETLMz<4@m-Qfc6EtO=sjH%F&-+48c7AY4(s%IPi(XF$ zixP_lh{|szOHN}U$Jw_+Z>>#QUKLCjZ6;Y}U5HE3bQZ^()S4^{D|&1Bq}`2i(92Tc z5Rsf*+U%vp5mf!ldpLyXx|t4{emP~j*yN}E4gQ%Ct`_BO%L}-h{g0>M>3O_3Io_ky zD#F?sy0;z6<%;feW6`Rh??Kf;OBga?N_`45jhVqv`}1y{QF(H#xrShd*U;f`6b+*N3K@7q1-a0Rw+GSa`nA(ibFa)H>YTv^6!#YFFC5BWO9s}RS#Nxj5hCBql$e>e5RUfe5!qx znx~p)RAv&J7E~ZVa8m�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.iWidth; +} + +int CameraImage::getHeight() +{ + return image->SizeInPixels().iHeight; +} + +unsigned char CameraImage::getPixel(int x, int y) +{ + TPoint pixelPosition(x,y); + TRgb color; + image->GetPixel(color, pixelPosition); + return ((color.Red() + color.Green() + color.Blue()) / 3); +} + +void CameraImage::setImage(CFbsBitmap* newImage) +{ + image = newImage; +} + +CFbsBitmap* CameraImage::getImage() +{ + return image; +} + + diff --git a/symbian/ZXingBarcodeReader/src/CameraWrapperExample.cpp b/symbian/ZXingBarcodeReader/src/CameraWrapperExample.cpp new file mode 100644 index 000000000..4ec789de7 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/CameraWrapperExample.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +// INCLUDE FILES +#include +#include "CameraWrapperExampleApplication.h" + +LOCAL_C CApaApplication* NewApplication () + { + return new CCameraWrapperExampleApplication; + } + +GLDEF_C TInt E32Main () + { + return EikStart::RunApplication (NewApplication ); + } + diff --git a/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppUi.cpp b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppUi.cpp new file mode 100644 index 000000000..585c031f1 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppUi.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +// INCLUDE FILES +#include +#include +#include +#include +#include + +#include +#include "CameraWrapperExample.hrh" +#include "CameraWrapperExample.pan" +#include "CameraWrapperExampleApplication.h" +#include "CameraWrapperExampleAppUi.h" +#include "CameraWrapperExampleAppView.h" + + +// ============================ MEMBER FUNCTIONS =============================== + +void CCameraWrapperExampleAppUi::ConstructL () + { + // Initialise app UI with standard value. + BaseConstructL (CAknAppUi::EAknEnableSkin ); + + // Start receiving camera shutter key events + #ifdef ENABLE_CAMERA_SHUTTER + CaptureCameraShutter(ETrue); + #endif + + // Make this class observe changes in foreground events + iEikonEnv->AddForegroundObserverL(*this); + + // Create view + iAppView = CCameraWrapperExampleAppView::NewL (ClientRect () ); + } + +CCameraWrapperExampleAppUi::CCameraWrapperExampleAppUi () + { + } + +CCameraWrapperExampleAppUi::~CCameraWrapperExampleAppUi () + { + delete iAppView; + + #ifdef ENABLE_CAMERA_SHUTTER + CaptureCameraShutter(EFalse); + #endif + + iShutterKeyHandles.Close(); + } + +#ifdef ENABLE_CAMERA_SHUTTER + +void CCameraWrapperExampleAppUi::CaptureCameraShutter(TBool aEnable) + { + // Try to capture events from the camera shutter key(s) + // http://wiki.forum.nokia.com/index.php/KIS000563_-_Camera_shutter_key_(EKeyCamera_events)_cannot_be_used_in_3rd_party_applications + if (aEnable && !iCameraKeyCaptured) + { + iCameraKeyCaptured = ETrue; + // Enable capturing + RProcess proc; + iShutterKeyHandles.Reset(); + if(proc.HasCapability(ECapabilitySwEvent)) + { + for(TInt i=0; KCameraShutterKeyEventCodes[i] != 0; i++) + { + TInt32 handle = iEikonEnv->RootWin().CaptureKey( KCameraShutterKeyEventCodes[i], 0, 0 ); + if(handle >= 0) + { + iShutterKeyHandles.Append(handle); + } + } + } + } + else if(!aEnable && iCameraKeyCaptured) + { + iCameraKeyCaptured = EFalse; + // Disable capturing + // Release the captured camera shutter key(s) + for(TInt i=0; i < iShutterKeyHandles.Count(); i++) + { + iEikonEnv->RootWin().CancelCaptureKey( iShutterKeyHandles[i] ); + } + } + } +#endif + + +void CCameraWrapperExampleAppUi::HandleGainingForeground() + { + // Application gets focused so reserve the camera + // http://wiki.forum.nokia.com/index.php/CS000821_-_Handling_Camera_resource + if ( iAppView && + iAppView->CameraEngine() && + iAppView->CameraEngine()->State() != CCameraEngine::EEngineNotReady ) + { + iAppView->CameraEngine()->ReserveAndPowerOn(); + +#ifdef ENABLE_CAMERA_SHUTTER + CaptureCameraShutter(ETrue); +#endif + } + } + +void CCameraWrapperExampleAppUi::HandleLosingForeground() + { + // Application loses focus so release the camera + // http://wiki.forum.nokia.com/index.php/CS000821_-_Handling_Camera_resource + if ( iAppView && + iAppView->CameraEngine() && + iAppView->CameraEngine()->State() != CCameraEngine::EEngineNotReady ) + { + iAppView->CameraEngine()->ReleaseAndPowerOff(); + +#ifdef ENABLE_CAMERA_SHUTTER + CaptureCameraShutter(EFalse); +#endif + } + } + +void CCameraWrapperExampleAppUi::UseOptionsExitCbaL() + { + CEikButtonGroupContainer* cba = Cba(); + if (cba) + { + cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT); + cba->DrawNow(); + } + } + +void CCameraWrapperExampleAppUi::UseOptionsBackCbaL() + { + CEikButtonGroupContainer* cba = Cba(); + if (cba) + { + cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_BACK); + cba->DrawNow(); + } + } + +TBool CCameraWrapperExampleAppUi::IsBackCBA() + { + CEikButtonGroupContainer* cba = Cba(); + // NOTE: There should be EAknSoftkeyBack in the application because + // we use R_AVKON_SOFTKEYS_SELECT_BACK, but it seems that there is EAknSoftkeyCancel + CCoeControl* back = cba->ControlOrNull(EAknSoftkeyBack); + CCoeControl* cancel = cba->ControlOrNull(EAknSoftkeyCancel); + if (back || cancel) + return ETrue; + else + return EFalse; + } + +TKeyResponse CCameraWrapperExampleAppUi::HandleKeyEventL( + const TKeyEvent& aKeyEvent,TEventCode aType) + { + // Capture picture with selection key + switch ( aKeyEvent.iCode ) + { + case EKeyOK: + case EStdKeyDevice3: + case EKeyUpArrow: + case EKeyDownArrow: + { + // Capture picture + return iAppView->OfferKeyEventL(aKeyEvent,aType); + } + default: + { + break; + } + }; + + // Camera shutter events handling + #ifdef ENABLE_CAMERA_SHUTTER + // Camera shutter autofocus + switch ( aKeyEvent.iScanCode ) + { + case KStdKeyCameraFocus: + case KStdKeyCameraFocus2: + { + // Camera shutter autofocus + return iAppView->OfferKeyEventL(aKeyEvent,aType); + } + default: + { + break; + } + }; + // Camera shutter key + for(TInt i=0; KCameraShutterKeyEventCodes[i] != 0; i++) + { + if( KCameraShutterKeyEventCodes[i] == aKeyEvent.iCode ) + { + // Capture image + iAppView->Capture(); + return EKeyWasConsumed; + } + } + #endif + + return EKeyWasNotConsumed; + } + +void CCameraWrapperExampleAppUi::HandleCommandL (TInt aCommand ) + { + switch (aCommand ) + { + case EEikCmdExit: + case EAknSoftkeyExit: + { + Exit(); + break; + } + case EAknSoftkeyBack: + { + iAppView->CancelCapturedPicture(); + UseOptionsExitCbaL(); + break; + } + case EAbout: + { + CAknMessageQueryDialog* dlg = new (ELeave) CAknMessageQueryDialog (); + dlg->PrepareLC (R_ABOUT_QUERY_DIALOG ); + HBufC* title = iEikonEnv->AllocReadResourceLC (R_ABOUT_DIALOG_TITLE ); + dlg->QueryHeading ()->SetTextL (*title ); + CleanupStack::PopAndDestroy (); //title + HBufC* msg = iEikonEnv->AllocReadResourceLC (R_ABOUT_DIALOG_TEXT ); + dlg->SetMessageTextL (*msg ); + CleanupStack::PopAndDestroy (); //msg + dlg->RunLD(); + break; + } + default: + { + break; + } + }; + } + +void CCameraWrapperExampleAppUi::HandleResourceChangeL(TInt aType) + { + CAknAppUi::HandleResourceChangeL( aType ); + + if ( aType==KEikDynamicLayoutVariantSwitch ) + { + if (iAppView) + { + TRect rect; + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane,rect); + iAppView->SetRect(rect); + } + } + + } + +// End of File diff --git a/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppView.cpp b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppView.cpp new file mode 100644 index 000000000..66daa8901 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleAppView.cpp @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include +#include "CameraWrapperExampleAppView.h" +#include "CameraWrapperExampleAppUi.h" + + + +// ============================ MEMBER FUNCTIONS =============================== + +CCameraWrapperExampleAppView* CCameraWrapperExampleAppView::NewL (const TRect& aRect ) + { + CCameraWrapperExampleAppView* self = CCameraWrapperExampleAppView::NewLC (aRect ); + CleanupStack::Pop (self ); + return self; + } + +CCameraWrapperExampleAppView* CCameraWrapperExampleAppView::NewLC (const TRect& aRect ) + { + CCameraWrapperExampleAppView* self = new (ELeave) CCameraWrapperExampleAppView; + CleanupStack::PushL (self ); + self->ConstructL (aRect ); + return self; + } + +void CCameraWrapperExampleAppView::ConstructL (const TRect& aRect ) + { + // Create a window for this application view + CreateWindowL (); + + iTitleFont = AknLayoutUtils::FontFromId(EAknLogicalFontPrimarySmallFont); + + iAppUi = static_cast(iEikonEnv->EikAppUi()); + + // Set the windows size + SetRect (aRect ); + + //Start decoder timer. + StartTimer(); + + // Activate the window, which makes it ready to be drawn + ActivateL (); + } + +CCameraWrapperExampleAppView::CCameraWrapperExampleAppView () : iPeriodic(NULL) + { + } + +CCameraWrapperExampleAppView::~CCameraWrapperExampleAppView () + { + if (iCameraWrapper) + { + iCameraWrapper->ReleaseAndPowerOff(); + } + delete iCameraWrapper; + delete iData; + + ReleaseBackBuffer(); + } + +TKeyResponse CCameraWrapperExampleAppView::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) + { + switch ( aKeyEvent.iCode ) + { + case EKeyOK: + case EStdKeyDevice3: + { + // Capture picture + iCameraShutterFocusing = EFalse; + StartFocusing(); + return EKeyWasConsumed; + } + case EKeyUpArrow: + { + if (iCameraWrapper->State() == CCameraEngine::EEngineViewFinding) + { + iCameraWrapper->AdjustDigitalZoom(ETrue); + } + return EKeyWasConsumed; + } + case EKeyDownArrow: + { + if (iCameraWrapper->State() == CCameraEngine::EEngineViewFinding) + { + iCameraWrapper->AdjustDigitalZoom(EFalse); + + } + return EKeyWasConsumed; + } + default: + { + break; + } + }; + + + +#ifdef ENABLE_CAMERA_SHUTTER + // Camera shutter autofocus + switch ( aKeyEvent.iScanCode ) + { + case KStdKeyCameraFocus: + case KStdKeyCameraFocus2: + { + // Camera shutter autofocus + if (aType == EEventKeyDown) + { + if (!iAppUi->IsBackCBA()) + { + iCameraShutterFocusing = ETrue; + StartFocusing(); + } + return EKeyWasConsumed; + } + else if (aType == EEventKeyUp) + { + // Camera state can be EEngineIdle or EEngineFocusing + if (!iAppUi->IsBackCBA() && (iCameraWrapper->State() == CCameraEngine::EEngineFocusing || + iCameraWrapper->State() == CCameraEngine::EEngineIdle)) + { + iCameraWrapper->FocusCancel(); + CancelCapturedPicture(); + iAppUi->UseOptionsExitCbaL(); + } + return EKeyWasConsumed; + } + } + default: + { + break; + } + }; +#endif + + return EKeyWasNotConsumed; + } + +void CCameraWrapperExampleAppView::CancelCapturedPicture(TBool aCleanTexts) + { + if (iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineIdle) + { + TRAPD(err,iCameraWrapper->StartViewFinderL(iViewFinderSize)); + if (aCleanTexts) + { + if (err) + { + SetError(_L("Camera viewfinder error %d"), err); + } + else + { + SetTitle(_L("Camera viewfinder")); + } + } + } + } + +void CCameraWrapperExampleAppView::Draw(const TRect& /*aRect*/) const + { + CWindowGc& gc = SystemGc (); + + // Draw backbuffer that has camera picture + gc.BitBlt(TPoint(0, 0), iBackBuffer); + + // Draw texts + DrawTexts(gc); + + // Focus rect + if (iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineFocusing) + { + gc.SetPenColor(KRgbWhite); + gc.DrawRect(iFocusRect); + } + } + +void CCameraWrapperExampleAppView::DrawTexts(CWindowGc& gc) const + { + if (iTitle.Length()>0) + { + TRect rect(Rect()); + gc.SetPenColor(KRgbWhite); + gc.UseFont(iTitleFont); + gc.DrawText(iTitle, rect, rect.Height()/10, CGraphicsContext::ECenter ); + gc.DiscardFont(); + } + } + +void CCameraWrapperExampleAppView::SizeChanged() + { + // Create camera wrapper class here because + // whole camera wrapper and all handles have to reset + // while orientatio of the application changes. + if (iCameraWrapper) + { + // Power off camera if it is on + iCameraWrapper->StopViewFinder(); + iCameraWrapper->ReleaseAndPowerOff(); + delete iCameraWrapper; iCameraWrapper = NULL; + } + TInt camErr(KErrNotSupported); + if(CCameraEngine::CamerasAvailable() > 0) + { + TRAP(camErr, iCameraWrapper = CCameraEngine::NewL(0,0,this)); + } + + // iViewFinderSize is picture size for viewfinder. + // iCaptureSize is picture size for capturing picture. + // We want fill whole screen + if (Rect().Size().iWidth > Rect().Size().iHeight) + { + iViewFinderSize = TSize(Rect().Size().iWidth,Rect().Size().iWidth); + iCaptureSize = TSize(1280,960); // Captured picture size + } + else + { + iViewFinderSize = TSize(Rect().Size().iHeight,Rect().Size().iHeight); + iCaptureSize = TSize(1280,960); // Captured picture size + } + + // Focus rectangle + iFocusRect = Rect(); + iFocusRect.Shrink(Rect().Size().iWidth/4, Rect().Size().iHeight/4); + + // Create back buffer where recieved camera pictures are copied + ReleaseBackBuffer(); + CreateBackBufferL(); + + // Power on camera, start viewfinder when MceoCameraReady() received + if(camErr == KErrNone) + { + iCameraWrapper->ReserveAndPowerOn(); + SetTitle(_L("Camera power on")); + } + else + { + SetTitle(_L("no camera found")); + } + } + +void CCameraWrapperExampleAppView::HandlePointerEventL ( + const TPointerEvent& aPointerEvent ) + { + if (aPointerEvent.iType == TPointerEvent::EButton1Down) + { + // When pointing to screen camera capture picture + if (!iAppUi->IsBackCBA() && + iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineViewFinding) + { + iCameraShutterFocusing = EFalse; + StartFocusing(); + } + // After captureing, when pointing again to screen camera + // start viewfinder again + else if (!iAppUi->IsBackCBA() && + iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineIdle) + { + CancelCapturedPicture(); + iAppUi->UseOptionsExitCbaL(); + } + } + } + +void CCameraWrapperExampleAppView::SetTitle(const TDesC& aTitle) + { + iTitle.Copy(aTitle); + DrawNow(); + } + +void CCameraWrapperExampleAppView::SetError( const TDesC& aMsg, TInt aVal ) + { + iTitle.Format(aMsg, aVal); + DrawNow(); + } + +void CCameraWrapperExampleAppView::SetError( const TDesC& aMsg, TInt aVal1, TInt aVal2 ) + { + iTitle.Format(aMsg, aVal1, aVal2); + DrawNow(); + } + +void CCameraWrapperExampleAppView::CreateBackBufferL() + { + // create back buffer bitmap + iBackBuffer = new (ELeave) CFbsBitmap; + + User::LeaveIfError( iBackBuffer->Create(Size(),EColor16M)); + + // create back buffer graphics context + iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBuffer); + User::LeaveIfError(iBackBufferDevice->CreateContext(iBackBufferContext)); + iBackBufferContext->SetPenStyle(CGraphicsContext::ESolidPen); + + iBackBufferContext->SetBrushColor(KRgbBlack); + iBackBufferContext->Clear(); + } + +void CCameraWrapperExampleAppView::ReleaseBackBuffer() + { + if (iBackBufferContext) + { + delete iBackBufferContext; + iBackBufferContext = NULL; + } + if (iBackBufferDevice) + { + delete iBackBufferDevice; + iBackBufferDevice = NULL; + } + if (iBackBuffer) + { + delete iBackBuffer; + iBackBuffer = NULL; + } + } + +void CCameraWrapperExampleAppView::MceoCameraReady() + { + iAppUi->UseOptionsExitCbaL(); + + if (iCameraWrapper->State() == CCameraEngine::EEngineIdle) + { + // Prepare camera + TRAPD(err,iCameraWrapper->PrepareL(iCaptureSize)); + if (err) + { + SetError(_L("Camera prepare error %d"), err); + return; + } + + // Start viewfinder. Viewfinder pictures starts coming into MceoViewFinderFrameReady(); + TRAPD(err2,iCameraWrapper->StartViewFinderL(iViewFinderSize)); + if (err2) + { + SetError(_L("Camera start viewfinder error %d"), err2); + return; + } + + SetTitle(_L("Camera viewfinder")); + } + } + +void CCameraWrapperExampleAppView::Capture() + { + // This method is called when picture is focused with camera shutter and pressed whole down + // as taking a new picture +#ifdef ENABLE_CAMERA_SHUTTER + if (iCameraWrapper && !iAppUi->IsBackCBA()) + { + // No focus supported + SetTitle(_L("Capturing picture")); + iCameraWrapper->StopViewFinder(); + TRAPD(err,iCameraWrapper->CaptureL()); + if (err) + { + SetError(_L("Camera capture error %d"), err); + } + } +#endif + } + +void CCameraWrapperExampleAppView::StartFocusing() + { + if (iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineViewFinding) + { + if (!iCameraWrapper->IsAutoFocusSupported()) + { + // No focus supported + SetTitle(_L("Capturing picture")); + iCameraWrapper->StopViewFinder(); + TRAPD(err,iCameraWrapper->CaptureL()); + if (err) + { + SetError(_L("Camera capture error %d"), err); + } + } + else + { + // Focusing supported + iCameraWrapper->StartFocusL(); + SetTitle(_L("Autofocusing...")); + } + } + } + +void CCameraWrapperExampleAppView::MceoFocusComplete() + { + // CameraEngine state is EEngineIdle + SetTitle(_L("Focused")); + + if (iCameraShutterFocusing) + { + // Leave as focused. User must press whole camera shutter down for capturing + // then CCameraWrapperExampleAppView::Capture() is called + } + else + { + // Capture picture after it has focused + iCameraWrapper->StopViewFinder(); + TRAPD(err,iCameraWrapper->CaptureL()); + if (err) + { + SetError(_L("Camera capture error %d"), err); + } + } + } + +void CCameraWrapperExampleAppView::MceoCapturedDataReady( TDesC8* aData ) + { + SetTitle(_L("Saving picture...")); + + delete iData; iData = NULL; + iData = aData->Alloc(); + + if (iCameraWrapper) + iCameraWrapper->ReleaseImageBuffer(); + + TRAP_IGNORE(iAppUi->UseOptionsBackCbaL()); + + StorePicture(iData); + } + +void CCameraWrapperExampleAppView::StorePicture( TDesC8* aData ) + { + // Create path for filename + TFileName path = PathInfo::PhoneMemoryRootPath(); + path.Append(PathInfo::ImagesPath()); + + // Ensure that path exists + BaflUtils::EnsurePathExistsL(iEikonEnv->FsSession(),path); + + // Get next free filename for the image + TFileName fileToSave; + TBool fileExists = ETrue; + for (TInt i=1 ; i<100 ; i++) + { + fileToSave.Copy(path); + fileToSave.Append(_L("cw_image_")); + fileToSave.AppendNum(i); + fileToSave.Append(_L(".jpg")); + fileExists = BaflUtils::FileExists(iEikonEnv->FsSession(),fileToSave); + if (!fileExists) + { + break; + } + } + + // Save file + if (!fileExists) + { + RFile file; + TInt err = file.Create(iEikonEnv->FsSession(),fileToSave,EFileWrite); + if (!err) + { + file.Write(*aData); + file.Close(); + SetTitle(fileToSave); + } + else + { + SetError(_L("File saving error %d"),err); + } + } + else + { + SetTitle(_L("File not saved, delete old pictures!")); + } + } + + +void CCameraWrapperExampleAppView::MceoCapturedBitmapReady( CFbsBitmap* aBitmap ) + { + if (iBackBufferContext) + { + TSize bmpSizeInPixels = aBitmap->SizeInPixels(); + TInt xDelta = (Rect().Width() - bmpSizeInPixels.iWidth) / 2; + TInt yDelta = (Rect().Height() - bmpSizeInPixels.iHeight) / 2; + TPoint pos( xDelta, yDelta ); + + // Copy received viewfinder picture to back buffer + iBackBufferContext->BitBlt( pos, aBitmap, TRect( TPoint( 0, 0 ), bmpSizeInPixels )); + + // Update backbuffer into screen + SetTitle(_L("New picture")); + } + if (iCameraWrapper) + iCameraWrapper->ReleaseImageBuffer(); + } + +void CCameraWrapperExampleAppView::MceoViewFinderFrameReady( CFbsBitmap& aFrame ) + { + if (iBackBufferContext) + { + TSize bmpSizeInPixels = aFrame.SizeInPixels(); + TInt xDelta = (Rect().Width() - bmpSizeInPixels.iWidth) / 2; + TInt yDelta = (Rect().Height() - bmpSizeInPixels.iHeight) / 2; + TPoint pos( xDelta, yDelta ); + + // Copy received viewfinder picture to back buffer + iBackBufferContext->BitBlt( pos, &aFrame, TRect( TPoint( 0, 0 ), bmpSizeInPixels )); + + // Update backbuffer into screen + DrawNow(); + } + if (iCameraWrapper) + iCameraWrapper->ReleaseViewFinderBuffer(); + } + +void CCameraWrapperExampleAppView::MceoHandleError( TCameraEngineError aErrorType, TInt aError ) + { + // NOTE: CameraEngine state seems to go into CCameraEngine::EEngineIdle state + + if (aErrorType == EErrReserve) + { + return; //-18 comes on application startup, but everything works ok + } + + switch (aErrorType) + { + case EErrReserve: + { + SetError(_L("Camera reserved error (%d)"), aError); + break; + } + case EErrPowerOn: + { + SetError(_L("Camera power on error (%d)"), aError); + break; + } + case EErrViewFinderReady: + { + SetError(_L("Camera viewfinder error (%d)"), aError); + break; + } + case EErrImageReady: + { + SetError(_L("Camera image ready error (%d)"), aError); + break; + } + case EErrAutoFocusInit: + case EErrAutoFocusMode: + case EErrAutoFocusArea: + case EErrAutoFocusRange: + case EErrAutoFocusType: + case EErrOptimisedFocusComplete: + { + //SetTitle(_L("Try focusing again")); + break; + } + default: + { + SetError(_L("Error %d (%d)"), aErrorType, aError); + break; + } + }; + + // Try handle error + CancelCapturedPicture(EFalse); + iAppUi->UseOptionsExitCbaL(); + } + +void CCameraWrapperExampleAppView::MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ) + { + } + + + + +// End of File diff --git a/symbian/ZXingBarcodeReader/src/CameraWrapperExampleApplication.cpp b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleApplication.cpp new file mode 100644 index 000000000..5542e4781 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleApplication.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +// INCLUDE FILES +#include "CameraWrapperExample.hrh" +#include "CameraWrapperExampleDocument.h" +#include "CameraWrapperExampleApplication.h" + +// ============================ MEMBER FUNCTIONS =============================== + +CApaDocument* CCameraWrapperExampleApplication::CreateDocumentL () + { + // Create an CameraWrapperExample document, and return a pointer to it + return CCameraWrapperExampleDocument::NewL (*this ); + } + +TUid CCameraWrapperExampleApplication::AppDllUid () const + { + // Return the UID for the CameraWrapperExample application + return KUidCameraWrapperExampleApp; + } + +// End of File diff --git a/symbian/ZXingBarcodeReader/src/CameraWrapperExampleDocument.cpp b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleDocument.cpp new file mode 100644 index 000000000..0b0e2c3d9 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/CameraWrapperExampleDocument.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +// INCLUDE FILES +#include "CameraWrapperExampleAppUi.h" +#include "CameraWrapperExampleDocument.h" + +// ============================ MEMBER FUNCTIONS =============================== + +CCameraWrapperExampleDocument* CCameraWrapperExampleDocument::NewL ( + CEikApplication& aApp ) + { + CCameraWrapperExampleDocument* self = NewLC (aApp ); + CleanupStack::Pop (self ); + return self; + } + +CCameraWrapperExampleDocument* CCameraWrapperExampleDocument::NewLC ( + CEikApplication& aApp ) + { + CCameraWrapperExampleDocument* self = + new (ELeave) CCameraWrapperExampleDocument (aApp ); + + CleanupStack::PushL (self ); + self->ConstructL (); + return self; + } + +void CCameraWrapperExampleDocument::ConstructL () + { + } + +CCameraWrapperExampleDocument::CCameraWrapperExampleDocument ( + CEikApplication& aApp ) : + CAknDocument (aApp ) + { + } + +CCameraWrapperExampleDocument::~CCameraWrapperExampleDocument () + { + } + +CEikAppUi* CCameraWrapperExampleDocument::CreateAppUiL () + { + return new (ELeave) CCameraWrapperExampleAppUi; + } + +// End of File diff --git a/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp b/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp new file mode 100644 index 000000000..56bfe41e4 --- /dev/null +++ b/symbian/ZXingBarcodeReader/src/DecodingOperations.cpp @@ -0,0 +1,104 @@ +#include "CameraWrapperExampleAppView.h" +#include + +#include + +#include +#include +#include +#include +#include + +using namespace zxing; +using namespace zxing::qrcode; + +void CCameraWrapperExampleAppView::StartTimer() + { + const TInt tickInterval=2000000; + iPeriodic=CPeriodic::NewL(0); // neutral priority + + //CleanupStack::PushL(iPeriodic); + + iPeriodic->Start(tickInterval,tickInterval,TCallBack(&CCameraWrapperExampleAppView::Tick, this)); + +// CleanupStack::PopAndDestroy(iPeriodic); + } + +TInt CCameraWrapperExampleAppView::Tick(TAny* aObject) + { + // cast, and call non-static function + ((CCameraWrapperExampleAppView*)aObject)->decodeBackbufferImage(); + return 1; + } + +void CCameraWrapperExampleAppView::decodeBackbufferImage() + { + QRCodeReader decoder; + + CameraImage image; + image.setImage(iBackBuffer); + + + Ref res; + + try + { + Ref imageRef(new CameraImage(image)); + GlobalHistogramBinarizer* binz = new GlobalHistogramBinarizer(imageRef); + + Ref bz (binz); + BinaryBitmap* bb = new BinaryBitmap(bz); + + Ref ref(bb); + + res = decoder.decode(ref); + + string string = res->getText()->getText(); + HBufC8 *pHeap8 = HBufC8::NewMaxLC(string.size()); + pHeap8->Des().Copy((const TUint8 *)string.c_str()); + + HBufC *pHeap16 = HBufC::NewMaxLC(pHeap8->Length()); + pHeap16->Des().Copy(*pHeap8); + + ShowResultL(*pHeap16); + } + catch(zxing::Exception& e) + { + string string = "Error...retrying..."; + HBufC8 *pHeap8 = HBufC8::NewMaxLC(string.size()); + pHeap8->Des().Copy((const TUint8 *)string.c_str()); + + HBufC *pHeap16 = HBufC::NewMaxLC(pHeap8->Length()); + pHeap16->Des().Copy(*pHeap8); + + ShowResultL(*pHeap16); + } + } + +void CCameraWrapperExampleAppView::ShowResultL(TDesC16& message) + { + if (!iNote) + { + // Create the note once + iNote = CAknInfoPopupNoteController::NewL(); + } + // Hide the note. The last note may be visible when creating the second + iNote->HideInfoPopupNote(); + + // Set the time delay period before the popup is shown (in milliseconds) + iNote->SetTimeDelayBeforeShow(100); + + // Set the time period of how long the popup is in the view (in milliseconds) + iNote->SetTimePopupInView(2*1000); + + // Note text + iNote->SetTextL(message); + + TRect rect(Rect()); + + // Note position + iNote->SetPositionAndAlignment(TPoint(rect.Width()/5,rect.Height()/7),EHLeftVTop); + + // Show note + iNote->ShowInfoPopupNote(); + }