From e29b06083d09a91a3a225e03e10f9d8ca1685e79 Mon Sep 17 00:00:00 2001 From: ftylitak Date: Thu, 6 May 2010 11:18:01 +0000 Subject: [PATCH] Added a project written on Qt framework for Symbian and added tutorials for both ZXingBarcodeReader and QQrDecoder git-svn-id: https://zxing.googlecode.com/svn/trunk@1339 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- AUTHORS | 1 + symbian/QQrDecoder/CameraImageWrapper.cpp | 77 +++ symbian/QQrDecoder/CameraImageWrapper.h | 31 + symbian/QQrDecoder/Nokia_Licence.txt | 31 + .../QQrDecoder/QCameraControllerWidget.cpp | 322 ++++++++++ symbian/QQrDecoder/QCameraControllerWidget.h | 67 +++ symbian/QQrDecoder/QQrDecoder.cpp | 99 ++++ symbian/QQrDecoder/QQrDecoder.h | 62 ++ symbian/QQrDecoder/QQrDecoder.pro | 159 +++++ symbian/QQrDecoder/QQrDecoder.svg | 91 +++ symbian/QQrDecoder/QQrDecoder.ui | 54 ++ symbian/QQrDecoder/QQrDecoder_template.sisx | Bin 0 -> 180076 bytes symbian/QQrDecoder/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 symbian/QQrDecoder/main.cpp | 42 ++ symbian/QQrDecoder/zxing/BarcodeFormat.cpp | 22 + symbian/QQrDecoder/zxing/BarcodeFormat.h | 42 ++ symbian/QQrDecoder/zxing/Binarizer.cpp | 48 ++ symbian/QQrDecoder/zxing/Binarizer.h | 51 ++ symbian/QQrDecoder/zxing/BinaryBitmap.cpp | 57 ++ symbian/QQrDecoder/zxing/BinaryBitmap.h | 51 ++ symbian/QQrDecoder/zxing/Exception.cpp | 25 + symbian/QQrDecoder/zxing/Exception.h | 40 ++ symbian/QQrDecoder/zxing/LuminanceSource.cpp | 43 ++ symbian/QQrDecoder/zxing/LuminanceSource.h | 42 ++ .../QQrDecoder/zxing/MultiFormatReader.cpp | 54 ++ symbian/QQrDecoder/zxing/MultiFormatReader.h | 38 ++ symbian/QQrDecoder/zxing/Reader.cpp | 27 + symbian/QQrDecoder/zxing/Reader.h | 38 ++ symbian/QQrDecoder/zxing/ReaderException.cpp | 32 + symbian/QQrDecoder/zxing/ReaderException.h | 35 ++ symbian/QQrDecoder/zxing/Result.cpp | 59 ++ symbian/QQrDecoder/zxing/Result.h | 54 ++ symbian/QQrDecoder/zxing/ResultPoint.cpp | 22 + symbian/QQrDecoder/zxing/ResultPoint.h | 36 ++ symbian/QQrDecoder/zxing/common/Array.cpp | 22 + symbian/QQrDecoder/zxing/common/Array.h | 209 +++++++ symbian/QQrDecoder/zxing/common/BitArray.cpp | 118 ++++ symbian/QQrDecoder/zxing/common/BitArray.h | 57 ++ symbian/QQrDecoder/zxing/common/BitMatrix.cpp | 148 +++++ symbian/QQrDecoder/zxing/common/BitMatrix.h | 61 ++ symbian/QQrDecoder/zxing/common/BitSource.cpp | 75 +++ symbian/QQrDecoder/zxing/common/BitSource.h | 68 +++ symbian/QQrDecoder/zxing/common/Counted.cpp | 32 + symbian/QQrDecoder/zxing/common/Counted.h | 204 +++++++ .../QQrDecoder/zxing/common/DecoderResult.cpp | 37 ++ .../QQrDecoder/zxing/common/DecoderResult.h | 44 ++ .../zxing/common/DetectorResult.cpp | 41 ++ .../QQrDecoder/zxing/common/DetectorResult.h | 47 ++ .../QQrDecoder/zxing/common/EdgeDetector.cpp | 190 ++++++ .../QQrDecoder/zxing/common/EdgeDetector.h | 38 ++ .../zxing/common/GlobalHistogramBinarizer.cpp | 177 ++++++ .../zxing/common/GlobalHistogramBinarizer.h | 44 ++ .../QQrDecoder/zxing/common/GridSampler.cpp | 101 ++++ symbian/QQrDecoder/zxing/common/GridSampler.h | 44 ++ .../zxing/common/IllegalArgumentException.cpp | 31 + .../zxing/common/IllegalArgumentException.h | 34 ++ .../zxing/common/LocalBlockBinarizer.cpp | 196 ++++++ .../zxing/common/LocalBlockBinarizer.h | 47 ++ .../zxing/common/PerspectiveTransform.cpp | 121 ++++ .../zxing/common/PerspectiveTransform.h | 50 ++ symbian/QQrDecoder/zxing/common/Point.h | 47 ++ symbian/QQrDecoder/zxing/common/Str.cpp | 38 ++ symbian/QQrDecoder/zxing/common/Str.h | 41 ++ .../zxing/common/reedsolomon/GF256.cpp | 140 +++++ .../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 ++ .../QQrDecoder/zxing/oned/Code128Reader.cpp | 478 +++++++++++++++ symbian/QQrDecoder/zxing/oned/Code128Reader.h | 61 ++ .../QQrDecoder/zxing/oned/Code39Reader.cpp | 340 +++++++++++ symbian/QQrDecoder/zxing/oned/Code39Reader.h | 57 ++ symbian/QQrDecoder/zxing/oned/EAN13Reader.cpp | 95 +++ symbian/QQrDecoder/zxing/oned/EAN13Reader.h | 41 ++ symbian/QQrDecoder/zxing/oned/EAN8Reader.cpp | 75 +++ symbian/QQrDecoder/zxing/oned/EAN8Reader.h | 40 ++ symbian/QQrDecoder/zxing/oned/ITFReader.cpp | 355 +++++++++++ symbian/QQrDecoder/zxing/oned/ITFReader.h | 53 ++ .../zxing/oned/MultiFormatOneDReader.cpp | 55 ++ .../zxing/oned/MultiFormatOneDReader.h | 39 ++ .../zxing/oned/MultiFormatUPCEANReader.cpp | 79 +++ .../zxing/oned/MultiFormatUPCEANReader.h | 41 ++ symbian/QQrDecoder/zxing/oned/OneDReader.cpp | 194 ++++++ symbian/QQrDecoder/zxing/oned/OneDReader.h | 46 ++ .../QQrDecoder/zxing/oned/OneDResultPoint.cpp | 39 ++ .../QQrDecoder/zxing/oned/OneDResultPoint.h | 37 ++ symbian/QQrDecoder/zxing/oned/UPCAReader.cpp | 64 ++ symbian/QQrDecoder/zxing/oned/UPCAReader.h | 45 ++ .../QQrDecoder/zxing/oned/UPCEANReader.cpp | 316 ++++++++++ symbian/QQrDecoder/zxing/oned/UPCEANReader.h | 65 ++ symbian/QQrDecoder/zxing/oned/UPCEReader.cpp | 150 +++++ symbian/QQrDecoder/zxing/oned/UPCEReader.h | 45 ++ .../zxing/qrcode/ErrorCorrectionLevel.cpp | 49 ++ .../zxing/qrcode/ErrorCorrectionLevel.h | 47 ++ .../zxing/qrcode/FormatInformation.cpp | 108 ++++ .../zxing/qrcode/FormatInformation.h | 55 ++ .../QQrDecoder/zxing/qrcode/QRCodeReader.cpp | 84 +++ .../QQrDecoder/zxing/qrcode/QRCodeReader.h | 43 ++ symbian/QQrDecoder/zxing/qrcode/Version.cpp | 559 ++++++++++++++++++ symbian/QQrDecoder/zxing/qrcode/Version.h | 87 +++ .../zxing/qrcode/decoder/BitMatrixParser.cpp | 191 ++++++ .../zxing/qrcode/decoder/BitMatrixParser.h | 52 ++ .../zxing/qrcode/decoder/DataBlock.cpp | 118 ++++ .../zxing/qrcode/decoder/DataBlock.h | 52 ++ .../zxing/qrcode/decoder/DataMask.cpp | 159 +++++ .../zxing/qrcode/decoder/DataMask.h | 51 ++ .../qrcode/decoder/DecodedBitStreamParser.cpp | 282 +++++++++ .../qrcode/decoder/DecodedBitStreamParser.h | 60 ++ .../zxing/qrcode/decoder/Decoder.cpp | 103 ++++ .../QQrDecoder/zxing/qrcode/decoder/Decoder.h | 49 ++ .../QQrDecoder/zxing/qrcode/decoder/Mode.cpp | 73 +++ .../QQrDecoder/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 ++ .../zxing/qrcode/detector/Detector.cpp | 265 +++++++++ .../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/QQrDecoder_tutorial.txt | 58 ++ symbian/ZXingBarcodeReader_tutorial.txt | 46 ++ 143 files changed, 12792 insertions(+) create mode 100644 symbian/QQrDecoder/CameraImageWrapper.cpp create mode 100644 symbian/QQrDecoder/CameraImageWrapper.h create mode 100644 symbian/QQrDecoder/Nokia_Licence.txt create mode 100644 symbian/QQrDecoder/QCameraControllerWidget.cpp create mode 100644 symbian/QQrDecoder/QCameraControllerWidget.h create mode 100644 symbian/QQrDecoder/QQrDecoder.cpp create mode 100644 symbian/QQrDecoder/QQrDecoder.h create mode 100644 symbian/QQrDecoder/QQrDecoder.pro create mode 100644 symbian/QQrDecoder/QQrDecoder.svg create mode 100644 symbian/QQrDecoder/QQrDecoder.ui create mode 100644 symbian/QQrDecoder/QQrDecoder_template.sisx create mode 100644 symbian/QQrDecoder/ZXing_Licence.txt create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/InstallToDevice/CameraWrapper/sis/camerawrapper.sisx create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/include/cameraengine.h create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/include/cameraengineobserver.h create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper.dso create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper.lib create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.dso create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.lib create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll.map create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/CamAutoFocus.dll create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.dll create mode 100644 symbian/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.lib create mode 100644 symbian/QQrDecoder/main.cpp create mode 100644 symbian/QQrDecoder/zxing/BarcodeFormat.cpp create mode 100644 symbian/QQrDecoder/zxing/BarcodeFormat.h create mode 100644 symbian/QQrDecoder/zxing/Binarizer.cpp create mode 100644 symbian/QQrDecoder/zxing/Binarizer.h create mode 100644 symbian/QQrDecoder/zxing/BinaryBitmap.cpp create mode 100644 symbian/QQrDecoder/zxing/BinaryBitmap.h create mode 100644 symbian/QQrDecoder/zxing/Exception.cpp create mode 100644 symbian/QQrDecoder/zxing/Exception.h create mode 100644 symbian/QQrDecoder/zxing/LuminanceSource.cpp create mode 100644 symbian/QQrDecoder/zxing/LuminanceSource.h create mode 100644 symbian/QQrDecoder/zxing/MultiFormatReader.cpp create mode 100644 symbian/QQrDecoder/zxing/MultiFormatReader.h create mode 100644 symbian/QQrDecoder/zxing/Reader.cpp create mode 100644 symbian/QQrDecoder/zxing/Reader.h create mode 100644 symbian/QQrDecoder/zxing/ReaderException.cpp create mode 100644 symbian/QQrDecoder/zxing/ReaderException.h create mode 100644 symbian/QQrDecoder/zxing/Result.cpp create mode 100644 symbian/QQrDecoder/zxing/Result.h create mode 100644 symbian/QQrDecoder/zxing/ResultPoint.cpp create mode 100644 symbian/QQrDecoder/zxing/ResultPoint.h create mode 100644 symbian/QQrDecoder/zxing/common/Array.cpp create mode 100644 symbian/QQrDecoder/zxing/common/Array.h create mode 100644 symbian/QQrDecoder/zxing/common/BitArray.cpp create mode 100644 symbian/QQrDecoder/zxing/common/BitArray.h create mode 100644 symbian/QQrDecoder/zxing/common/BitMatrix.cpp create mode 100644 symbian/QQrDecoder/zxing/common/BitMatrix.h create mode 100644 symbian/QQrDecoder/zxing/common/BitSource.cpp create mode 100644 symbian/QQrDecoder/zxing/common/BitSource.h create mode 100644 symbian/QQrDecoder/zxing/common/Counted.cpp create mode 100644 symbian/QQrDecoder/zxing/common/Counted.h create mode 100644 symbian/QQrDecoder/zxing/common/DecoderResult.cpp create mode 100644 symbian/QQrDecoder/zxing/common/DecoderResult.h create mode 100644 symbian/QQrDecoder/zxing/common/DetectorResult.cpp create mode 100644 symbian/QQrDecoder/zxing/common/DetectorResult.h create mode 100644 symbian/QQrDecoder/zxing/common/EdgeDetector.cpp create mode 100644 symbian/QQrDecoder/zxing/common/EdgeDetector.h create mode 100644 symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp create mode 100644 symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.h create mode 100644 symbian/QQrDecoder/zxing/common/GridSampler.cpp create mode 100644 symbian/QQrDecoder/zxing/common/GridSampler.h create mode 100644 symbian/QQrDecoder/zxing/common/IllegalArgumentException.cpp create mode 100644 symbian/QQrDecoder/zxing/common/IllegalArgumentException.h create mode 100644 symbian/QQrDecoder/zxing/common/LocalBlockBinarizer.cpp create mode 100644 symbian/QQrDecoder/zxing/common/LocalBlockBinarizer.h create mode 100644 symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp create mode 100644 symbian/QQrDecoder/zxing/common/PerspectiveTransform.h create mode 100644 symbian/QQrDecoder/zxing/common/Point.h create mode 100644 symbian/QQrDecoder/zxing/common/Str.cpp create mode 100644 symbian/QQrDecoder/zxing/common/Str.h create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/GF256.h create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/GF256Poly.cpp create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/GF256Poly.h create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.cpp create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.h create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.cpp create mode 100644 symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.h create mode 100644 symbian/QQrDecoder/zxing/oned/Code128Reader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/Code128Reader.h create mode 100644 symbian/QQrDecoder/zxing/oned/Code39Reader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/Code39Reader.h create mode 100644 symbian/QQrDecoder/zxing/oned/EAN13Reader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/EAN13Reader.h create mode 100644 symbian/QQrDecoder/zxing/oned/EAN8Reader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/EAN8Reader.h create mode 100644 symbian/QQrDecoder/zxing/oned/ITFReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/ITFReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/MultiFormatOneDReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/MultiFormatOneDReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/OneDReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/OneDReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/OneDResultPoint.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/OneDResultPoint.h create mode 100644 symbian/QQrDecoder/zxing/oned/UPCAReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/UPCAReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/UPCEANReader.h create mode 100644 symbian/QQrDecoder/zxing/oned/UPCEReader.cpp create mode 100644 symbian/QQrDecoder/zxing/oned/UPCEReader.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/FormatInformation.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/FormatInformation.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/QRCodeReader.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/QRCodeReader.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/Version.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/Version.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DataBlock.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DataBlock.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DataMask.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DataMask.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/Decoder.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/Decoder.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/Mode.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/decoder/Mode.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/Detector.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/Detector.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPattern.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPattern.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.h create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.cpp create mode 100644 symbian/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.h create mode 100644 symbian/QQrDecoder_tutorial.txt create mode 100644 symbian/ZXingBarcodeReader_tutorial.txt diff --git a/AUTHORS b/AUTHORS index e2f33f5af..b30e0c33d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -30,6 +30,7 @@ Mateusz JÄ™drasik Matthew Schulkind (Google) Matt York (LifeMarks) Mohamad Fairol +Nikolaos Ftylitakis Paul Hackenberger Randy Shen (Acer) Rasmus Schrøder Sørensen diff --git a/symbian/QQrDecoder/CameraImageWrapper.cpp b/symbian/QQrDecoder/CameraImageWrapper.cpp new file mode 100644 index 000000000..e8ac50f2c --- /dev/null +++ b/symbian/QQrDecoder/CameraImageWrapper.cpp @@ -0,0 +1,77 @@ +#include "CameraImageWrapper.h" +#include +#include +#include + +CameraImageWrapper::CameraImageWrapper() : LuminanceSource() +{ +} + +CameraImageWrapper::CameraImageWrapper(CameraImageWrapper& otherInstance) : LuminanceSource() +{ + image = otherInstance.getOriginalImage().copy(); +} + +CameraImageWrapper::~CameraImageWrapper() +{ +} + +int CameraImageWrapper::getWidth() +{ + return image.width(); +} + +int CameraImageWrapper::getHeight() +{ + return image.height(); +} + +unsigned char CameraImageWrapper::getPixel(int x, int y) +{ + QRgb pixel = image.pixel(x,y); + + return qGray(pixel);//((qRed(pixel) + qGreen(pixel) + qBlue(pixel)) / 3); +} + +void CameraImageWrapper::setImage(QString fileName, char* format) +{ + image.load(fileName); + + if(image.width() > QApplication::desktop()->width()) + image = image.scaled(QApplication::desktop()->width(), image.height(), Qt::IgnoreAspectRatio); + + if(image.height() > QApplication::desktop()->height()) + image = image.scaled(image.width(), QApplication::desktop()->height(), Qt::IgnoreAspectRatio); +} + +void CameraImageWrapper::setImage(QImage newImage) +{ + image = newImage.copy(); + + if(image.width() > 640) + image = image.scaled(640, image.height(), Qt::KeepAspectRatio); +} + +QImage CameraImageWrapper::grayScaleImage(QImage::Format f) +{ + QImage tmp(image.width(), image.height(), f); + for(int i=0; i +#include +#include + +using namespace zxing; + +class CameraImageWrapper : public LuminanceSource +{ +public: + CameraImageWrapper(); + CameraImageWrapper(CameraImageWrapper& otherInstance); + ~CameraImageWrapper(); + + int getWidth(); + int getHeight(); + + unsigned char getPixel(int x, int y); + + void setImage(QString fileName, char* format); + void setImage(QImage newImage); + QImage grayScaleImage(QImage::Format f); + QImage getOriginalImage(); + +private: + QImage image; +}; + +#endif //CAMERAIMAGE_H diff --git a/symbian/QQrDecoder/Nokia_Licence.txt b/symbian/QQrDecoder/Nokia_Licence.txt new file mode 100644 index 000000000..758a74555 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/QCameraControllerWidget.cpp b/symbian/QQrDecoder/QCameraControllerWidget.cpp new file mode 100644 index 000000000..12f22c5b4 --- /dev/null +++ b/symbian/QQrDecoder/QCameraControllerWidget.cpp @@ -0,0 +1,322 @@ +#include "QCameraControllerWidget.h" +#include + +QCameraControllerWidget::QCameraControllerWidget(QWidget* parent) : QWidget(parent), +iCameraWrapper(NULL), iBackBuffer(NULL), iBackBufferDevice(NULL), iBackBufferContext(NULL) +{ + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(sendBackbufferToDecode())); + timer->start(500); +} + +QCameraControllerWidget::~QCameraControllerWidget() +{ + if (iCameraWrapper) + { + iCameraWrapper->ReleaseAndPowerOff(); + } + + delete iCameraWrapper; + + if(timer) + { + delete timer; + timer = NULL; + } + + ReleaseBackBuffer(); +} + +void QCameraControllerWidget::CaptureImage() +{ + if (iCameraWrapper && iCameraWrapper->State() == CCameraEngine::EEngineViewFinding) + { + emit logMessage("Capturing picture"); + iCameraWrapper->StopViewFinder(); + TRAPD(err,iCameraWrapper->CaptureL()); + if (err) + { + emit logMessage("Camera capture error"); + } + } +} + +void QCameraControllerWidget::paintEvent(QPaintEvent* event) +{ + if(iBackBuffer) + { + QPainter paint(this); + paint.drawPixmap(0,0,QPixmap::fromSymbianCFbsBitmap(iBackBuffer)); + } +} + +void QCameraControllerWidget::resizeEvent(QResizeEvent* event) +{ + static int savedWidth = 0; + static int savedHeight = 0; + + if(!savedWidth || !savedHeight) + { + InitializeCamera(); + savedWidth = geometry().width(); + savedHeight = geometry().height(); + } +} + +void QCameraControllerWidget::InitializeCamera() +{ + // 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 (geometry().width() > geometry().height()) + { + iViewFinderSize = TSize(geometry().width(),geometry().width()); + iCaptureSize = TSize(geometry().width(),geometry().width()); // Captured picture size + } + else + { + iViewFinderSize = TSize(geometry().height(), geometry().height()); + iCaptureSize = TSize(geometry().height(),geometry().height()); // Captured picture size + } + + // Create back buffer where recieved camera pictures are copied + ReleaseBackBuffer(); + CreateBackBufferL(); + + // Power on camera, start viewfinder when MceoCameraReady() received + if(camErr == KErrNone) + { + iCameraWrapper->ReserveAndPowerOn(); + emit logMessage("Camera power on"); + } + else + { + emit logMessage("no camera found"); + } +} + +void QCameraControllerWidget::CreateBackBufferL() +{ + // create back buffer bitmap + iBackBuffer = q_check_ptr(new CFbsBitmap); + + try{ + TSize size; + size.iHeight = this->geometry().height(); + size.iWidth = this->geometry().width(); + QT_TRAP_THROWING( iBackBuffer->Create(size,EColor64K)); + } + catch(std::exception& e) + { + + } + + // create back buffer graphics context + iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBuffer); + User::LeaveIfError(iBackBufferDevice->CreateContext(iBackBufferContext)); + iBackBufferContext->SetPenStyle(CGraphicsContext::ESolidPen); + + iBackBufferContext->SetBrushColor(KRgbBlack); + iBackBufferContext->Clear(); +} + +void QCameraControllerWidget::ReleaseBackBuffer() +{ + if (iBackBufferContext) + { + delete iBackBufferContext; + iBackBufferContext = NULL; + } + if (iBackBufferDevice) + { + delete iBackBufferDevice; + iBackBufferDevice = NULL; + } + if (iBackBuffer) + { + delete iBackBuffer; + iBackBuffer = NULL; + } +} + +void QCameraControllerWidget::MceoCameraReady() +{ + if (iCameraWrapper->State() == CCameraEngine::EEngineIdle) + { + // Prepare camera + TSize imageSize; + imageSize.iHeight = 480; + imageSize.iWidth = 640; + + CCamera::TFormat format = CCamera::EFormatFbsBitmapColor64K; + + TRAPD(err,iCameraWrapper->PrepareL(imageSize, format)); + if (err) + { + emit logMessage("Camera prepare error"); + return; + } + + // Start viewfinder. Viewfinder pictures starts coming into MceoViewFinderFrameReady(); + + TSize finderSize; + finderSize.iHeight = this->geometry().height(); + finderSize.iWidth = this->geometry().width(); + TRAPD(err2,iCameraWrapper->StartViewFinderL(finderSize)); + if (err2) + { + emit logMessage("Camera start viewfinder error"); + return; + } + + emit logMessage("Camera viewfinder started"); + } +} + +void QCameraControllerWidget::MceoFocusComplete() +{ + // CameraEngine state is EEngineIdle + emit logMessage("Focused"); + + // Capture picture after it has focused + iCameraWrapper->StopViewFinder(); + TRAPD(err,iCameraWrapper->CaptureL()); + if (err) + { + emit logMessage("Camera capture error"); + } +} + +void QCameraControllerWidget::MceoCapturedDataReady( TDesC8* aData ) +{ + +} + +void QCameraControllerWidget::MceoCapturedBitmapReady( CFbsBitmap* aBitmap ) +{ + if (iBackBufferContext) + { + emit logMessage("Succesfull capture"); + + QPixmap pix(QPixmap::fromSymbianCFbsBitmap(aBitmap)); + emit imageCaptured(pix.toImage()); + + TSize finderSize; + finderSize.iHeight = this->geometry().height(); + finderSize.iWidth = this->geometry().width(); + TRAPD(err2,iCameraWrapper->StartViewFinderL(finderSize)); + if (err2) + { + emit logMessage("Camera start viewfinder error"); + return; + } + } + if (iCameraWrapper) + iCameraWrapper->ReleaseImageBuffer(); +} + +void QCameraControllerWidget::MceoViewFinderFrameReady( CFbsBitmap& aFrame ) +{ + if (iBackBufferContext) + { + TSize bmpSizeInPixels = aFrame.SizeInPixels(); + TInt xDelta = 0; + TInt yDelta = 0; + TPoint pos( xDelta, yDelta ); + + // Copy received viewfinder picture to back buffer + iBackBufferContext->BitBlt( pos, &aFrame, TRect( TPoint( 0, 0 ), bmpSizeInPixels )); + + // Update backbuffer into screen + update(); + } + if (iCameraWrapper) + iCameraWrapper->ReleaseViewFinderBuffer(); +} + +void QCameraControllerWidget::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: + { + emit logMessage("Camera reserved error"); + break; + } + case EErrPowerOn: + { + emit logMessage("Camera power on error"); + break; + } + case EErrViewFinderReady: + { + emit logMessage("Camera viewfinder error"); + break; + } + case EErrImageReady: + { + emit logMessage("Camera image ready error"); + break; + } + case EErrAutoFocusInit: + case EErrAutoFocusMode: + case EErrAutoFocusArea: + case EErrAutoFocusRange: + case EErrAutoFocusType: + case EErrOptimisedFocusComplete: + { + //emit logMessage("Try focusing again"); + break; + } + default: + { + emit logMessage("Unknown error"); + break; + } + }; + + // Try handle error + //CancelCapturedPicture(EFalse); + // iAppUi->UseOptionsExitCbaL(); +} + +void QCameraControllerWidget::MceoHandleOtherEvent( const TECAMEvent& /*aEvent*/ ) +{ +} + +//Timer slot +void QCameraControllerWidget::sendBackbufferToDecode() +{ + if(!iBackBuffer) + return; + + QPixmap pix(QPixmap::fromSymbianCFbsBitmap(iBackBuffer)); + emit imageCaptured(pix.toImage()); + + if(timer) + timer->start(500); +} + diff --git a/symbian/QQrDecoder/QCameraControllerWidget.h b/symbian/QQrDecoder/QCameraControllerWidget.h new file mode 100644 index 000000000..ae0e38d0d --- /dev/null +++ b/symbian/QQrDecoder/QCameraControllerWidget.h @@ -0,0 +1,67 @@ +#ifndef QCAMERACONTROLLER_H +#define QCAMERACONTROLLER_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +class QCameraControllerWidget : public QWidget, public MCameraEngineObserver +{ + Q_OBJECT + +public: + QCameraControllerWidget(QWidget* parent); + ~QCameraControllerWidget(); + +protected: + void paintEvent(QPaintEvent* event); + void resizeEvent(QResizeEvent* event); + +private: // From MCameraEngineObserver + void CreateBackBufferL(); + void ReleaseBackBuffer(); + + 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*/ ); + void InitializeCamera(); + +//////////////////////// +public slots: + void CaptureImage(); + +private slots: + void sendBackbufferToDecode(); + +signals: + void logMessage(QString str); + void imageCaptured(QImage cImage); + +private: + // CameraWrapper class + CCameraEngine* iCameraWrapper; + + CFbsBitmap* iBackBuffer; + CFbsBitmapDevice* iBackBufferDevice; + CFbsBitGc* iBackBufferContext; + + TSize iViewFinderSize; + TSize iCaptureSize; + + //Timer + QTimer* timer; +}; + +#endif //QCAMERACONTROLLER_H diff --git a/symbian/QQrDecoder/QQrDecoder.cpp b/symbian/QQrDecoder/QQrDecoder.cpp new file mode 100644 index 000000000..a20ad1fa4 --- /dev/null +++ b/symbian/QQrDecoder/QQrDecoder.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** + ** + ** Trolltech hereby grants a license to use the Qt/Eclipse Integration + ** plug-in (the software contained herein), in binary form, solely for the + ** purpose of creating code to be used with Trolltech's Qt software. + ** + ** Qt Designer is licensed under the terms of the GNU General Public + ** License versions 2.0 and 3.0 ("GPL License"). Trolltech offers users the + ** right to use certain no GPL licensed software under the terms of its GPL + ** Exception version 1.2 (http://trolltech.com/products/qt/gplexception). + ** + ** THIS SOFTWARE IS PROVIDED BY TROLLTECH AND ITS CONTRIBUTORS (IF ANY) "AS + ** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + ** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** + ** Since we now have the GPL exception I think that the "special exception + ** is no longer needed. The license text proposed above (other than the + ** special exception portion of it) is the BSD license and we have added + ** the BSD license as a permissible license under the exception. + ** + ****************************************************************************/ + +#include "QQrDecoder.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace zxing; +using namespace zxing::qrcode; + +QQrDecoder::QQrDecoder(QWidget *parent): QMainWindow(parent) +{ + ui.setupUi(this); + connect(ui.startDecode, SIGNAL(clicked()), this, SLOT(findAndDecode())); + connect(ui.cameraWidget, SIGNAL(imageCaptured(QImage)), this, SLOT(decodeImage(QImage))); + connect(ui.cameraWidget, SIGNAL(logMessage(QString)), ui.resultLabel, SLOT(setText(QString))); +} + +QQrDecoder::~QQrDecoder() +{ +} + +void QQrDecoder::InitializeSymbianCamera() +{ + +} + +void QQrDecoder::findAndDecode() +{ + ui.cameraWidget->CaptureImage(); +} + +void QQrDecoder::decodeImage(QImage originalImage) +{ + QRCodeReader decoder; + + image.setImage(originalImage); + + Ref res; + + try{ + Ref imageRef(new CameraImageWrapper(image)); + GlobalHistogramBinarizer* binz = new GlobalHistogramBinarizer(imageRef); + + Ref bz (binz); + BinaryBitmap* bb = new BinaryBitmap(bz); + + Ref ref(bb); + + res = decoder.decode(ref); + + QString string = QString(res->getText()->getText().c_str()); + ui.resultLabel->setText(string); + } + catch(zxing::Exception& e) + { + ui.resultLabel->setText("Error"); + } +} + +void QQrDecoder::reloadFormatedPicture(int x) +{ +} + diff --git a/symbian/QQrDecoder/QQrDecoder.h b/symbian/QQrDecoder/QQrDecoder.h new file mode 100644 index 000000000..ecdfff228 --- /dev/null +++ b/symbian/QQrDecoder/QQrDecoder.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Trolltech hereby grants a license to use the Qt/Eclipse Integration +** plug-in (the software contained herein), in binary form, solely for the +** purpose of creating code to be used with Trolltech's Qt software. +** +** Qt Designer is licensed under the terms of the GNU General Public +** License versions 2.0 and 3.0 ("GPL License"). Trolltech offers users the +** right to use certain no GPL licensed software under the terms of its GPL +** Exception version 1.2 (http://trolltech.com/products/qt/gplexception). +** +** THIS SOFTWARE IS PROVIDED BY TROLLTECH AND ITS CONTRIBUTORS (IF ANY) "AS +** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** Since we now have the GPL exception I think that the "special exception +** is no longer needed. The license text proposed above (other than the +** special exception portion of it) is the BSD license and we have added +** the BSD license as a permissible license under the exception. +** +****************************************************************************/ + +#ifndef QQRDECODER_H +#define QQRDECODER_H + +#include +#include +#include "ui_QQrDecoder.h" + +#include "CameraImageWrapper.h" + +class QQrDecoder : public QMainWindow +{ + Q_OBJECT + +public: + QQrDecoder(QWidget *parent = 0); + ~QQrDecoder(); + +private: + void InitializeSymbianCamera(); + +protected slots: + void findAndDecode(); + void decodeImage(QImage originalImage); + void reloadFormatedPicture(int x); + +private: + Ui::QQrDecoder ui; + CameraImageWrapper image; + QPixmap px; +}; + +#endif // QQRDECODER_H diff --git a/symbian/QQrDecoder/QQrDecoder.pro b/symbian/QQrDecoder/QQrDecoder.pro new file mode 100644 index 000000000..8db037323 --- /dev/null +++ b/symbian/QQrDecoder/QQrDecoder.pro @@ -0,0 +1,159 @@ +TEMPLATE = app +TARGET = QQrDecoder +QT += core \ + gui +HEADERS += CameraImageWrapper.h \ + zxing/BarcodeFormat.h \ + zxing/Binarizer.h \ + zxing/BinaryBitmap.h \ + zxing/Exception.h \ + zxing/LuminanceSource.h \ + zxing/MultiFormatReader.h \ + zxing/Reader.h \ + zxing/ReaderException.h \ + zxing/Result.h \ + zxing/ResultPoint.h \ + zxing/common/Array.h \ + zxing/common/BitArray.h \ + zxing/common/BitMatrix.h \ + zxing/common/BitSource.h \ + zxing/common/Counted.h \ + zxing/common/DecoderResult.h \ + zxing/common/DetectorResult.h \ + zxing/common/EdgeDetector.h \ + zxing/common/GlobalHistogramBinarizer.h \ + zxing/common/GridSampler.h \ + zxing/common/IllegalArgumentException.h \ + zxing/common/LocalBlockBinarizer.h \ + zxing/common/PerspectiveTransform.h \ + zxing/common/Point.h \ + zxing/common/Str.h \ + zxing/common/reedsolomon/GF256.h \ + zxing/common/reedsolomon/GF256Poly.h \ + zxing/common/reedsolomon/ReedSolomonDecoder.h \ + zxing/common/reedsolomon/ReedSolomonException.h \ + zxing/oned/Code128Reader.h \ + zxing/oned/Code39Reader.h \ + zxing/oned/EAN13Reader.h \ + zxing/oned/EAN8Reader.h \ + zxing/oned/ITFReader.h \ + zxing/oned/MultiFormatOneDReader.h \ + zxing/oned/MultiFormatUPCEANReader.h \ + zxing/oned/OneDReader.h \ + zxing/oned/OneDResultPoint.h \ + zxing/oned/UPCAReader.h \ + zxing/oned/UPCEANReader.h \ + zxing/oned/UPCEReader.h \ + zxing/qrcode/ErrorCorrectionLevel.h \ + zxing/qrcode/FormatInformation.h \ + zxing/qrcode/QRCodeReader.h \ + zxing/qrcode/Version.h \ + zxing/qrcode/decoder/BitMatrixParser.h \ + zxing/qrcode/decoder/DataBlock.h \ + zxing/qrcode/decoder/DataMask.h \ + zxing/qrcode/decoder/DecodedBitStreamParser.h \ + zxing/qrcode/decoder/Decoder.h \ + zxing/qrcode/decoder/Mode.h \ + zxing/qrcode/detector/AlignmentPattern.h \ + zxing/qrcode/detector/AlignmentPatternFinder.h \ + zxing/qrcode/detector/Detector.h \ + zxing/qrcode/detector/FinderPattern.h \ + zxing/qrcode/detector/FinderPatternFinder.h \ + zxing/qrcode/detector/FinderPatternInfo.h \ + zxing/qrcode/detector/QREdgeDetector.h \ + QQrDecoder.loc \ + QQrDecoder.h +SOURCES += CameraImageWrapper.cpp \ + zxing/BarcodeFormat.cpp \ + zxing/Binarizer.cpp \ + zxing/BinaryBitmap.cpp \ + zxing/Exception.cpp \ + zxing/LuminanceSource.cpp \ + zxing/MultiFormatReader.cpp \ + zxing/Reader.cpp \ + zxing/ReaderException.cpp \ + zxing/Result.cpp \ + zxing/ResultPoint.cpp \ + zxing/common/Array.cpp \ + zxing/common/BitArray.cpp \ + zxing/common/BitMatrix.cpp \ + zxing/common/BitSource.cpp \ + zxing/common/Counted.cpp \ + zxing/common/DecoderResult.cpp \ + zxing/common/DetectorResult.cpp \ + zxing/common/EdgeDetector.cpp \ + zxing/common/GlobalHistogramBinarizer.cpp \ + zxing/common/GridSampler.cpp \ + zxing/common/IllegalArgumentException.cpp \ + zxing/common/LocalBlockBinarizer.cpp \ + zxing/common/PerspectiveTransform.cpp \ + zxing/common/Str.cpp \ + zxing/common/reedsolomon/GF256.cpp \ + zxing/common/reedsolomon/GF256Poly.cpp \ + zxing/common/reedsolomon/ReedSolomonDecoder.cpp \ + zxing/common/reedsolomon/ReedSolomonException.cpp \ + zxing/oned/Code128Reader.cpp \ + zxing/oned/Code39Reader.cpp \ + zxing/oned/EAN13Reader.cpp \ + zxing/oned/EAN8Reader.cpp \ + zxing/oned/ITFReader.cpp \ + zxing/oned/MultiFormatOneDReader.cpp \ + zxing/oned/MultiFormatUPCEANReader.cpp \ + zxing/oned/OneDReader.cpp \ + zxing/oned/OneDResultPoint.cpp \ + zxing/oned/UPCAReader.cpp \ + zxing/oned/UPCEANReader.cpp \ + zxing/oned/UPCEReader.cpp \ + zxing/qrcode/ErrorCorrectionLevel.cpp \ + zxing/qrcode/FormatInformation.cpp \ + zxing/qrcode/QRCodeReader.cpp \ + zxing/qrcode/Version.cpp \ + zxing/qrcode/decoder/BitMatrixParser.cpp \ + zxing/qrcode/decoder/DataBlock.cpp \ + zxing/qrcode/decoder/DataMask.cpp \ + zxing/qrcode/decoder/DecodedBitStreamParser.cpp \ + zxing/qrcode/decoder/Decoder.cpp \ + zxing/qrcode/decoder/Mode.cpp \ + zxing/qrcode/detector/AlignmentPattern.cpp \ + zxing/qrcode/detector/AlignmentPatternFinder.cpp \ + zxing/qrcode/detector/Detector.cpp \ + zxing/qrcode/detector/FinderPattern.cpp \ + zxing/qrcode/detector/FinderPatternFinder.cpp \ + zxing/qrcode/detector/FinderPatternInfo.cpp \ + zxing/qrcode/detector/QREdgeDetector.cpp \ + QQrDecoder.rss \ + QQrDecoder_reg.rss \ + main.cpp \ + QQrDecoder.cpp +FORMS += QQrDecoder.ui +RESOURCES += +symbian { + TARGET.UID3 = 0xEF2CE79D + HEADERS += QCameraControllerWidget.h + SOURCES += QCameraControllerWidget.cpp + LIBS += -leuser \ + -lapparc \ + -lcone \ + -leikcore \ + -lavkon \ + -lcommonengine \ + -lefsrv \ + -lestor \ + -laknnotify \ + -lfbscli \ + -lbitgdi \ + -leikcoctl \ + -lbafl \ # BafUtils + -lecam \ # Camera + -lcamerawrapper + TARGET.CAPABILITY = UserEnvironment + + customrules.pkg_prerules = \ + ";CameraWrapper" \ + "@\"$(EPOCROOT)Epoc32\InstallToDevice\CameraWrapper\sis\camerawrapper.sisx\", (0x2001ec5f)" \ + " " + + DEPLOYMENT += customrules +} + +ICON = QQrDecoder.svg diff --git a/symbian/QQrDecoder/QQrDecoder.svg b/symbian/QQrDecoder/QQrDecoder.svg new file mode 100644 index 000000000..3bd9d64ae --- /dev/null +++ b/symbian/QQrDecoder/QQrDecoder.svg @@ -0,0 +1,91 @@ + + + + + + diff --git a/symbian/QQrDecoder/QQrDecoder.ui b/symbian/QQrDecoder/QQrDecoder.ui new file mode 100644 index 000000000..c691a66a9 --- /dev/null +++ b/symbian/QQrDecoder/QQrDecoder.ui @@ -0,0 +1,54 @@ + + + QQrDecoder + + + + 0 + 0 + 340 + 640 + + + + QQrDecoder + + + + + + + Capture And Decode + + + + + + + + 0 + 0 + + + + No result + + + + + + + + + + + + QCameraControllerWidget + QWidget +
qcameracontrollerwidget.h
+ 1 +
+
+ + +
diff --git a/symbian/QQrDecoder/QQrDecoder_template.sisx b/symbian/QQrDecoder/QQrDecoder_template.sisx new file mode 100644 index 0000000000000000000000000000000000000000..dbf497dd2b9440dab676f77ff84e20c621d5f3ce GIT binary patch literal 180076 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

;4+$4V>(~sTI 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

    -QO_`AN&txUq55vG&oO!=P+kBTs@NE4^p? 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 pk8vKG=Tm$^|&> literal 0 HcmV?d00001 diff --git a/symbian/QQrDecoder/camerawrapper/epoc32/include/cameraengine.h b/symbian/QQrDecoder/camerawrapper/epoc32/include/cameraengine.h new file mode 100644 index 000000000..d802fb377 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/include/cameraengineobserver.h b/symbian/QQrDecoder/camerawrapper/epoc32/include/cameraengineobserver.h new file mode 100644 index 000000000..832dfc1c1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper.dso b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper.lib b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.dso b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/armv5/lib/camerawrapper{000a0000}.lib b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/armv5/urel/camerawrapper.dll b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/CamAutoFocus.dll b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.dll b/symbian/QQrDecoder/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/QQrDecoder/camerawrapper/epoc32/release/winscw/udeb/camerawrapper.lib b/symbian/QQrDecoder/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 + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QQrDecoder w; + w.showMaximized(); + return a.exec(); +} diff --git a/symbian/QQrDecoder/zxing/BarcodeFormat.cpp b/symbian/QQrDecoder/zxing/BarcodeFormat.cpp new file mode 100644 index 000000000..b31afccf1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/BarcodeFormat.h b/symbian/QQrDecoder/zxing/BarcodeFormat.h new file mode 100644 index 000000000..943831dad --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Binarizer.cpp b/symbian/QQrDecoder/zxing/Binarizer.cpp new file mode 100644 index 000000000..5f6e746bc --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Binarizer.h b/symbian/QQrDecoder/zxing/Binarizer.h new file mode 100644 index 000000000..ea1240c0b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/BinaryBitmap.cpp b/symbian/QQrDecoder/zxing/BinaryBitmap.cpp new file mode 100644 index 000000000..1e692a9f5 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/BinaryBitmap.h b/symbian/QQrDecoder/zxing/BinaryBitmap.h new file mode 100644 index 000000000..ecd9a8549 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Exception.cpp b/symbian/QQrDecoder/zxing/Exception.cpp new file mode 100644 index 000000000..47143c964 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Exception.h b/symbian/QQrDecoder/zxing/Exception.h new file mode 100644 index 000000000..7502c5cb6 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/LuminanceSource.cpp b/symbian/QQrDecoder/zxing/LuminanceSource.cpp new file mode 100644 index 000000000..6c8ef1e6e --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/LuminanceSource.h b/symbian/QQrDecoder/zxing/LuminanceSource.h new file mode 100644 index 000000000..e23621ef9 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/MultiFormatReader.cpp b/symbian/QQrDecoder/zxing/MultiFormatReader.cpp new file mode 100644 index 000000000..2270ebeca --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/MultiFormatReader.h b/symbian/QQrDecoder/zxing/MultiFormatReader.h new file mode 100644 index 000000000..ff51c01c2 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; +} diff --git a/symbian/QQrDecoder/zxing/Reader.cpp b/symbian/QQrDecoder/zxing/Reader.cpp new file mode 100644 index 000000000..1e1fdc39b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Reader.h b/symbian/QQrDecoder/zxing/Reader.h new file mode 100644 index 000000000..3de270f95 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/ReaderException.cpp b/symbian/QQrDecoder/zxing/ReaderException.cpp new file mode 100644 index 000000000..7d2bc9d98 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/ReaderException.h b/symbian/QQrDecoder/zxing/ReaderException.h new file mode 100644 index 000000000..1a31ae8e9 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Result.cpp b/symbian/QQrDecoder/zxing/Result.cpp new file mode 100644 index 000000000..f87ef8844 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/Result.h b/symbian/QQrDecoder/zxing/Result.h new file mode 100644 index 000000000..710d8d5a6 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/ResultPoint.cpp b/symbian/QQrDecoder/zxing/ResultPoint.cpp new file mode 100644 index 000000000..464956873 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/ResultPoint.h b/symbian/QQrDecoder/zxing/ResultPoint.h new file mode 100644 index 000000000..6118cc0dc --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Array.cpp b/symbian/QQrDecoder/zxing/common/Array.cpp new file mode 100644 index 000000000..aa1834a27 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Array.h b/symbian/QQrDecoder/zxing/common/Array.h new file mode 100644 index 000000000..39b178607 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitArray.cpp b/symbian/QQrDecoder/zxing/common/BitArray.cpp new file mode 100644 index 000000000..26e686930 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitArray.h b/symbian/QQrDecoder/zxing/common/BitArray.h new file mode 100644 index 000000000..1e8828e96 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitMatrix.cpp b/symbian/QQrDecoder/zxing/common/BitMatrix.cpp new file mode 100644 index 000000000..9256c4097 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitMatrix.h b/symbian/QQrDecoder/zxing/common/BitMatrix.h new file mode 100644 index 000000000..e8f8f847e --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitSource.cpp b/symbian/QQrDecoder/zxing/common/BitSource.cpp new file mode 100644 index 000000000..4b53b4da7 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/BitSource.h b/symbian/QQrDecoder/zxing/common/BitSource.h new file mode 100644 index 000000000..78201738f --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Counted.cpp b/symbian/QQrDecoder/zxing/common/Counted.cpp new file mode 100644 index 000000000..fb2a99b06 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Counted.h b/symbian/QQrDecoder/zxing/common/Counted.h new file mode 100644 index 000000000..c2723996b --- /dev/null +++ b/symbian/QQrDecoder/zxing/common/Counted.h @@ -0,0 +1,204 @@ +#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 +using namespace std; +#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/QQrDecoder/zxing/common/DecoderResult.cpp b/symbian/QQrDecoder/zxing/common/DecoderResult.cpp new file mode 100644 index 000000000..86b11f810 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/DecoderResult.h b/symbian/QQrDecoder/zxing/common/DecoderResult.h new file mode 100644 index 000000000..1e3e42b2a --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/DetectorResult.cpp b/symbian/QQrDecoder/zxing/common/DetectorResult.cpp new file mode 100644 index 000000000..a314cfe79 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/DetectorResult.h b/symbian/QQrDecoder/zxing/common/DetectorResult.h new file mode 100644 index 000000000..ba8f9a821 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/EdgeDetector.cpp b/symbian/QQrDecoder/zxing/common/EdgeDetector.cpp new file mode 100644 index 000000000..3f0b403cc --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/EdgeDetector.h b/symbian/QQrDecoder/zxing/common/EdgeDetector.h new file mode 100644 index 000000000..3698c1c8b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp b/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.cpp new file mode 100644 index 000000000..8767dbd34 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/GlobalHistogramBinarizer.h b/symbian/QQrDecoder/zxing/common/GlobalHistogramBinarizer.h new file mode 100644 index 000000000..6735c5b9f --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/GridSampler.cpp b/symbian/QQrDecoder/zxing/common/GridSampler.cpp new file mode 100644 index 000000000..06bb602c1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/GridSampler.h b/symbian/QQrDecoder/zxing/common/GridSampler.h new file mode 100644 index 000000000..3dd577dcb --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/IllegalArgumentException.cpp b/symbian/QQrDecoder/zxing/common/IllegalArgumentException.cpp new file mode 100644 index 000000000..49068ca5d --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/IllegalArgumentException.h b/symbian/QQrDecoder/zxing/common/IllegalArgumentException.h new file mode 100644 index 000000000..5def73636 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/LocalBlockBinarizer.cpp b/symbian/QQrDecoder/zxing/common/LocalBlockBinarizer.cpp new file mode 100644 index 000000000..135902a6d --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/LocalBlockBinarizer.h b/symbian/QQrDecoder/zxing/common/LocalBlockBinarizer.h new file mode 100644 index 000000000..bae80bc75 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/PerspectiveTransform.cpp b/symbian/QQrDecoder/zxing/common/PerspectiveTransform.cpp new file mode 100644 index 000000000..44d9ddcb0 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/PerspectiveTransform.h b/symbian/QQrDecoder/zxing/common/PerspectiveTransform.h new file mode 100644 index 000000000..581f92880 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Point.h b/symbian/QQrDecoder/zxing/common/Point.h new file mode 100644 index 000000000..a391042fe --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Str.cpp b/symbian/QQrDecoder/zxing/common/Str.cpp new file mode 100644 index 000000000..e2122dc3a --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/Str.h b/symbian/QQrDecoder/zxing/common/Str.h new file mode 100644 index 000000000..255a05531 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/GF256.cpp b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.cpp new file mode 100644 index 000000000..8add88934 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/GF256.h b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256.h new file mode 100644 index 000000000..0930f63bf --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/GF256Poly.cpp b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256Poly.cpp new file mode 100644 index 000000000..2c7f4812e --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/GF256Poly.h b/symbian/QQrDecoder/zxing/common/reedsolomon/GF256Poly.h new file mode 100644 index 000000000..e036f29c0 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.cpp b/symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.cpp new file mode 100644 index 000000000..58a95a8e1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.h b/symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonDecoder.h new file mode 100644 index 000000000..f7c534ba7 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.cpp b/symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.cpp new file mode 100644 index 000000000..20af025bb --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.h b/symbian/QQrDecoder/zxing/common/reedsolomon/ReedSolomonException.h new file mode 100644 index 000000000..ec0df95ce --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/Code128Reader.cpp b/symbian/QQrDecoder/zxing/oned/Code128Reader.cpp new file mode 100644 index 000000000..943a57481 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/Code128Reader.h b/symbian/QQrDecoder/zxing/oned/Code128Reader.h new file mode 100644 index 000000000..ad191aa0d --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/Code39Reader.cpp b/symbian/QQrDecoder/zxing/oned/Code39Reader.cpp new file mode 100644 index 000000000..cb03dd9ac --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/Code39Reader.h b/symbian/QQrDecoder/zxing/oned/Code39Reader.h new file mode 100644 index 000000000..1846761a6 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/EAN13Reader.cpp b/symbian/QQrDecoder/zxing/oned/EAN13Reader.cpp new file mode 100644 index 000000000..0e3de9731 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/EAN13Reader.h b/symbian/QQrDecoder/zxing/oned/EAN13Reader.h new file mode 100644 index 000000000..381d6e928 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/EAN8Reader.cpp b/symbian/QQrDecoder/zxing/oned/EAN8Reader.cpp new file mode 100644 index 000000000..5c34c9fe2 --- /dev/null +++ b/symbian/QQrDecoder/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; + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/EAN8Reader.h b/symbian/QQrDecoder/zxing/oned/EAN8Reader.h new file mode 100644 index 000000000..f7008562c --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/ITFReader.cpp b/symbian/QQrDecoder/zxing/oned/ITFReader.cpp new file mode 100644 index 000000000..7febab090 --- /dev/null +++ b/symbian/QQrDecoder/zxing/oned/ITFReader.cpp @@ -0,0 +1,355 @@ +/* + * 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]; + int* pattern = new int(countersLen); + for(int ind = 0; ind= 0) { + return bestMatch; + } else { + throw ReaderException("digit didint found"); + } + } + + + ITFReader::~ITFReader(){ + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/ITFReader.h b/symbian/QQrDecoder/zxing/oned/ITFReader.h new file mode 100644 index 000000000..759d84144 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/MultiFormatOneDReader.cpp b/symbian/QQrDecoder/zxing/oned/MultiFormatOneDReader.cpp new file mode 100644 index 000000000..245003b1d --- /dev/null +++ b/symbian/QQrDecoder/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; + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/MultiFormatOneDReader.h b/symbian/QQrDecoder/zxing/oned/MultiFormatOneDReader.h new file mode 100644 index 000000000..5320924f6 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.cpp b/symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.cpp new file mode 100644 index 000000000..21045e3b1 --- /dev/null +++ b/symbian/QQrDecoder/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; + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.h b/symbian/QQrDecoder/zxing/oned/MultiFormatUPCEANReader.h new file mode 100644 index 000000000..2021bb5f1 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/OneDReader.cpp b/symbian/QQrDecoder/zxing/oned/OneDReader.cpp new file mode 100644 index 000000000..0b557d625 --- /dev/null +++ b/symbian/QQrDecoder/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() { + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/OneDReader.h b/symbian/QQrDecoder/zxing/oned/OneDReader.h new file mode 100644 index 000000000..92a7e779b --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/OneDResultPoint.cpp b/symbian/QQrDecoder/zxing/oned/OneDResultPoint.cpp new file mode 100644 index 000000000..272319dbf --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/OneDResultPoint.h b/symbian/QQrDecoder/zxing/oned/OneDResultPoint.h new file mode 100644 index 000000000..1b07b772c --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/UPCAReader.cpp b/symbian/QQrDecoder/zxing/oned/UPCAReader.cpp new file mode 100644 index 000000000..8757b2ace --- /dev/null +++ b/symbian/QQrDecoder/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; + } + } +} diff --git a/symbian/QQrDecoder/zxing/oned/UPCAReader.h b/symbian/QQrDecoder/zxing/oned/UPCAReader.h new file mode 100644 index 000000000..056295245 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp b/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp new file mode 100644 index 000000000..e9bfa1795 --- /dev/null +++ b/symbian/QQrDecoder/zxing/oned/UPCEANReader.cpp @@ -0,0 +1,316 @@ +/* + * 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* counters = new int(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; + } + } + delete counters; + 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]; + int* pattern = new int(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; + } + delete pattern; + } + 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]; + int* pattern = new int(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; + } + delete pattern; + } + 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/QQrDecoder/zxing/oned/UPCEANReader.h b/symbian/QQrDecoder/zxing/oned/UPCEANReader.h new file mode 100644 index 000000000..3a39cf9db --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/oned/UPCEReader.cpp b/symbian/QQrDecoder/zxing/oned/UPCEReader.cpp new file mode 100644 index 000000000..3738d4c6b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/oned/UPCEReader.h b/symbian/QQrDecoder/zxing/oned/UPCEReader.h new file mode 100644 index 000000000..7daa87ac9 --- /dev/null +++ b/symbian/QQrDecoder/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(); + }; + } +} diff --git a/symbian/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.cpp b/symbian/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.cpp new file mode 100644 index 000000000..9c610b526 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.h b/symbian/QQrDecoder/zxing/qrcode/ErrorCorrectionLevel.h new file mode 100644 index 000000000..426d204cf --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/FormatInformation.cpp b/symbian/QQrDecoder/zxing/qrcode/FormatInformation.cpp new file mode 100644 index 000000000..41332fb0f --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/FormatInformation.h b/symbian/QQrDecoder/zxing/qrcode/FormatInformation.h new file mode 100644 index 000000000..cad027a01 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/QRCodeReader.cpp b/symbian/QQrDecoder/zxing/qrcode/QRCodeReader.cpp new file mode 100644 index 000000000..f3843eca1 --- /dev/null +++ b/symbian/QQrDecoder/zxing/qrcode/QRCodeReader.cpp @@ -0,0 +1,84 @@ +/* + * 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" ; +#endif + + Detector detector(image->getBlackMatrix()); + + +#ifdef DEBUG + cout << "(1) created detector " << &detector << "\n" ; +#endif + + Ref detectorResult(detector.detect()); +#ifdef DEBUG + cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" ; +#endif + + std::vector > points(detectorResult->getPoints()); + + +#ifdef DEBUG + cout << "(3) extracted points " << &points << "\n"; + 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" ; +#endif + + Ref result( + new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_QR_CODE)); +#ifdef DEBUG + cout << "(5) created result " << result.object_ << ", returning\n" ; + + cout << "(6) text: " << result->getText()->getText() << std::endl; +#endif + + return result; + } + + QRCodeReader::~QRCodeReader() { + } + + } +} diff --git a/symbian/QQrDecoder/zxing/qrcode/QRCodeReader.h b/symbian/QQrDecoder/zxing/qrcode/QRCodeReader.h new file mode 100644 index 000000000..8257c7a39 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/Version.cpp b/symbian/QQrDecoder/zxing/qrcode/Version.cpp new file mode 100644 index 000000000..5e63c8271 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/Version.h b/symbian/QQrDecoder/zxing/qrcode/Version.h new file mode 100644 index 000000000..181bd98fe --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.cpp new file mode 100644 index 000000000..e4ef5e2d8 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.h b/symbian/QQrDecoder/zxing/qrcode/decoder/BitMatrixParser.h new file mode 100644 index 000000000..824556b93 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DataBlock.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/DataBlock.cpp new file mode 100644 index 000000000..1ea6602d7 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DataBlock.h b/symbian/QQrDecoder/zxing/qrcode/decoder/DataBlock.h new file mode 100644 index 000000000..df536f4d6 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DataMask.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/DataMask.cpp new file mode 100644 index 000000000..9b293b13c --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DataMask.h b/symbian/QQrDecoder/zxing/qrcode/decoder/DataMask.h new file mode 100644 index 000000000..c4a3e0ccf --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.cpp new file mode 100644 index 000000000..ab32b2e8c --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.h b/symbian/QQrDecoder/zxing/qrcode/decoder/DecodedBitStreamParser.h new file mode 100644 index 000000000..8c4ab9bb3 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/Decoder.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/Decoder.cpp new file mode 100644 index 000000000..13023131d --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/Decoder.h b/symbian/QQrDecoder/zxing/qrcode/decoder/Decoder.h new file mode 100644 index 000000000..96e1dc0cc --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/Mode.cpp b/symbian/QQrDecoder/zxing/qrcode/decoder/Mode.cpp new file mode 100644 index 000000000..5a6eb4aa5 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/decoder/Mode.h b/symbian/QQrDecoder/zxing/qrcode/decoder/Mode.h new file mode 100644 index 000000000..28708a94b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.cpp new file mode 100644 index 000000000..0f6ee592b --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.h b/symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPattern.h new file mode 100644 index 000000000..56a683f95 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.cpp new file mode 100644 index 000000000..b3d92d40c --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.h b/symbian/QQrDecoder/zxing/qrcode/detector/AlignmentPatternFinder.h new file mode 100644 index 000000000..266364316 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/Detector.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/Detector.cpp new file mode 100644 index 000000000..dc8090bdf --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/Detector.h b/symbian/QQrDecoder/zxing/qrcode/detector/Detector.h new file mode 100644 index 000000000..98eed51e9 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPattern.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPattern.cpp new file mode 100644 index 000000000..531d4e2a1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPattern.h b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPattern.h new file mode 100644 index 000000000..0b6615c81 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.cpp new file mode 100644 index 000000000..666c4f210 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.h b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternFinder.h new file mode 100644 index 000000000..e1fc9ce7f --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.cpp new file mode 100644 index 000000000..088a0e760 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.h b/symbian/QQrDecoder/zxing/qrcode/detector/FinderPatternInfo.h new file mode 100644 index 000000000..287a8d17d --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.cpp b/symbian/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.cpp new file mode 100644 index 000000000..18affe6e1 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.h b/symbian/QQrDecoder/zxing/qrcode/detector/QREdgeDetector.h new file mode 100644 index 000000000..f5cdc89e3 --- /dev/null +++ b/symbian/QQrDecoder/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/QQrDecoder_tutorial.txt b/symbian/QQrDecoder_tutorial.txt new file mode 100644 index 000000000..d7f6cfb4c --- /dev/null +++ b/symbian/QQrDecoder_tutorial.txt @@ -0,0 +1,58 @@ +This project is the same as ZXingBarcodeReader. The difference is that the GUI is +developed using Qt framework. This means that it can easily be ported to other platforms +supported by Qt by simply changing the camera operations implemented in "QCameraControllerWidget" +which is Symbian specific code. + +Also the advantage of this implementation over "ZXingBarcodeReader" is that the code written is +more readable and familiar to users that have never used Qt framework or Symbian C++ before. + +== Prerequisities == + +* Have at least one S60 SDK. One of the SDKs can be obtained from here: + http://www.forum.nokia.com/info/sw.nokia.com/id/ec866fab-4b76-49f6-b5a5-af0631419e9c/S60_All_in_One_SDKs.html + +* After installing S60 SDK you have to install OpenC++. + http://www.forum.nokia.com/info/sw.nokia.com/id/91d89929-fb8c-4d66-bea0-227e42df9053/Open_C_SDK_Plug-In.html + +* Next step, have "Qt for Symbian" installed. It under LGLP licence. + http://qt.nokia.com/downloads/symbian-cpp + +* (Optional) You can use Carbide C++ as IDE which makes the life a bit easier on creating applications for Symbian. + An alternative approach is to compile the program in command line but i am afraid i can help you here because i + have no idea :P +or + You can use Qt Creator (see its tutorials on how to use it) + http://qt.nokia.com/products/developer-tools/developer-tools + +== Create project == +If you have Carbide C++ IDE then go "File->Import->Qt->Qt Project", +click "Browse" and find and select file "QQrDecoder\QQrDecoder.pro". +Next step you select the S60 SDK to be compiled to and you are ready. + +== Build project == +Since the project is created, we can proceed to build it. + +First in "QQrDecoder\camerawrapper" folder there is a folder named "epoc32". +Copy this folder and paste it to the root folder of the S60 SDK that you are going to use +(in my case: C:\S60\devices\S60_5th_Edition_SDK_v1.0). This step is important in order +to use a Plug-In API for the easier manipulation of the camera. + +Now we are ready to compile. Since the camera is not supported in the Symbian emulator we +will build the project directly to be installed on a devidce. +Select "QQrDecoder" project in the "Project Explorer" view in Carbide, right click on it +and select "Properties". Expand "Carbide.c++" field and select "Build Configurations". +Being in the "SIS Builder" tab, select as Active Configuration the "Phone Degug (GCCE)". +Then press "Add" button, and to select a PKG file click "Browse" button. Go to "QQrDecoder" +folder and select "QQrDecoder_template.pkg" file. Make sure that "Self sign sis file" radio +button is selected and press OK. + +Now go "Project->Build Project" and if everything goes right, you will have 2 installation files +in "QQrDecoder" folder. Install the .sisx file to your device and you are ready. + +== Additional information == +For afew more details about the implementation you can see the following page: +http://wiki.forum.nokia.com/index.php/Qr_Decoder_in_Qt + +== The same project in Symbian C++ == + +In case you are interested in using this project with only Symbian C++, take a look at ZXingBarcodeReader folder. \ No newline at end of file diff --git a/symbian/ZXingBarcodeReader_tutorial.txt b/symbian/ZXingBarcodeReader_tutorial.txt new file mode 100644 index 000000000..254f50df3 --- /dev/null +++ b/symbian/ZXingBarcodeReader_tutorial.txt @@ -0,0 +1,46 @@ +The whole ZXingBarcodeReader folder is a Carbide project build and tested on both +S60 5th Edition SDK and S60 3rd Edition FP2. (currently only Qr Codes can be detected) + +== Prerequisities == + +* Have at least one S60 SDK. One of the SDKs can be obtained from here: + http://www.forum.nokia.com/info/sw.nokia.com/id/ec866fab-4b76-49f6-b5a5-af0631419e9c/S60_All_in_One_SDKs.html + +* After installing S60 SDK you have to install OpenC++. + http://www.forum.nokia.com/info/sw.nokia.com/id/91d89929-fb8c-4d66-bea0-227e42df9053/Open_C_SDK_Plug-In.html + +* (Optional) You can use Carbide C++ as IDE which makes the life a bit easier on creating applications for Symbian. + An alternative approach is to compile the program in command line but i am afraid i can help you here because i + have no idea :P + +== Create project == +If you have Carbide C++ IDE then go "File->Import->Symbian OS->Symbian OS Bld.inf file", +click "Browse" and find and select file "ZXingBarcodeReader\group\bld.inf". +Next step you select the S60 SDK to be compiled to and you are ready. + +== Build project == +Since the project is created, we can proceed to build it. + +First in "ZXingBarcodeReader\camerawrapper" folder there is a folder named "epoc32". +Copy this folder and paste it to the root folder of the S60 SDK that you are going to use +(in my case: C:\S60\devices\S60_5th_Edition_SDK_v1.0). This step is important in order +to use a Plug-In API for the easier manipulation of the camera. + +Now we are ready to compile. Since the camera is not supported in the Symbian emulator we +will build the project directly to be installed on a devidce. +Select "ZXingBarcodeReader" project in the "Project Explorer" view in Carbide, right click on it +and select "Properties". Expand "Carbide.c++" field and select "Build Configurations". +Being in the "SIS Builder" tab, select as Active Configuration the "Phone Degug (GCCE)". +Then press "Add" button, and to select a PKG file click "Browse" button. Go to "ZXingBarcodeReader\sis" +folder and select "ZXingBarcodeReader_S60.pkg" file. Make sure that "Self sign sis file" radio +button is selected and press OK. + +Now go "Project->Build Project" and if everything goes right, you will have 2 installation files +in "ZXingBarcodeReader\sis" folder. Install the .sisx file to your device and you are ready. + +== The same project in Qt == + +In case you are interested in using this project with Qt on Symbian, take a look at QQrDecoder folder. + + +