From 709f7f060a613210552d2c9cfd4eadd5d3bb413e Mon Sep 17 00:00:00 2001 From: "smparkes@smparkes.net" Date: Thu, 20 Oct 2011 19:11:33 +0000 Subject: [PATCH] Port multi reader from Java. Closes Issue 1027. I tweaked things a little, small formatting (to help me diff) and made some of the protection levels match the Java code. Nothing semantic. Great work. Thanks! git-svn-id: https://zxing.googlecode.com/svn/trunk@1986 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- cpp/SConscript | 4 +- cpp/core/src/zxing/ResultPoint.cpp | 12 + cpp/core/src/zxing/ResultPoint.h | 11 +- .../zxing/datamatrix/detector/CornerPoint.cpp | 10 +- .../zxing/datamatrix/detector/CornerPoint.h | 4 - cpp/core/src/zxing/multi/ByQuadrantReader.cpp | 71 ++++++ cpp/core/src/zxing/multi/ByQuadrantReader.h | 40 ++++ .../multi/GenericMultipleBarcodeReader.cpp | 128 ++++++++++ .../multi/GenericMultipleBarcodeReader.h | 47 ++++ .../src/zxing/multi/MultipleBarcodeReader.cpp | 29 +++ .../src/zxing/multi/MultipleBarcodeReader.h | 39 +++ .../zxing/multi/qrcode/QRCodeMultiReader.cpp | 57 +++++ .../zxing/multi/qrcode/QRCodeMultiReader.h | 34 +++ .../multi/qrcode/detector/MultiDetector.cpp | 46 ++++ .../multi/qrcode/detector/MultiDetector.h | 35 +++ .../detector/MultiFinderPatternFinder.cpp | 225 ++++++++++++++++++ .../detector/MultiFinderPatternFinder.h | 45 ++++ cpp/core/src/zxing/oned/OneDResultPoint.cpp | 10 +- cpp/core/src/zxing/oned/OneDResultPoint.h | 5 - cpp/core/src/zxing/qrcode/QRCodeReader.cpp | 3 + cpp/core/src/zxing/qrcode/QRCodeReader.h | 3 + .../qrcode/detector/AlignmentPattern.cpp | 10 +- .../zxing/qrcode/detector/AlignmentPattern.h | 4 - .../src/zxing/qrcode/detector/Detector.cpp | 4 + cpp/core/src/zxing/qrcode/detector/Detector.h | 4 +- .../zxing/qrcode/detector/FinderPattern.cpp | 12 +- .../src/zxing/qrcode/detector/FinderPattern.h | 4 - .../qrcode/detector/FinderPatternFinder.h | 2 + cpp/magick/src/MagickBitmapSource.cpp | 34 +-- cpp/magick/src/MagickBitmapSource.h | 10 +- cpp/magick/src/main.cpp | 154 +++++++++--- 31 files changed, 983 insertions(+), 113 deletions(-) create mode 100644 cpp/core/src/zxing/multi/ByQuadrantReader.cpp create mode 100644 cpp/core/src/zxing/multi/ByQuadrantReader.h create mode 100644 cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp create mode 100644 cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h create mode 100644 cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp create mode 100644 cpp/core/src/zxing/multi/MultipleBarcodeReader.h create mode 100644 cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp create mode 100644 cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h create mode 100644 cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp create mode 100644 cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h create mode 100644 cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp create mode 100644 cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h diff --git a/cpp/SConscript b/cpp/SConscript index 6aa57b094..5277c48c2 100644 --- a/cpp/SConscript +++ b/cpp/SConscript @@ -1,3 +1,5 @@ +# -*- python -*- + Decider('MD5') vars = Variables() @@ -20,7 +22,7 @@ if env['PIC']: compile_options['CXXFLAGS'] = ' '.join(flags) compile_options['LINKFLAGS'] = "-ldl" -def all_files(dir, ext='.cpp', level=5): +def all_files(dir, ext='.cpp', level=6): files = [] for i in range(1, level): files += Glob(dir + ('/*' * i) + ext) diff --git a/cpp/core/src/zxing/ResultPoint.cpp b/cpp/core/src/zxing/ResultPoint.cpp index 967068551..ea4a755c6 100755 --- a/cpp/core/src/zxing/ResultPoint.cpp +++ b/cpp/core/src/zxing/ResultPoint.cpp @@ -22,6 +22,18 @@ namespace zxing { +ResultPoint::ResultPoint() : posX_(0), posY_(0) {} + +ResultPoint::ResultPoint(float x, float y) : posX_(x), posY_(y) {} + ResultPoint::~ResultPoint() {} +float ResultPoint::getX() const { + return posX_; +} + +float ResultPoint::getY() const { + return posY_; +} + } diff --git a/cpp/core/src/zxing/ResultPoint.h b/cpp/core/src/zxing/ResultPoint.h index f3e6090c2..6b8b3de1a 100644 --- a/cpp/core/src/zxing/ResultPoint.h +++ b/cpp/core/src/zxing/ResultPoint.h @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- #ifndef __RESULT_POINT_H__ #define __RESULT_POINT_H__ @@ -26,12 +27,16 @@ namespace zxing { class ResultPoint : public Counted { protected: - ResultPoint() {} + float posX_; + float posY_; + public: + ResultPoint(); + ResultPoint(float x, float y); virtual ~ResultPoint(); - virtual float getX() const = 0; - virtual float getY() const = 0; + virtual float getX() const; + virtual float getY() const; }; } diff --git a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp index 8222f6b27..b04f28237 100644 --- a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp +++ b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.cpp @@ -27,15 +27,7 @@ namespace zxing { using namespace std; CornerPoint::CornerPoint(float posX, float posY) : - posX_(posX), posY_(posY), counter_(0) { - } - - float CornerPoint::getX() const { - return posX_; - } - - float CornerPoint::getY() const { - return posY_; + ResultPoint(posX,posY), counter_(0) { } int CornerPoint::getCount() const { diff --git a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h index a44d72b38..cbf2a7ef6 100644 --- a/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h +++ b/cpp/core/src/zxing/datamatrix/detector/CornerPoint.h @@ -29,14 +29,10 @@ namespace zxing { class CornerPoint : public ResultPoint { private: - float posX_; - float posY_; int counter_; public: CornerPoint(float posX, float posY); - float getX() const; - float getY() const; int getCount() const; void incrementCount(); bool equals(Ref other) const; diff --git a/cpp/core/src/zxing/multi/ByQuadrantReader.cpp b/cpp/core/src/zxing/multi/ByQuadrantReader.cpp new file mode 100644 index 000000000..427278907 --- /dev/null +++ b/cpp/core/src/zxing/multi/ByQuadrantReader.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2011 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 multi { + +ByQuadrantReader::ByQuadrantReader(Reader& delegate) : delegate_(delegate) {} + +ByQuadrantReader::~ByQuadrantReader(){} + +Ref ByQuadrantReader::decode(Ref image){ + return decode(image, DecodeHints::DEFAULT_HINT); +} + +Ref ByQuadrantReader::decode(Ref image, DecodeHints hints){ + int width = image->getWidth(); + int height = image->getHeight(); + int halfWidth = width / 2; + int halfHeight = height / 2; + Ref topLeft = image->crop(0, 0, halfWidth, halfHeight); + try { + return delegate_.decode(topLeft, hints); + } catch (ReaderException re) { + // continue + } + + Ref topRight = image->crop(halfWidth, 0, halfWidth, halfHeight); + try { + return delegate_.decode(topRight, hints); + } catch (ReaderException re) { + // continue + } + + Ref bottomLeft = image->crop(0, halfHeight, halfWidth, halfHeight); + try { + return delegate_.decode(bottomLeft, hints); + } catch (ReaderException re) { + // continue + } + + Ref bottomRight = image->crop(halfWidth, halfHeight, halfWidth, halfHeight); + try { + return delegate_.decode(bottomRight, hints); + } catch (ReaderException re) { + // continue + } + + int quarterWidth = halfWidth / 2; + int quarterHeight = halfHeight / 2; + Ref center = image->crop(quarterWidth, quarterHeight, halfWidth, halfHeight); + return delegate_.decode(center, hints); +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/ByQuadrantReader.h b/cpp/core/src/zxing/multi/ByQuadrantReader.h new file mode 100644 index 000000000..18dcc33ab --- /dev/null +++ b/cpp/core/src/zxing/multi/ByQuadrantReader.h @@ -0,0 +1,40 @@ +#ifndef __BY_QUADRANT_READER_H__ +#define __BY_QUADRANT_READER_H__ + +/* + * Copyright 2011 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 multi { +class ByQuadrantReader : public Reader { + private: + Reader& delegate_; + + public: + ByQuadrantReader(Reader& delegate); + virtual ~ByQuadrantReader(); + virtual Ref decode(Ref image); + virtual Ref decode(Ref image, DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __BY_QUADRANT_READER_H__ diff --git a/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp new file mode 100644 index 000000000..adad94d04 --- /dev/null +++ b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2011 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 multi { +GenericMultipleBarcodeReader::GenericMultipleBarcodeReader(Reader& delegate) : + delegate_(delegate) +{ +} + +GenericMultipleBarcodeReader::~GenericMultipleBarcodeReader(){} + +std::vector > GenericMultipleBarcodeReader::decodeMultiple( + Ref image, DecodeHints hints) +{ + std::vector > results; + doDecodeMultiple(image, hints, results, 0, 0); + if (results.empty()){ + throw ReaderException("No code detected"); + } + return results; +} + +void GenericMultipleBarcodeReader::doDecodeMultiple(Ref image, + DecodeHints hints, std::vector >& results, int xOffset, int yOffset) +{ + Ref result; + try { + result = delegate_.decode(image, hints); + } catch (ReaderException re) { + return; + } + bool alreadyFound = false; + for (unsigned int i = 0; i < results.size(); i++) { + Ref existingResult = results[i]; + if (existingResult->getText()->getText() == result->getText()->getText()) { + alreadyFound = true; + break; + } + } + if (alreadyFound) { + return; + } + + results.push_back(translateResultPoints(result, xOffset, yOffset)); + const std::vector > resultPoints = result->getResultPoints(); + if (resultPoints.empty()) { + return; + } + + int width = image->getWidth(); + int height = image->getHeight(); + float minX = width; + float minY = height; + float maxX = 0.0f; + float maxY = 0.0f; + for (unsigned int i = 0; i < resultPoints.size(); i++) { + Ref point = resultPoints[i]; + float x = point->getX(); + float y = point->getY(); + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + + // Decode left of barcode + if (minX > MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, 0, (int) minX, height), + hints, results, xOffset, yOffset); + } + // Decode above barcode + if (minY > MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, 0, width, (int) minY), + hints, results, xOffset, yOffset); + } + // Decode right of barcode + if (maxX < width - MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop((int) maxX, 0, width - (int) maxX, height), + hints, results, xOffset + (int) maxX, yOffset); + } + // Decode below barcode + if (maxY < height - MIN_DIMENSION_TO_RECUR) { + doDecodeMultiple(image->crop(0, (int) maxY, width, height - (int) maxY), + hints, results, xOffset, yOffset + (int) maxY); + } +} + +Ref GenericMultipleBarcodeReader::translateResultPoints(Ref result, int xOffset, int yOffset){ + const std::vector > oldResultPoints = result->getResultPoints(); + if (oldResultPoints.empty()) { + return result; + } + std::vector > newResultPoints; + for (unsigned int i = 0; i < oldResultPoints.size(); i++) { + Ref oldPoint = oldResultPoints[i]; + newResultPoints.push_back(Ref(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset))); + } + return Ref(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat())); +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h new file mode 100644 index 000000000..87d46b335 --- /dev/null +++ b/cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h @@ -0,0 +1,47 @@ +#ifndef __GENERIC_MULTIPLE_BARCODE_READER_H__ +#define __GENERIC_MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 2011 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 multi { +class GenericMultipleBarcodeReader : public MultipleBarcodeReader { + private: + static Ref translateResultPoints(Ref result, + int xOffset, + int yOffset); + void doDecodeMultiple(Ref image, + DecodeHints hints, + std::vector >& results, + int xOffset, + int yOffset); + Reader& delegate_; + static const int MIN_DIMENSION_TO_RECUR = 100; + + public: + GenericMultipleBarcodeReader(Reader& delegate); + virtual ~GenericMultipleBarcodeReader(); + virtual std::vector > decodeMultiple(Ref image, + DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __GENERIC_MULTIPLE_BARCODE_READER_H__ diff --git a/cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp b/cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp new file mode 100644 index 000000000..67e187e1b --- /dev/null +++ b/cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2011 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 multi { + +MultipleBarcodeReader::~MultipleBarcodeReader() { } + +std::vector > MultipleBarcodeReader::decodeMultiple(Ref image) { + return decodeMultiple(image, DecodeHints::DEFAULT_HINT); +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/MultipleBarcodeReader.h b/cpp/core/src/zxing/multi/MultipleBarcodeReader.h new file mode 100644 index 000000000..61242971d --- /dev/null +++ b/cpp/core/src/zxing/multi/MultipleBarcodeReader.h @@ -0,0 +1,39 @@ +#ifndef __MULTIPLE_BARCODE_READER_H__ +#define __MULTIPLE_BARCODE_READER_H__ + +/* + * Copyright 2011 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 multi { +class MultipleBarcodeReader : public Counted { + protected: + MultipleBarcodeReader() {} + public: + virtual std::vector > decodeMultiple(Ref image); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints) = 0; + virtual ~MultipleBarcodeReader(); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __MULTIPLE_BARCODE_READER_H__ diff --git a/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp new file mode 100644 index 000000000..d60f5e069 --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp @@ -0,0 +1,57 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 2011 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 multi { +QRCodeMultiReader::QRCodeMultiReader(){} + +QRCodeMultiReader::~QRCodeMultiReader(){} + +std::vector > QRCodeMultiReader::decodeMultiple(Ref image, + DecodeHints hints) +{ + std::vector > results; + MultiDetector detector(image->getBlackMatrix()); + + std::vector > detectorResult = detector.detectMulti(hints); + for (unsigned int i = 0; i < detectorResult.size(); i++) { + try { + Ref decoderResult = getDecoder().decode(detectorResult[i]->getBits()); + std::vector > points = detectorResult[i]->getPoints(); + Ref result = Ref(new Result(decoderResult->getText(), + decoderResult->getRawBytes(), + points, BarcodeFormat_QR_CODE)); + // result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments()); + // result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString()); + results.push_back(result); + } catch (ReaderException re) { + // ignore and continue + } + } + if (results.empty()){ + throw ReaderException("No code detected"); + } + return results; +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h new file mode 100644 index 000000000..e32be8ce1 --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h @@ -0,0 +1,34 @@ +#ifndef __QRCODE_MULTI_READER_H__ +#define __QRCODE_MULTI_READER_H__ + +/* + * Copyright 2011 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 multi { +class QRCodeMultiReader: public zxing::qrcode::QRCodeReader, public MultipleBarcodeReader { + public: + QRCodeMultiReader(); + virtual ~QRCodeMultiReader(); + virtual std::vector > decodeMultiple(Ref image, DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __QRCODE_MULTI_READER_H__ diff --git a/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp b/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp new file mode 100644 index 000000000..53f64a24c --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +namespace multi { +using namespace zxing::qrcode; + +MultiDetector::MultiDetector(Ref image) : Detector(image) {} + +MultiDetector::~MultiDetector(){} + +std::vector > MultiDetector::detectMulti(DecodeHints hints){ + Ref image = getImage(); + MultiFinderPatternFinder finder = MultiFinderPatternFinder(image, hints.getResultPointCallback()); + std::vector > info = finder.findMulti(hints); + std::vector > result; + for(unsigned int i = 0; i < info.size(); i++){ + try{ + result.push_back(processFinderPatternInfo(info[i])); + } catch (ReaderException e){ + // ignore + } + } + + return result; +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h b/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h new file mode 100644 index 000000000..338d5d9c0 --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h @@ -0,0 +1,35 @@ +#ifndef __MULTI_DETECTOR_H__ +#define __MULTI_DETECTOR_H__ + +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +namespace multi { +class MultiDetector : public zxing::qrcode::Detector { + public: + MultiDetector(Ref image); + virtual ~MultiDetector(); + virtual std::vector > detectMulti(DecodeHints hints); +}; +} // End zxing::multi namespace +} // End zxing namespace + +#endif // __MULTI_DETECTOR_H__ diff --git a/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp b/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp new file mode 100644 index 000000000..c7694f256 --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.cpp @@ -0,0 +1,225 @@ +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace zxing{ +namespace multi { +using namespace zxing::qrcode; + +bool compareModuleSize(Ref a, Ref b){ + float value = a->getEstimatedModuleSize() - b->getEstimatedModuleSize(); + return value < 0.0; +} + + +MultiFinderPatternFinder::MultiFinderPatternFinder(Ref image, + Ref resultPointCallback) : + FinderPatternFinder(image, resultPointCallback) +{ +} + +MultiFinderPatternFinder::~MultiFinderPatternFinder(){} + +std::vector > MultiFinderPatternFinder::findMulti(DecodeHints const& hints){ + bool tryHarder = hints.getTryHarder(); + Ref image = image_; // Protected member + int maxI = image->getHeight(); + int 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 + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3); + if (iSkip < MIN_SKIP || tryHarder) { + iSkip = MIN_SKIP; + } + + int stateCount[5]; + for (int i = iSkip - 1; i < maxI; i += iSkip) { + // Get a row of black/white values + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + for (int j = 0; j < maxJ; j++) { + if (image->get(j, i)) { + // Black pixel + if ((currentState & 1) == 1) { // Counting white pixels + currentState++; + } + stateCount[currentState]++; + } else { // White pixel + if ((currentState & 1) == 0) { // Counting black pixels + if (currentState == 4) { // A winner? + if (foundPatternCross(stateCount)) { // Yes + bool confirmed = handlePossibleCenter(stateCount, i, j); + if (!confirmed) { + do { // Advance to next black pixel + j++; + } while (j < maxJ && !image->get(j, i)); + j--; // back up to that last white pixel + } + // Clear state to start looking again + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { // No, shift counts back by two + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { // Counting white pixels + stateCount[currentState]++; + } + } + } // for j=... + + if (foundPatternCross(stateCount)) { + handlePossibleCenter(stateCount, i, maxJ); + } // end if foundPatternCross + } // for i=iSkip-1 ... + std::vector > > patternInfo = selectBestPatterns(); + std::vector > result; + for (unsigned int i = 0; i < patternInfo.size(); i++) { + std::vector > pattern = patternInfo[i]; + FinderPatternFinder::orderBestPatterns(pattern); + result.push_back(Ref(new FinderPatternInfo(pattern))); + } + return result; +} + +std::vector > > MultiFinderPatternFinder::selectBestPatterns(){ + std::vector > possibleCenters = possibleCenters_; + + int size = possibleCenters.size(); + + if (size < 3) { + // Couldn't find enough finder patterns + throw ReaderException("No code detected"); + } + + std::vector > > results; + + /* + * Begin HE modifications to safely detect multiple codes of equal size + */ + if (size == 3) { + results.push_back(possibleCenters_); + return results; + } + + // Sort by estimated module size to speed up the upcoming checks + //TODO do a sort based on module size + std::sort(possibleCenters.begin(), possibleCenters.end(), compareModuleSize); + + /* + * Now lets start: build a list of tuples of three finder locations that + * - feature similar module sizes + * - are placed in a distance so the estimated module count is within the QR specification + * - have similar distance between upper left/right and left top/bottom finder patterns + * - form a triangle with 90° angle (checked by comparing top right/bottom left distance + * with pythagoras) + * + * Note: we allow each point to be used for more than one code region: this might seem + * counterintuitive at first, but the performance penalty is not that big. At this point, + * we cannot make a good quality decision whether the three finders actually represent + * a QR code, or are just by chance layouted so it looks like there might be a QR code there. + * So, if the layout seems right, lets have the decoder try to decode. + */ + + for (int i1 = 0; i1 < (size - 2); i1++) { + Ref p1 = possibleCenters[i1]; + for (int i2 = i1 + 1; i2 < (size - 1); i2++) { + Ref p2 = possibleCenters[i2]; + // Compare the expected module sizes; if they are really off, skip + float vModSize12 = (p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()) / std::min(p1->getEstimatedModuleSize(), p2->getEstimatedModuleSize()); + float vModSize12A = abs(p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()); + if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) { + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; + } + for (int i3 = i2 + 1; i3 < size; i3++) { + Ref p3 = possibleCenters[i3]; + // Compare the expected module sizes; if they are really off, skip + float vModSize23 = (p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()) / std::min(p2->getEstimatedModuleSize(), p3->getEstimatedModuleSize()); + float vModSize23A = abs(p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()); + if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) { + // break, since elements are ordered by the module size deviation there cannot be + // any more interesting elements for the given p1. + break; + } + std::vector > test; + test.push_back(p1); + test.push_back(p2); + test.push_back(p3); + FinderPatternFinder::orderBestPatterns(test); + // Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal + Ref info = Ref(new FinderPatternInfo(test)); + float dA = FinderPatternFinder::distance(info->getTopLeft(), info->getBottomLeft()); + float dC = FinderPatternFinder::distance(info->getTopRight(), info->getBottomLeft()); + float dB = FinderPatternFinder::distance(info->getTopLeft(), info->getTopRight()); + // Check the sizes + float estimatedModuleCount = (dA + dB) / (p1->getEstimatedModuleSize() * 2.0f); + if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) { + continue; + } + // Calculate the difference of the edge lengths in percent + float vABBC = abs((dA - dB) / std::min(dA, dB)); + if (vABBC >= 0.1f) { + continue; + } + // Calculate the diagonal length by assuming a 90° angle at topleft + float dCpy = (float) sqrt(dA * dA + dB * dB); + // Compare to the real distance in % + float vPyC = abs((dC - dCpy) / std::min(dC, dCpy)); + if (vPyC >= 0.1f) { + continue; + } + // All tests passed! + results.push_back(test); + } // end iterate p3 + } // end iterate p2 + } // end iterate p1 + if (results.empty()){ + // Nothing found! + throw ReaderException("No code detected"); + } + return results; +} + +} // End zxing::multi namespace +} // End zxing namespace diff --git a/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h b/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h new file mode 100644 index 000000000..b6db8107d --- /dev/null +++ b/cpp/core/src/zxing/multi/qrcode/detector/MultiFinderPatternFinder.h @@ -0,0 +1,45 @@ +#ifndef __MULTI_FINDER_PATTERN_FINDER_H__ +#define __MULTI_FINDER_PATTERN_FINDER_H__ + +/* + * Copyright 2011 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace zxing { +namespace multi { +class MultiFinderPatternFinder : zxing::qrcode::FinderPatternFinder { + private: + std::vector > > selectBestPatterns(); + + static const float MAX_MODULE_COUNT_PER_EDGE = 180; + static const float MIN_MODULE_COUNT_PER_EDGE = 9; + static const float DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; + static const float DIFF_MODSIZE_CUTOFF = 0.5f; + + public: + MultiFinderPatternFinder(Ref image, Ref resultPointCallback); + virtual ~MultiFinderPatternFinder(); + virtual std::vector > findMulti(DecodeHints const& hints); + + +}; +} +} + +#endif // __MULTI_FINDER_PATTERN_FINDER_H__ diff --git a/cpp/core/src/zxing/oned/OneDResultPoint.cpp b/cpp/core/src/zxing/oned/OneDResultPoint.cpp index 3e68b66a9..bdf7d7926 100644 --- a/cpp/core/src/zxing/oned/OneDResultPoint.cpp +++ b/cpp/core/src/zxing/oned/OneDResultPoint.cpp @@ -22,15 +22,7 @@ namespace zxing { namespace oned { - OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY) { - } - - float OneDResultPoint::getX() const { - return posX_; - } - - float OneDResultPoint::getY() const { - return posY_; + OneDResultPoint::OneDResultPoint(float posX, float posY) : ResultPoint(posX,posY) { } } } diff --git a/cpp/core/src/zxing/oned/OneDResultPoint.h b/cpp/core/src/zxing/oned/OneDResultPoint.h index c9968c3ec..825a04e08 100644 --- a/cpp/core/src/zxing/oned/OneDResultPoint.h +++ b/cpp/core/src/zxing/oned/OneDResultPoint.h @@ -25,14 +25,9 @@ namespace zxing { namespace oned { class OneDResultPoint : public ResultPoint { - private: - float posX_; - float posY_; public: OneDResultPoint(float posX, float posY); - float getX() const; - float getY() const; }; } } diff --git a/cpp/core/src/zxing/qrcode/QRCodeReader.cpp b/cpp/core/src/zxing/qrcode/QRCodeReader.cpp index ef59f1ad8..969633a89 100644 --- a/cpp/core/src/zxing/qrcode/QRCodeReader.cpp +++ b/cpp/core/src/zxing/qrcode/QRCodeReader.cpp @@ -79,5 +79,8 @@ namespace zxing { QRCodeReader::~QRCodeReader() { } + Decoder& QRCodeReader::getDecoder() { + return decoder_; + } } } diff --git a/cpp/core/src/zxing/qrcode/QRCodeReader.h b/cpp/core/src/zxing/qrcode/QRCodeReader.h index 0e4fa6961..b245be65e 100644 --- a/cpp/core/src/zxing/qrcode/QRCodeReader.h +++ b/cpp/core/src/zxing/qrcode/QRCodeReader.h @@ -32,6 +32,9 @@ namespace zxing { private: Decoder decoder_; + protected: + Decoder& getDecoder(); + public: QRCodeReader(); virtual Ref decode(Ref image, DecodeHints hints); diff --git a/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.cpp b/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.cpp index c06cd9372..d8744939e 100644 --- a/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.cpp +++ b/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.cpp @@ -27,15 +27,7 @@ namespace qrcode { using namespace std; AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) : - posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize) { -} - -float AlignmentPattern::getX() const { - return posX_; -} - -float AlignmentPattern::getY() const { - return posY_; + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize) { } bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) const { diff --git a/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.h b/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.h index a3f4f6a34..f95b92abe 100644 --- a/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.h +++ b/cpp/core/src/zxing/qrcode/detector/AlignmentPattern.h @@ -30,14 +30,10 @@ namespace zxing { class AlignmentPattern : public ResultPoint { private: - float posX_; - float posY_; float estimatedModuleSize_; public: AlignmentPattern(float posX, float posY, float estimatedModuleSize); - float getX() const; - float getY() const; bool aboutEquals(float moduleSize, float i, float j) const; Ref combineEstimate(float i, float j, float newModuleSize) const; diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.cpp b/cpp/core/src/zxing/qrcode/detector/Detector.cpp index 6e1bb14da..952010a28 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/Detector.cpp @@ -1,3 +1,4 @@ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* * Detector.cpp * zxing @@ -47,7 +48,10 @@ Ref Detector::detect(DecodeHints const& hints) { callback_ = hints.getResultPointCallback(); FinderPatternFinder finder(image_, hints.getResultPointCallback()); Ref info(finder.find(hints)); + return processFinderPatternInfo(info); +} +Ref Detector::processFinderPatternInfo(Ref info){ Ref topLeft(info->getTopLeft()); Ref topRight(info->getTopRight()); Ref bottomLeft(info->getBottomLeft()); diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.h b/cpp/core/src/zxing/qrcode/detector/Detector.h index 6ec305270..62e5c8642 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.h +++ b/cpp/core/src/zxing/qrcode/detector/Detector.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace zxing { @@ -50,6 +51,7 @@ protected: float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, float allowanceFactor); + Ref processFinderPatternInfo(Ref info); public: virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < @@ -61,4 +63,4 @@ public: } } -#endif // __DETECTOR_H__ +#endif // __DETECTOR_H__ \ No newline at end of file diff --git a/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp b/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp index 4ac8ae86b..32c64da7f 100644 --- a/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp +++ b/cpp/core/src/zxing/qrcode/detector/FinderPattern.cpp @@ -27,19 +27,11 @@ namespace zxing { using namespace std; FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) : - posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), count_(1) { + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) { } FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) : - posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), count_(count) { - } - - float FinderPattern::getX() const { - return posX_; - } - - float FinderPattern::getY() const { - return posY_; + ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) { } int FinderPattern::getCount() const { diff --git a/cpp/core/src/zxing/qrcode/detector/FinderPattern.h b/cpp/core/src/zxing/qrcode/detector/FinderPattern.h index 2b4729ced..e23ba5dc0 100644 --- a/cpp/core/src/zxing/qrcode/detector/FinderPattern.h +++ b/cpp/core/src/zxing/qrcode/detector/FinderPattern.h @@ -29,16 +29,12 @@ namespace zxing { class FinderPattern : public ResultPoint { private: - float posX_; - float posY_; float estimatedModuleSize_; int count_; public: FinderPattern(float posX, float posY, float estimatedModuleSize); FinderPattern(float posX, float posY, float estimatedModuleSize, int count); - float getX() const; - float getY() const; int getCount() const; float getEstimatedModuleSize() const; void incrementCount(); diff --git a/cpp/core/src/zxing/qrcode/detector/FinderPatternFinder.h b/cpp/core/src/zxing/qrcode/detector/FinderPatternFinder.h index 6c8684d59..1d85f9b65 100644 --- a/cpp/core/src/zxing/qrcode/detector/FinderPatternFinder.h +++ b/cpp/core/src/zxing/qrcode/detector/FinderPatternFinder.h @@ -36,6 +36,8 @@ namespace qrcode { class FinderPatternFinder { private: static int CENTER_QUORUM; + +protected: static int MIN_SKIP; static int MAX_MODULES; diff --git a/cpp/magick/src/MagickBitmapSource.cpp b/cpp/magick/src/MagickBitmapSource.cpp index f805487e8..16d1ac730 100644 --- a/cpp/magick/src/MagickBitmapSource.cpp +++ b/cpp/magick/src/MagickBitmapSource.cpp @@ -1,8 +1,5 @@ /* - * MagickBitmapSource.cpp - * zxing - * - * Copyright 2010 ZXing authors All rights reserved. + * Copyright 2010-2011 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,12 +25,10 @@ namespace zxing { MagickBitmapSource::MagickBitmapSource(Image& image) : image_(image) { width = image.columns(); height = image.rows(); - - pixel_cache = image.getConstPixels(0, 0, width, height); + } MagickBitmapSource::~MagickBitmapSource() { - } int MagickBitmapSource::getWidth() const { @@ -45,12 +40,13 @@ int MagickBitmapSource::getHeight() const { } unsigned char* MagickBitmapSource::getRow(int y, unsigned char* row) { + const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, y, width, 1); int width = getWidth(); if (row == NULL) { row = new unsigned char[width]; } for (int x = 0; x < width; x++) { - const PixelPacket* p = pixel_cache + y * width + x; + const PixelPacket* p = pixel_cache + x; // We assume 16 bit values here // 0x200 = 1<<9, half an lsb of the result to force rounding row[x] = (unsigned char)((306 * ((int)p->red >> 8) + 601 * ((int)p->green >> 8) + @@ -62,6 +58,7 @@ unsigned char* MagickBitmapSource::getRow(int y, unsigned char* row) { /** This is a more efficient implementation. */ unsigned char* MagickBitmapSource::getMatrix() { + const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, 0, width, height); int width = getWidth(); int height = getHeight(); unsigned char* matrix = new unsigned char[width*height]; @@ -79,20 +76,29 @@ unsigned char* MagickBitmapSource::getMatrix() { } bool MagickBitmapSource::isRotateSupported() const { - return false; + return true; } Ref MagickBitmapSource::rotateCounterClockwise() { - //TODO(flyashi): add rotated image support. - /* this segfaults. I tried a few things, none seemed to work. Perhaps the problem is elsewhere? */ - /* Magick::Image rotated(image_); rotated.modifyImage(); rotated.rotate(90); // Image::rotate takes CCW degrees as an argument rotated.syncPixels(); return Ref (new MagickBitmapSource(rotated)); - */ - return Ref (NULL); +} + +bool MagickBitmapSource::isCropSupported() const{ + return true; +} + +Ref MagickBitmapSource::crop(int left, int top, int width, int height){ + /* TODO Investigate memory leak: + * This method "possibly leaks" 160 bytes in 1 block */ + Image copy(image_); + copy.modifyImage(); + copy.crop( Geometry(width,height,left,top)); + copy.syncPixels(); + return Ref(new MagickBitmapSource(copy)); } } diff --git a/cpp/magick/src/MagickBitmapSource.h b/cpp/magick/src/MagickBitmapSource.h index 886449939..ed556007d 100644 --- a/cpp/magick/src/MagickBitmapSource.h +++ b/cpp/magick/src/MagickBitmapSource.h @@ -1,10 +1,7 @@ #ifndef __MAGICK_BITMAP_SOURCE_H_ #define __MAGICK_BITMAP_SOURCE_H_ /* - * MagickBitmapSource.h - * zxing - * - * Copyright 2010 ZXing authors All rights reserved. + * Copyright 2010-2011 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +23,9 @@ namespace zxing { class MagickBitmapSource : public LuminanceSource { private: - Magick::Image& image_; + Magick::Image image_; int width; int height; - const Magick::PixelPacket* pixel_cache; public: MagickBitmapSource(Magick::Image& image); @@ -40,6 +36,8 @@ public: int getHeight() const; unsigned char* getRow(int y, unsigned char* row); unsigned char* getMatrix(); + bool isCropSupported() const; + Ref crop(int left, int top, int width, int height); bool isRotateSupported() const; Ref rotateCounterClockwise(); }; diff --git a/cpp/magick/src/main.cpp b/cpp/magick/src/main.cpp index 91056bfaf..403f0faca 100644 --- a/cpp/magick/src/main.cpp +++ b/cpp/magick/src/main.cpp @@ -1,9 +1,6 @@ // -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- /* - * main.cpp - * zxing - * - * Copyright 2010 ZXing authors All rights reserved. + * Copyright 2010-2011 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +21,6 @@ #include #include "MagickBitmapSource.h" #include -//#include #include #include #include @@ -37,6 +33,12 @@ #include #include +#include +#include +#include +#include +#include + //#include //#include //#include @@ -44,12 +46,14 @@ using namespace Magick; using namespace std; using namespace zxing; -//using namespace zxing::qrcode; +using namespace zxing::multi; +using namespace zxing::qrcode; static bool raw_dump = false; static bool show_format = false; static bool tryHarder = false; static bool show_filename = false; +static bool search_multi = false; static const int MAX_EXPECTED = 1024; @@ -58,6 +62,16 @@ Ref decode(Ref image, DecodeHints hints) { return reader->decode(image, hints); } +vector > decodeMultiple(Ref image, DecodeHints hints){ + MultiFormatReader delegate; +// MultiFormatReader mformat; +// ByQuadrantReader delegate(mformat); + + GenericMultipleBarcodeReader reader(delegate); +// QRCodeMultiReader reader; + return reader.decodeMultiple(image,hints); +} + int test_image(Image& image, bool hybrid, string expected = "") { @@ -101,22 +115,20 @@ int test_image(Image& image, bool hybrid, string expected = "") { if (cell_result.compare(expected)) { res = -6; if (!raw_dump) { - cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n"; - if (expected.length() >= 0) { - cout << " Expected: " << expected << "\n"; - } - cout << " Detected: " << cell_result << endl; + cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n"; + if (expected.length() >= 0) { + cout << " Expected: " << expected << "\n"; + } + cout << " Detected: " << cell_result << endl; } } - if (raw_dump && !hybrid) {/* don't print twice, and global is a bit better */ cout << cell_result; if (show_format) { cout << " " << result_format; } cout << endl; - } return res; } @@ -129,6 +141,64 @@ int test_image_global(Image& image, string expected = "") { return test_image(image, false, expected); } +int test_image_multi(Image& image, bool hybrid){ + vector > results; + string cell_result; + int res = -1; + + Ref matrix(NULL); + Ref binarizer(NULL); + + try { + Ref source(new MagickBitmapSource(image)); + + if (hybrid) { + binarizer = new HybridBinarizer(source); + } else { + binarizer = new GlobalHistogramBinarizer(source); + } + DecodeHints hints(DecodeHints::DEFAULT_HINT); + hints.setTryHarder(tryHarder); + Ref binary(new BinaryBitmap(binarizer)); + results = decodeMultiple(binary, hints); + res = 0; + } catch (ReaderException e) { + cell_result = "zxing::ReaderException: " + string(e.what()); + res = -2; + } catch (zxing::IllegalArgumentException& e) { + cell_result = "zxing::IllegalArgumentException: " + string(e.what()); + res = -3; + } catch (zxing::Exception& e) { + cell_result = "zxing::Exception: " + string(e.what()); + res = -4; + } catch (std::exception& e) { + cell_result = "std::exception: " + string(e.what()); + res = -5; + } + cout << (hybrid ? "Hybrid" : "Global"); + if (res != 0){ + cout<<" binarizer failed: "<getText()->getText(); + if (show_format) { + cout << " " << barcodeFormatNames[results[i]->getBarcodeFormat()]; + } + cout << endl; + } + } + return res; +} + +int test_image_multi_hybrid(Image& image){ + return test_image_multi(image, true); +} + +int test_image_multi_global(Image& image){ + return test_image_multi(image, false); +} + string get_expected(string imagefilename) { string textfilename = imagefilename; int dotpos = textfilename.rfind("."); @@ -144,14 +214,14 @@ string get_expected(string imagefilename) { fseek(fp, 0, SEEK_END); int toread = ftell(fp); rewind(fp); - + if (toread > MAX_EXPECTED) { - cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread - << " bytes! Skipping..." << endl; + cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread + << " bytes! Skipping..." << endl; fclose(fp); return ""; } - + int nread = fread(data, sizeof(char), toread, fp); if (nread != toread) { cerr << "Could not read entire contents of file '" << textfilename << "'! Skipping..." << endl; @@ -166,7 +236,7 @@ string get_expected(string imagefilename) { int main(int argc, char** argv) { if (argc <= 1) { - cout << "Usage: " << argv[0] << " [--dump-raw] [--show-format] [--try-harder] [--show-filename] [ ...]" << endl; + cout << "Usage: " << argv[0] << " [--dump-raw] [--show-format] [--try-harder] [--search_multi] [--show-filename] [ ...]" << endl; return 1; } @@ -199,6 +269,10 @@ int main(int argc, char** argv) { show_filename = true; continue; } + if (infilename.compare("--search_multi") == 0){ + search_multi = true; + continue; + } if (!raw_dump) cerr << "Processing: " << infilename << endl; if (show_filename) @@ -214,27 +288,39 @@ int main(int argc, char** argv) { string expected; expected = get_expected(infilename); - int gresult = 1; - int hresult = 1; + if (search_multi){ + int gresult = 1; + int hresult = 1; + gresult = test_image_multi_global(image); + hresult = test_image_multi_hybrid(image); + gresult = gresult == 0; + hresult = hresult == 0; + gonly += gresult && !hresult; + honly += hresult && !gresult; + both += gresult && hresult; + neither += !gresult && !hresult; + total = total + 1; + } else { + int gresult = 1; + int hresult = 1; + hresult = test_image_hybrid(image, expected); + gresult = test_image_global(image, expected); + gresult = gresult == 0; + hresult = hresult == 0; - hresult = test_image_hybrid(image, expected); - gresult = test_image_global(image, expected); - - gresult = gresult == 0; - hresult = hresult == 0; - - gonly += gresult && !hresult; - honly += hresult && !gresult; - both += gresult && hresult; - neither += !gresult && !hresult; - total = total + 1; + gonly += gresult && !hresult; + honly += hresult && !gresult; + both += gresult && hresult; + neither += !gresult && !hresult; + total = total + 1; + } } if (!raw_dump) cout << (honly+both) << " passed hybrid, " << (gonly+both) << " passed global, " - << both << " pass both, " << neither << " pass neither, " << honly - << " passed only hybrid, " << gonly << " passed only global, of " << total - << " total." << endl; + << both << " pass both, " << neither << " pass neither, " << honly + << " passed only hybrid, " << gonly << " passed only global, of " << total + << " total." << endl; return 0; }