other) {
+ return posX_ == other->getX() && posY_ == other->getY();
+}
+
+/**
+ * Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and
+ * BC < AC and the angle between BC and BA is less than 180 degrees.
+ */
+void ResultPoint::orderBestPatterns(std::vector[ > &patterns) {
+ // Find distances between pattern centers
+ float zeroOneDistance = distance(patterns[0]->getX(), patterns[1]->getX(),patterns[0]->getY(), patterns[1]->getY());
+ float oneTwoDistance = distance(patterns[1]->getX(), patterns[2]->getX(),patterns[1]->getY(), patterns[2]->getY());
+ float zeroTwoDistance = distance(patterns[0]->getX(), patterns[2]->getX(),patterns[0]->getY(), patterns[2]->getY());
+
+ Ref pointA, pointB, pointC;
+ // Assume one closest to other two is B; A and C will just be guesses at first
+ if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
+ pointB = patterns[0];
+ pointA = patterns[1];
+ pointC = patterns[2];
+ } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
+ pointB = patterns[1];
+ pointA = patterns[0];
+ pointC = patterns[2];
+ } else {
+ pointB = patterns[2];
+ pointA = patterns[0];
+ pointC = patterns[1];
+ }
+
+ // Use cross product to figure out whether A and C are correct or flipped.
+ // This asks whether BC x BA has a positive z component, which is the arrangement
+ // we want for A, B, C. If it's negative, then we've got it flipped around and
+ // should swap A and C.
+ if (crossProductZ(pointA, pointB, pointC) < 0.0f) {
+ Ref temp = pointA;
+ pointA = pointC;
+ pointC = temp;
+ }
+
+ patterns[0] = pointA;
+ patterns[1] = pointB;
+ patterns[2] = pointC;
+}
+
+float ResultPoint::distance(Ref point1, Ref point2) {
+ return distance(point1->getX(), point1->getY(), point2->getX(), point2->getY());
+}
+
+float ResultPoint::distance(float x1, float x2, float y1, float y2) {
+ float xDiff = x1 - x2;
+ float yDiff = y1 - y2;
+ return (float) sqrt((double) (xDiff * xDiff + yDiff * yDiff));
+}
+
+float ResultPoint::crossProductZ(Ref pointA, Ref pointB, Ref pointC) {
+ float bX = pointB->getX();
+ float bY = pointB->getY();
+ return ((pointC->getX() - bX) * (pointA->getY() - bY)) - ((pointC->getY() - bY) * (pointA->getX() - bX));
+}
+}
+
+// file: zxing/ResultPointCallback.cpp
+
+/*
+ * ResultPointCallback.cpp
+ * zxing
+ *
+ * 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
+
+namespace zxing {
+
+ResultPointCallback::~ResultPointCallback() {}
+
+}
+
+// file: zxing/common/Array.cpp
+
+/*
+ * 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
+
+
+// file: zxing/common/BitArray.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * 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
+
+using namespace std;
+
+namespace zxing {
+
+
+size_t BitArray::wordsForBits(size_t bits) {
+ int arraySize = (bits + bitsPerWord_ - 1) >> logBits_;
+ return arraySize;
+}
+
+BitArray::BitArray(size_t size) :
+ size_(size), bits_(wordsForBits(size), (const unsigned int)0) {
+}
+
+BitArray::~BitArray() {
+}
+
+size_t BitArray::getSize() {
+ return size_;
+}
+
+void BitArray::setBulk(size_t i, unsigned int newBits) {
+ bits_[i >> logBits_] = newBits;
+}
+
+void BitArray::setRange(int start, int end) {
+ if (end < start) {
+ throw IllegalArgumentException("invalid call to BitArray::setRange");
+ }
+ if (end == start) {
+ return;
+ }
+ end--; // will be easier to treat this as the last actually set bit -- inclusive
+ int firstInt = start >> 5;
+ int lastInt = end >> 5;
+ for (int i = firstInt; i <= lastInt; i++) {
+ int firstBit = i > firstInt ? 0 : start & 0x1F;
+ int lastBit = i < lastInt ? 31 : end & 0x1F;
+ int mask;
+ if (firstBit == 0 && lastBit == 31) {
+ mask = -1;
+ } else {
+ mask = 0;
+ for (int j = firstBit; j <= lastBit; j++) {
+ mask |= 1 << j;
+ }
+ }
+ bits_[i] |= mask;
+ }
+}
+
+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 ? bitsPerWord_ - 1: end & bitsMask_;
+ unsigned int mask;
+ if (firstBit == 0 && lastBit == bitsPerWord_ - 1) {
+ 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;
+}
+
+vector& BitArray::getBitArray() {
+ return bits_;
+}
+
+void BitArray::reverse() {
+ std::vector newBits(bits_.size(),(const unsigned int) 0);
+ for (size_t i = 0; i < size_; i++) {
+ if (get(size_ - i - 1)) {
+ newBits[i >> logBits_] |= 1<< (i & bitsMask_);
+ }
+ }
+ bits_ = newBits;
+}
+}
+
+// file: zxing/common/BitMatrix.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * 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
+// #include
+// #include
+
+using std::ostream;
+using std::ostringstream;
+
+using zxing::BitMatrix;
+using zxing::BitArray;
+using zxing::Ref;
+
+namespace {
+ size_t wordsForSize(size_t width,
+ size_t height,
+ unsigned int bitsPerWord,
+ unsigned int logBits) {
+ size_t bits = width * height;
+ int arraySize = (bits + bitsPerWord - 1) >> logBits;
+ return arraySize;
+ }
+}
+
+BitMatrix::BitMatrix(size_t dimension) :
+ width_(dimension), height_(dimension), words_(0), bits_(NULL) {
+ words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
+ bits_ = new unsigned int[words_];
+ clear();
+}
+
+BitMatrix::BitMatrix(size_t width, size_t height) :
+ width_(width), height_(height), words_(0), bits_(NULL) {
+ words_ = wordsForSize(width_, height_, bitsPerWord, logBits);
+ bits_ = new unsigned int[words_];
+ clear();
+}
+
+BitMatrix::~BitMatrix() {
+ delete[] bits_;
+}
+
+
+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::fill(bits_, bits_+words_, 0);
+}
+
+void BitMatrix::setRegion(size_t left, size_t top, size_t width, size_t height) {
+ if ((long)top < 0 || (long)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);
+ }
+ }
+}
+
+Ref BitMatrix::getRow(int y, Ref row) {
+ if (row.empty() || row->getSize() < width_) {
+ row = new BitArray(width_);
+ } else {
+ row->clear();
+ }
+ size_t start = y * width_;
+ size_t end = start + width_ - 1; // end is inclusive
+ size_t firstWord = start >> logBits;
+ size_t lastWord = end >> logBits;
+ size_t bitOffset = start & bitsMask;
+ for (size_t i = firstWord; i <= lastWord; i++) {
+ size_t firstBit = i > firstWord ? 0 : start & bitsMask;
+ size_t lastBit = i < lastWord ? bitsPerWord - 1 : end & bitsMask;
+ unsigned int mask;
+ if (firstBit == 0 && lastBit == logBits) {
+ mask = std::numeric_limits::max();
+ } else {
+ mask = 0;
+ for (size_t j = firstBit; j <= lastBit; j++) {
+ mask |= 1 << j;
+ }
+ }
+ row->setBulk((i - firstWord) << logBits, (bits_[i] & mask) >> bitOffset);
+ if (firstBit == 0 && bitOffset != 0) {
+ unsigned int prevBulk = row->getBitArray()[i - firstWord - 1];
+ prevBulk |= (bits_[i] & mask) << (bitsPerWord - bitOffset);
+ row->setBulk((i - firstWord - 1) << logBits, prevBulk);
+ }
+ }
+ return row;
+}
+
+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() const {
+ return bits_;
+}
+
+namespace zxing {
+ ostream& operator<<(ostream &out, const 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();
+}
+
+// file: zxing/common/BitSource.cpp
+
+/*
+ * 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_;
+}
+}
+
+// file: zxing/common/CharacterSetECI.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * Copyright 2008-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
+
+using std::string;
+
+using zxing::common::CharacterSetECI;
+using zxing::IllegalArgumentException;
+
+std::map CharacterSetECI::VALUE_TO_ECI;
+std::map CharacterSetECI::NAME_TO_ECI;
+
+const bool CharacterSetECI::inited = CharacterSetECI::init_tables();
+
+bool CharacterSetECI::init_tables() {
+ addCharacterSet(0, "Cp437");
+ { char const* s[] = {"ISO8859_1", "ISO-8859-1", 0};
+ addCharacterSet(1, s); }
+ addCharacterSet(2, "Cp437");
+ { char const* s[] = {"ISO8859_1", "ISO-8859-1", 0};
+ addCharacterSet(3, s); }
+ addCharacterSet(4, "ISO8859_2");
+ addCharacterSet(5, "ISO8859_3");
+ addCharacterSet(6, "ISO8859_4");
+ addCharacterSet(7, "ISO8859_5");
+ addCharacterSet(8, "ISO8859_6");
+ addCharacterSet(9, "ISO8859_7");
+ addCharacterSet(10, "ISO8859_8");
+ addCharacterSet(11, "ISO8859_9");
+ addCharacterSet(12, "ISO8859_10");
+ addCharacterSet(13, "ISO8859_11");
+ addCharacterSet(15, "ISO8859_13");
+ addCharacterSet(16, "ISO8859_14");
+ addCharacterSet(17, "ISO8859_15");
+ addCharacterSet(18, "ISO8859_16");
+ { char const* s[] = {"SJIS", "Shift_JIS", 0};
+ addCharacterSet(20, s ); }
+ return true;
+}
+
+CharacterSetECI::CharacterSetECI(int value, char const* encodingName_)
+ : ECI(value), encodingName(encodingName_) {}
+
+char const* CharacterSetECI::getEncodingName() {
+ return encodingName;
+}
+
+void CharacterSetECI::addCharacterSet(int value, char const* encodingName) {
+ CharacterSetECI* eci = new CharacterSetECI(value, encodingName);
+ VALUE_TO_ECI[value] = eci; // can't use valueOf
+ NAME_TO_ECI[string(encodingName)] = eci;
+}
+
+void CharacterSetECI::addCharacterSet(int value, char const* const* encodingNames) {
+ CharacterSetECI* eci = new CharacterSetECI(value, encodingNames[0]);
+ VALUE_TO_ECI[value] = eci;
+ for (int i = 0; encodingNames[i]; i++) {
+ NAME_TO_ECI[string(encodingNames[i])] = eci;
+ }
+}
+
+CharacterSetECI* CharacterSetECI::getCharacterSetECIByValue(int value) {
+ if (value < 0 || value >= 900) {
+ std::ostringstream oss;
+ oss << "Bad ECI value: " << value;
+ throw IllegalArgumentException(oss.str().c_str());
+ }
+ return VALUE_TO_ECI[value];
+}
+
+CharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) {
+ return NAME_TO_ECI[name];
+}
+
+// file: zxing/common/Counted.cpp
+
+/*
+ * 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;
+}
+}
+
+// file: zxing/common/DecoderResult.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * DecoderResult.cpp
+ * zxing
+ *
+ * Created by Christian Brunschen on 20/05/2008.
+ * Copyright 2008-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
+
+using namespace std;
+using namespace zxing;
+
+DecoderResult::DecoderResult(ArrayRef rawBytes,
+ Ref text,
+ ArrayRef< ArrayRef >& byteSegments,
+ string const& ecLevel) :
+ rawBytes_(rawBytes),
+ text_(text),
+ byteSegments_(byteSegments),
+ ecLevel_(ecLevel) {}
+
+DecoderResult::DecoderResult(ArrayRef rawBytes,
+ Ref text)
+ : rawBytes_(rawBytes), text_(text) {}
+
+ArrayRef DecoderResult::getRawBytes() {
+ return rawBytes_;
+}
+
+Ref DecoderResult::getText() {
+ return text_;
+}
+
+// file: zxing/common/DetectorResult.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * 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_;
+}
+
+}
+
+// file: zxing/common/ECI.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * Copyright 2008-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
+
+using zxing::common::ECI;
+using zxing::IllegalArgumentException;
+
+ECI::ECI(int value_) : value(value_) {}
+
+int ECI::getValue() const {
+ return value;
+}
+
+ECI* ECI::getECIByValue(int value) {
+ if (value < 0 || value > 999999) {
+ std::ostringstream oss;
+ oss << "Bad ECI value: " << value;
+ throw IllegalArgumentException(oss.str().c_str());
+ }
+ if (value < 900) { // Character set ECIs use 000000 - 000899
+ return CharacterSetECI::getCharacterSetECIByValue(value);
+ }
+ return 0;
+}
+
+// file: zxing/common/EdgeDetector.cpp
+
+/*
+ * 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
+// #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
+
+// file: zxing/common/GlobalHistogramBinarizer.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * GlobalHistogramBinarizer.cpp
+ * zxing
+ *
+ * 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 {
+using namespace std;
+
+const int LUMINANCE_BITS_25 = 5;
+const int LUMINANCE_SHIFT_25 = 8 - LUMINANCE_BITS_25;
+const int LUMINANCE_BUCKETS_25 = 1 << LUMINANCE_BITS_25;
+
+GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref source) :
+ Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {
+
+}
+
+GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
+}
+
+
+Ref GlobalHistogramBinarizer::getBlackRow(int y, Ref row) {
+ if (y == cached_row_num_) {
+ if (cached_row_ != NULL) {
+ return cached_row_;
+ } else {
+ throw IllegalArgumentException("Too little dynamic range in luminance");
+ }
+ }
+
+ vector histogram(LUMINANCE_BUCKETS_25, 0);
+ LuminanceSource& source = *getLuminanceSource();
+ int width = source.getWidth();
+ if (row == NULL || static_cast(row->getSize()) < width) {
+ row = new BitArray(width);
+ } else {
+ row->clear();
+ }
+
+ //TODO(flyashi): cache this instead of allocating and deleting per row
+ unsigned char* row_pixels = NULL;
+ try {
+ row_pixels = new unsigned char[width];
+ row_pixels = source.getRow(y, row_pixels);
+ for (int x = 0; x < width; x++) {
+ histogram[row_pixels[x] >> LUMINANCE_SHIFT_25]++;
+ }
+ int blackPoint = estimate(histogram);
+
+ BitArray& array = *row;
+ int left = row_pixels[0];
+ int center = row_pixels[1];
+ for (int x = 1; x < width - 1; x++) {
+ int right = row_pixels[x + 1];
+ // 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;
+ }
+
+ cached_row_ = row;
+ cached_row_num_ = y;
+ delete [] row_pixels;
+ return row;
+ } catch (IllegalArgumentException const& iae) {
+ // Cache the fact that this row failed.
+ cached_row_ = NULL;
+ cached_row_num_ = y;
+ delete [] row_pixels;
+ throw iae;
+ }
+}
+
+Ref GlobalHistogramBinarizer::getBlackMatrix() {
+ if (cached_matrix_ != NULL) {
+ return cached_matrix_;
+ }
+
+ // Faster than working with the reference
+ LuminanceSource& source = *getLuminanceSource();
+ int width = source.getWidth();
+ int height = source.getHeight();
+ vector histogram(LUMINANCE_BUCKETS_25, 0);
+
+ // 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.
+ ArrayRef ref (width);
+ unsigned char* row = &ref[0];
+ for (int y = 1; y < 5; y++) {
+ int rownum = height * y / 5;
+ int right = (width << 2) / 5;
+ row = source.getRow(rownum, row);
+ for (int x = width / 5; x < right; x++) {
+ histogram[row[x] >> LUMINANCE_SHIFT_25]++;
+ }
+ }
+
+ int blackPoint = estimate(histogram);
+
+ Ref matrix_ref(new BitMatrix(width, height));
+ BitMatrix& matrix = *matrix_ref;
+ for (int y = 0; y < height; y++) {
+ row = source.getRow(y, row);
+ for (int x = 0; x < width; x++) {
+ if (row[x] < blackPoint)
+ matrix.set(x, y);
+ }
+ }
+
+ cached_matrix_ = matrix_ref;
+ // delete [] row;
+ return matrix_ref;
+}
+
+int GlobalHistogramBinarizer::estimate(vector &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 << LUMINANCE_SHIFT_25;
+}
+
+Ref GlobalHistogramBinarizer::createBinarizer(Ref source) {
+ return Ref (new GlobalHistogramBinarizer(source));
+}
+
+} // namespace zxing
+
+// file: zxing/common/GreyscaleLuminanceSource.cpp
+
+/*
+ * GreyscaleLuminanceSource.cpp
+ * zxing
+ *
+ * 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 {
+
+GreyscaleLuminanceSource::GreyscaleLuminanceSource(unsigned char* greyData, int dataWidth,
+ int dataHeight, int left, int top, int width, int height) : greyData_(greyData),
+ dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),
+ height_(height) {
+
+ if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) {
+ throw IllegalArgumentException("Crop rectangle does not fit within image data.");
+ }
+}
+
+unsigned char* GreyscaleLuminanceSource::getRow(int y, unsigned char* row) {
+ if (y < 0 || y >= this->getHeight()) {
+ throw IllegalArgumentException("Requested row is outside the image: " + y);
+ }
+ int width = getWidth();
+ // TODO(flyashi): determine if row has enough size.
+ if (row == NULL) {
+ row = new unsigned char[width_];
+ }
+ int offset = (y + top_) * dataWidth_ + left_;
+ memcpy(row, &greyData_[offset], width);
+ return row;
+}
+
+unsigned char* GreyscaleLuminanceSource::getMatrix() {
+ int size = width_ * height_;
+ unsigned char* result = new unsigned char[size];
+ if (left_ == 0 && top_ == 0 && dataWidth_ == width_ && dataHeight_ == height_) {
+ memcpy(result, greyData_, size);
+ } else {
+ for (int row = 0; row < height_; row++) {
+ memcpy(result + row * width_, greyData_ + (top_ + row) * dataWidth_ + left_, width_);
+ }
+ }
+ return result;
+}
+
+Ref GreyscaleLuminanceSource::rotateCounterClockwise() {
+ // Intentionally flip the left, top, width, and height arguments as needed. dataWidth and
+ // dataHeight are always kept unrotated.
+ return Ref (new GreyscaleRotatedLuminanceSource(greyData_, dataWidth_,
+ dataHeight_, top_, left_, height_, width_));
+}
+
+} /* namespace */
+
+// file: zxing/common/GreyscaleRotatedLuminanceSource.cpp
+
+/*
+ * GreyscaleRotatedLuminanceSource.cpp
+ * zxing
+ *
+ * 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 {
+
+// Note that dataWidth and dataHeight are not reversed, as we need to be able to traverse the
+// greyData correctly, which does not get rotated.
+GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(unsigned char* greyData,
+ int dataWidth, int dataHeight, int left, int top, int width, int height) : greyData_(greyData),
+ dataWidth_(dataWidth), dataHeight_(dataHeight), left_(left), top_(top), width_(width),
+ height_(height) {
+
+ // Intentionally comparing to the opposite dimension since we're rotated.
+ if (left + width > dataHeight || top + height > dataWidth) {
+ throw IllegalArgumentException("Crop rectangle does not fit within image data.");
+ }
+}
+
+// The API asks for rows, but we're rotated, so we return columns.
+unsigned char* GreyscaleRotatedLuminanceSource::getRow(int y, unsigned char* row) {
+ if (y < 0 || y >= getHeight()) {
+ throw IllegalArgumentException("Requested row is outside the image: " + y);
+ }
+ int width = getWidth();
+ if (row == NULL) {
+ row = new unsigned char[width];
+ }
+ int offset = (left_ * dataWidth_) + (dataWidth_ - (y + top_));
+ for (int x = 0; x < width; x++) {
+ row[x] = greyData_[offset];
+ offset += dataWidth_;
+ }
+ return row;
+}
+
+unsigned char* GreyscaleRotatedLuminanceSource::getMatrix() {
+ unsigned char* result = new unsigned char[width_ * height_];
+ // This depends on getRow() honoring its second parameter.
+ for (int y = 0; y < height_; y++) {
+ getRow(y, &result[y * width_]);
+ }
+ return result;
+}
+
+} // namespace
+
+// file: zxing/common/GridSampler.cpp
+
+/*
+ * 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));
+ vector points(dimension << 1, (const float)0.0f);
+ 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 dimensionX, int dimensionY, Ref transform) {
+ Ref bits(new BitMatrix(dimensionX, dimensionY));
+ vector points(dimensionX << 1, (const float)0.0f);
+ for (int y = 0; y < dimensionY; 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, vector &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;
+}
+}
+
+// file: zxing/common/HybridBinarizer.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+/*
+ * HybridBinarizer.cpp
+ * zxing
+ *
+ * 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
+
+using namespace std;
+using namespace zxing;
+
+namespace {
+ const int BLOCK_SIZE_POWER = 3;
+ const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER;
+ const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1;
+ const int MINIMUM_DIMENSION = BLOCK_SIZE * 5;
+}
+
+HybridBinarizer::HybridBinarizer(Ref source) :
+ GlobalHistogramBinarizer(source), matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {
+}
+
+HybridBinarizer::~HybridBinarizer() {
+}
+
+
+Ref
+HybridBinarizer::createBinarizer(Ref source) {
+ return Ref (new HybridBinarizer(source));
+}
+
+Ref HybridBinarizer::getBlackMatrix() {
+ // 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.
+ if (matrix_) {
+ return matrix_;
+ }
+ LuminanceSource& source = *getLuminanceSource();
+ if (source.getWidth() >= MINIMUM_DIMENSION &&
+ source.getHeight() >= MINIMUM_DIMENSION) {
+ unsigned char* luminances = source.getMatrix();
+ int width = source.getWidth();
+ int height = source.getHeight();
+ int subWidth = width >> BLOCK_SIZE_POWER;
+ if ((width & BLOCK_SIZE_MASK) != 0) {
+ subWidth++;
+ }
+ int subHeight = height >> BLOCK_SIZE_POWER;
+ if ((height & BLOCK_SIZE_MASK) != 0) {
+ subHeight++;
+ }
+ int* blackPoints =
+ calculateBlackPoints(luminances, subWidth, subHeight, width, height);
+
+ Ref newMatrix (new BitMatrix(width, height));
+ calculateThresholdForBlock(luminances,
+ subWidth,
+ subHeight,
+ width,
+ height,
+ blackPoints,
+ newMatrix);
+ matrix_ = newMatrix;
+
+ // N.B.: these deletes are inadequate if anything between the new
+ // and this point can throw. As of this writing, it doesn't look
+ // like they do.
+
+ delete [] blackPoints;
+ delete [] luminances;
+ } else {
+ // If the image is too small, fall back to the global histogram approach.
+ matrix_ = GlobalHistogramBinarizer::getBlackMatrix();
+ }
+ return matrix_;
+}
+
+void
+HybridBinarizer::calculateThresholdForBlock(unsigned char* luminances,
+ int subWidth,
+ int subHeight,
+ int width,
+ int height,
+ int blackPoints[],
+ Ref const& matrix) {
+ for (int y = 0; y < subHeight; y++) {
+ int yoffset = y << BLOCK_SIZE_POWER;
+ if (yoffset + BLOCK_SIZE >= height) {
+ yoffset = height - BLOCK_SIZE;
+ }
+ for (int x = 0; x < subWidth; x++) {
+ int xoffset = x << BLOCK_SIZE_POWER;
+ if (xoffset + BLOCK_SIZE >= width) {
+ xoffset = width - BLOCK_SIZE;
+ }
+ int left = (x > 1) ? x : 2;
+ left = (left < subWidth - 2) ? left : subWidth - 3;
+ int top = (y > 1) ? y : 2;
+ top = (top < subHeight - 2) ? top : subHeight - 3;
+ int sum = 0;
+ for (int z = -2; z <= 2; z++) {
+ int *blackRow = &blackPoints[(top + z) * subWidth];
+ sum += blackRow[left - 2];
+ sum += blackRow[left - 1];
+ sum += blackRow[left];
+ sum += blackRow[left + 1];
+ sum += blackRow[left + 2];
+ }
+ int average = sum / 25;
+ threshold8x8Block(luminances, xoffset, yoffset, average, width, matrix);
+ }
+ }
+}
+
+void HybridBinarizer::threshold8x8Block(unsigned char* luminances,
+ int xoffset,
+ int yoffset,
+ int threshold,
+ int stride,
+ Ref const& matrix) {
+ for (int y = 0, offset = yoffset * stride + xoffset;
+ y < BLOCK_SIZE;
+ y++, offset += stride) {
+ for (int x = 0; x < BLOCK_SIZE; x++) {
+ int pixel = luminances[offset + x] & 0xff;
+ if (pixel <= threshold) {
+ matrix->set(xoffset + x, yoffset + y);
+ }
+ }
+ }
+}
+
+namespace {
+ inline int getBlackPointFromNeighbors(int* blackPoints, int subWidth, int x, int y) {
+ return (blackPoints[(y-1)*subWidth+x] +
+ 2*blackPoints[y*subWidth+x-1] +
+ blackPoints[(y-1)*subWidth+x-1]) >> 2;
+ }
+}
+
+int* HybridBinarizer::calculateBlackPoints(unsigned char* luminances, int subWidth, int subHeight,
+ int width, int height) {
+ int *blackPoints = new int[subHeight * subWidth];
+ for (int y = 0; y < subHeight; y++) {
+ int yoffset = y << BLOCK_SIZE_POWER;
+ if (yoffset + BLOCK_SIZE >= height) {
+ yoffset = height - BLOCK_SIZE;
+ }
+ for (int x = 0; x < subWidth; x++) {
+ int xoffset = x << BLOCK_SIZE_POWER;
+ if (xoffset + BLOCK_SIZE >= width) {
+ xoffset = width - BLOCK_SIZE;
+ }
+ int sum = 0;
+ int min = 0xFF;
+ int max = 0;
+ for (int yy = 0, offset = yoffset * width + xoffset;
+ yy < BLOCK_SIZE;
+ yy++, offset += width) {
+ for (int xx = 0; xx < BLOCK_SIZE; xx++) {
+ int pixel = luminances[offset + xx] & 0xFF;
+ sum += pixel;
+ if (pixel < min) {
+ min = pixel;
+ }
+ if (pixel > max) {
+ max = pixel;
+ }
+ }
+ }
+
+ // See
+ // http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
+ int average = sum >> 6;
+ if (max - min <= 24) {
+ average = min >> 1;
+ if (y > 0 && x > 0) {
+ int bp = getBlackPointFromNeighbors(blackPoints, subWidth, x, y);
+ if (min < bp) {
+ average = bp;
+ }
+ }
+ }
+ blackPoints[y * subWidth + x] = average;
+ }
+ }
+ return blackPoints;
+}
+
+
+// file: zxing/common/IllegalArgumentException.cpp
+
+/*
+ * 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() {
+
+}
+}
+
+// file: zxing/common/PerspectiveTransform.cpp
+
+/*
+ * 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 inA11, float inA21,
+ float inA31, float inA12,
+ float inA22, float inA32,
+ float inA13, float inA23,
+ float inA33) :
+ a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),
+ a31(inA31), a32(inA32), a33(inA33) {}
+
+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(vector &points) {
+ int max = points.size();
+ 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, const 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;
+}
+
+}
+
+// file: zxing/common/Str.cpp
+
+/*
+ * 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) {
+}
+const std::string& String::getText() const {
+ return text_;
+}
+
+ostream &operator<<(ostream &out, const String &s) {
+ out << s.text_;
+ return out;
+}
+
+}
+
+// file: zxing/common/StringUtils.cpp
+
+// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
+
+/*
+ * Copyright (C) 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+using namespace zxing;
+using namespace zxing::common;
+
+// N.B.: these are the iconv strings for at least some versions of iconv
+
+char const* const StringUtils::PLATFORM_DEFAULT_ENCODING = "UTF-8";
+char const* const StringUtils::ASCII = "ASCII";
+char const* const StringUtils::SHIFT_JIS = "SHIFT_JIS";
+char const* const StringUtils::GB2312 = "GBK";
+char const* const StringUtils::EUC_JP = "EUC-JP";
+char const* const StringUtils::UTF8 = "UTF-8";
+char const* const StringUtils::ISO88591 = "ISO8859-1";
+const bool StringUtils::ASSUME_SHIFT_JIS = false;
+
+string
+StringUtils::guessEncoding(unsigned char* bytes, int length, Hashtable const& hints) {
+ Hashtable::const_iterator i = hints.find(DecodeHints::CHARACTER_SET);
+ if (i != hints.end()) {
+ return i->second;
+ }
+ // 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 canBeShiftJIS = true;
+ bool canBeUTF8 = true;
+ int utf8BytesLeft = 0;
+ int maybeDoubleByteCount = 0;
+ int maybeSingleByteKatakanaCount = 0;
+ bool sawLatin1Supplement = false;
+ bool sawUTF8Start = false;
+ bool lastWasPossibleDoubleByteStart = false;
+
+ for (int i = 0;
+ i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8);
+ i++) {
+
+ int value = bytes[i] & 0xFF;
+
+ // UTF-8 stuff
+ if (value >= 0x80 && value <= 0xBF) {
+ if (utf8BytesLeft > 0) {
+ utf8BytesLeft--;
+ }
+ } else {
+ if (utf8BytesLeft > 0) {
+ canBeUTF8 = false;
+ }
+ if (value >= 0xC0 && value <= 0xFD) {
+ sawUTF8Start = true;
+ int valueCopy = value;
+ while ((valueCopy & 0x40) != 0) {
+ utf8BytesLeft++;
+ valueCopy <<= 1;
+ }
+ }
+ }
+
+ // ISO-8859-1 stuff
+
+ if ((value == 0xC2 || value == 0xC3) && i < length - 1) {
+ // This is really a poor hack. The slightly more exotic characters people might want to put in
+ // a QR Code, by which I mean the Latin-1 supplement characters (e.g. u-umlaut) have encodings
+ // that start with 0xC2 followed by [0xA0,0xBF], or start with 0xC3 followed by [0x80,0xBF].
+ int nextValue = bytes[i + 1] & 0xFF;
+ if (nextValue <= 0xBF &&
+ ((value == 0xC2 && nextValue >= 0xA0) || (value == 0xC3 && nextValue >= 0x80))) {
+ sawLatin1Supplement = true;
+ }
+ }
+ if (value >= 0x7F && value <= 0x9F) {
+ canBeISO88591 = false;
+ }
+
+ // Shift_JIS stuff
+
+ if (value >= 0xA1 && value <= 0xDF) {
+ // count the number of characters that might be a Shift_JIS single-byte Katakana character
+ if (!lastWasPossibleDoubleByteStart) {
+ maybeSingleByteKatakanaCount++;
+ }
+ }
+ if (!lastWasPossibleDoubleByteStart &&
+ ((value >= 0xF0 && value <= 0xFF) || value == 0x80 || value == 0xA0)) {
+ canBeShiftJIS = false;
+ }
+ if ((value >= 0x81 && value <= 0x9F) || (value >= 0xE0 && value <= 0xEF)) {
+ // These start double-byte characters in Shift_JIS. Let's see if it's followed by a valid
+ // second byte.
+ 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 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;
+ if (i >= length - 1) {
+ canBeShiftJIS = false;
+ } else {
+ int nextValue = bytes[i + 1] & 0xFF;
+ if (nextValue < 0x40 || nextValue > 0xFC) {
+ canBeShiftJIS = false;
+ } else {
+ maybeDoubleByteCount++;
+ }
+ // There is some conflicting information out there about which bytes can follow which in
+ // double-byte Shift_JIS characters. The rule above seems to be the one that matches practice.
+ }
+ }
+ } else {
+ lastWasPossibleDoubleByteStart = false;
+ }
+ }
+ if (utf8BytesLeft > 0) {
+ canBeUTF8 = false;
+ }
+
+ // Easy -- if assuming Shift_JIS and no evidence it can't be, done
+ if (canBeShiftJIS && ASSUME_SHIFT_JIS) {
+ return SHIFT_JIS;
+ }
+ if (canBeUTF8 && sawUTF8Start) {
+ return UTF8;
+ }
+ // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough. The crude heuristic is:
+ // - If we saw
+ // - at least 3 bytes that starts a double-byte value (bytes that are rare in ISO-8859-1), or
+ // - over 5% of bytes could be single-byte Katakana (also rare in ISO-8859-1),
+ // - and, saw no sequences that are invalid in Shift_JIS, then we conclude Shift_JIS
+ if (canBeShiftJIS && (maybeDoubleByteCount >= 3 || 20 * maybeSingleByteKatakanaCount > length)) {
+ return SHIFT_JIS;
+ }
+ // Otherwise, we default to ISO-8859-1 unless we know it can't be
+ if (!sawLatin1Supplement && canBeISO88591) {
+ return ISO88591;
+ }
+ // Otherwise, we take a wild guess with platform encoding
+ return PLATFORM_DEFAULT_ENCODING;
+}
+
+// file: zxing/common/detector/MonochromeRectangleDetector.cpp
+
+/*
+ * MonochromeRectangleDetector.cpp
+ * y_wmk
+ *
+ * Created by Luiz Silva on 09/02/2010.
+ * Copyright 2010 y_wmk 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 {
+using namespace std;
+
+std::vector][ > MonochromeRectangleDetector::detect() {
+ int height = image_->getHeight();
+ int width = image_->getWidth();
+ int halfHeight = height >> 1;
+ int halfWidth = width >> 1;
+ int deltaY = max(1, height / (MAX_MODULES << 3));
+ int deltaX = max(1, width / (MAX_MODULES << 3));
+
+ int top = 0;
+ int bottom = height;
+ int left = 0;
+ int right = width;
+ Ref pointA(findCornerFromCenter(halfWidth, 0, left, right,
+ halfHeight, -deltaY, top, bottom, halfWidth >> 1));
+ top = (int) pointA->getY() - 1;;
+ Ref pointB(findCornerFromCenter(halfWidth, -deltaX, left, right,
+ halfHeight, 0, top, bottom, halfHeight >> 1));
+ left = (int) pointB->getX() - 1;
+ Ref pointC(findCornerFromCenter(halfWidth, deltaX, left, right,
+ halfHeight, 0, top, bottom, halfHeight >> 1));
+ right = (int) pointC->getX() + 1;
+ Ref pointD(findCornerFromCenter(halfWidth, 0, left, right,
+ halfHeight, deltaY, top, bottom, halfWidth >> 1));
+ bottom = (int) pointD->getY() + 1;
+
+ // Go try to find point A again with better information -- might have been off at first.
+ pointA.reset(findCornerFromCenter(halfWidth, 0, left, right,
+ halfHeight, -deltaY, top, bottom, halfWidth >> 2));
+
+ std::vector][ > corners(4);
+ corners[0].reset(pointA);
+ corners[1].reset(pointB);
+ corners[2].reset(pointC);
+ corners[3].reset(pointD);
+ return corners;
+ }
+
+Ref MonochromeRectangleDetector::findCornerFromCenter(int centerX, int deltaX, int left, int right,
+ int centerY, int deltaY, int top, int bottom, int maxWhiteRun) {
+ Ref lastRange(NULL);
+ for (int y = centerY, x = centerX;
+ y < bottom && y >= top && x < right && x >= left;
+ y += deltaY, x += deltaX) {
+ Ref range(NULL);
+ if (deltaX == 0) {
+ // horizontal slices, up and down
+ range = blackWhiteRange(y, maxWhiteRun, left, right, true);
+ } else {
+ // vertical slices, left and right
+ range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
+ }
+ if (range == NULL) {
+ if (lastRange == NULL) {
+ throw NotFoundException("Couldn't find corners (lastRange = NULL) ");
+ } else {
+ // lastRange was found
+ if (deltaX == 0) {
+ int lastY = y - deltaY;
+ if (lastRange->start < centerX) {
+ if (lastRange->end > centerX) {
+ // straddle, choose one or the other based on direction
+ Ref result(new ResultPoint(deltaY > 0 ? lastRange->start : lastRange->end, lastY));
+ return result;
+ }
+ Ref result(new ResultPoint(lastRange->start, lastY));
+ return result;
+ } else {
+ Ref result(new ResultPoint(lastRange->end, lastY));
+ return result;
+ }
+ } else {
+ int lastX = x - deltaX;
+ if (lastRange->start < centerY) {
+ if (lastRange->end > centerY) {
+ Ref result(new ResultPoint(lastX, deltaX < 0 ? lastRange->start : lastRange->end));
+ return result;
+ }
+ Ref result(new ResultPoint(lastX, lastRange->start));
+ return result;
+ } else {
+ Ref result(new ResultPoint(lastX, lastRange->end));
+ return result;
+ }
+ }
+ }
+ }
+ lastRange = range;
+ }
+ throw NotFoundException("Couldn't find corners");
+ }
+
+Ref MonochromeRectangleDetector::blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim,
+ bool horizontal) {
+
+ int center = (minDim + maxDim) >> 1;
+
+ // Scan left/up first
+ int start = center;
+ while (start >= minDim) {
+ if (horizontal ? image_->get(start, fixedDimension) : image_->get(fixedDimension, start)) {
+ start--;
+ } else {
+ int whiteRunStart = start;
+ do {
+ start--;
+ } while (start >= minDim && !(horizontal ? image_->get(start, fixedDimension) :
+ image_->get(fixedDimension, start)));
+ int whiteRunSize = whiteRunStart - start;
+ if (start < minDim || whiteRunSize > maxWhiteRun) {
+ start = whiteRunStart;
+ break;
+ }
+ }
+ }
+ start++;
+
+ // Then try right/down
+ int end = center;
+ while (end < maxDim) {
+ if (horizontal ? image_->get(end, fixedDimension) : image_->get(fixedDimension, end)) {
+ end++;
+ } else {
+ int whiteRunStart = end;
+ do {
+ end++;
+ } while (end < maxDim && !(horizontal ? image_->get(end, fixedDimension) :
+ image_->get(fixedDimension, end)));
+ int whiteRunSize = end - whiteRunStart;
+ if (end >= maxDim || whiteRunSize > maxWhiteRun) {
+ end = whiteRunStart;
+ break;
+ }
+ }
+ }
+ end--;
+ Ref result(NULL);
+ if (end > start) {
+ result = new TwoInts;
+ result->start = start;
+ result->end = end;
+ }
+ return result;
+ }
+}
+
+// file: zxing/common/detector/WhiteRectangleDetector.cpp
+
+/*
+ * WhiteRectangleDetector.cpp
+ * y_wmk
+ *
+ * Created by Luiz Silva on 09/02/2010.
+ * Copyright 2010 y_wmk 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 {
+using namespace std;
+
+int WhiteRectangleDetector::INIT_SIZE = 30;
+int WhiteRectangleDetector::CORR = 1;
+
+
+WhiteRectangleDetector::WhiteRectangleDetector(Ref image) : image_(image) {
+ width_ = image->getWidth();
+ height_ = image->getHeight();
+}
+
+/**
+ * ]
+ * Detects a candidate barcode-like rectangular region within an image. It
+ * starts around the center of the image, increases the size of the candidate
+ * region until it finds a white rectangular region.
+ *
+ *
+ * @return {@link vector[ >} describing the corners of the rectangular
+ * region. The first and last points are opposed on the diagonal, as
+ * are the second and third. The first point will be the topmost
+ * point and the last, the bottommost. The second point will be
+ * leftmost and the third, the rightmost
+ * @throws NotFoundException if no Data Matrix Code can be found
+*/
+std::vector][ > WhiteRectangleDetector::detect() {
+ int left = (width_ - INIT_SIZE) >> 1;
+ int right = (width_ + INIT_SIZE) >> 1;
+ int up = (height_ - INIT_SIZE) >> 1;
+ int down = (height_ + INIT_SIZE) >> 1;
+ if (up < 0 || left < 0 || down >= height_ || right >= width_) {
+ throw NotFoundException("Invalid dimensions WhiteRectangleDetector");
+ }
+
+ bool sizeExceeded = false;
+ bool aBlackPointFoundOnBorder = true;
+ bool atLeastOneBlackPointFoundOnBorder = false;
+
+ while (aBlackPointFoundOnBorder) {
+ aBlackPointFoundOnBorder = false;
+
+ // .....
+ // . |
+ // .....
+ bool rightBorderNotWhite = true;
+ while (rightBorderNotWhite && right < width_) {
+ rightBorderNotWhite = containsBlackPoint(up, down, right, false);
+ if (rightBorderNotWhite) {
+ right++;
+ aBlackPointFoundOnBorder = true;
+ }
+ }
+
+ if (right >= width_) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // . .
+ // .___.
+ bool bottomBorderNotWhite = true;
+ while (bottomBorderNotWhite && down < height_) {
+ bottomBorderNotWhite = containsBlackPoint(left, right, down, true);
+ if (bottomBorderNotWhite) {
+ down++;
+ aBlackPointFoundOnBorder = true;
+ }
+ }
+
+ if (down >= height_) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .....
+ // | .
+ // .....
+ bool leftBorderNotWhite = true;
+ while (leftBorderNotWhite && left >= 0) {
+ leftBorderNotWhite = containsBlackPoint(up, down, left, false);
+ if (leftBorderNotWhite) {
+ left--;
+ aBlackPointFoundOnBorder = true;
+ }
+ }
+
+ if (left < 0) {
+ sizeExceeded = true;
+ break;
+ }
+
+ // .___.
+ // . .
+ // .....
+ bool topBorderNotWhite = true;
+ while (topBorderNotWhite && up >= 0) {
+ topBorderNotWhite = containsBlackPoint(left, right, up, true);
+ if (topBorderNotWhite) {
+ up--;
+ aBlackPointFoundOnBorder = true;
+ }
+ }
+
+ if (up < 0) {
+ sizeExceeded = true;
+ break;
+ }
+
+ if (aBlackPointFoundOnBorder) {
+ atLeastOneBlackPointFoundOnBorder = true;
+ }
+
+ }
+ if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
+
+ int maxSize = right - left;
+
+ Ref z(NULL);
+ //go up right
+ for (int i = 1; i < maxSize; i++) {
+ z = getBlackPointOnSegment(left, down - i, left + i, down);
+ if (z != NULL) {
+ break;
+ }
+ }
+
+ if (z == NULL) {
+ throw NotFoundException("z == NULL");
+ }
+
+ Ref t(NULL);
+ //go down right
+ for (int i = 1; i < maxSize; i++) {
+ t = getBlackPointOnSegment(left, up + i, left + i, up);
+ if (t != NULL) {
+ break;
+ }
+ }
+
+ if (t == NULL) {
+ throw NotFoundException("t == NULL");
+ }
+
+ Ref x(NULL);
+ //go down left
+ for (int i = 1; i < maxSize; i++) {
+ x = getBlackPointOnSegment(right, up + i, right - i, up);
+ if (x != NULL) {
+ break;
+ }
+ }
+
+ if (x == NULL) {
+ throw NotFoundException("x == NULL");
+ }
+
+ Ref y(NULL);
+ //go up left
+ for (int i = 1; i < maxSize; i++) {
+ y = getBlackPointOnSegment(right, down - i, right - i, down);
+ if (y != NULL) {
+ break;
+ }
+ }
+
+ if (y == NULL) {
+ throw NotFoundException("y == NULL");
+ }
+
+ return centerEdges(y, z, x, t);
+
+ } else {
+ throw NotFoundException("No black point found on border");
+ }
+}
+
+/**
+ * Ends up being a bit faster than Math.round(). This merely rounds its
+ * argument to the nearest int, where x.5 rounds up.
+ */
+int WhiteRectangleDetector::round(float d) {
+ return (int) (d + 0.5f);
+}
+
+Ref WhiteRectangleDetector::getBlackPointOnSegment(float aX, float aY, float bX, float bY) {
+ int dist = distanceL2(aX, aY, bX, bY);
+ float xStep = (bX - aX) / dist;
+ float yStep = (bY - aY) / dist;
+ for (int i = 0; i < dist; i++) {
+ int x = round(aX + i * xStep);
+ int y = round(aY + i * yStep);
+ if (image_->get(x, y)) {
+ Ref point(new ResultPoint(x, y));
+ return point;
+ }
+ }
+ Ref point(NULL);
+ return point;
+}
+
+int WhiteRectangleDetector::distanceL2(float aX, float aY, float bX, float bY) {
+ float xDiff = aX - bX;
+ float yDiff = aY - bY;
+ return round((float)sqrt(xDiff * xDiff + yDiff * yDiff));
+}
+
+/**
+ * recenters the points of a constant distance towards the center
+ *
+ * @param y bottom most point
+ * @param z left most point
+ * @param x right most point
+ * @param t top most point
+ * @return {@link vector][ >} describing the corners of the rectangular
+ * region. The first and last points are opposed on the diagonal, as
+ * are the second and third. The first point will be the topmost
+ * point and the last, the bottommost. The second point will be
+ * leftmost and the third, the rightmost
+ */
+vector][ > WhiteRectangleDetector::centerEdges(Ref y, Ref z,
+ Ref x, Ref t) {
+
+ //
+ // t t
+ // z x
+ // x OR z
+ // y y
+ //
+
+ float yi = y->getX();
+ float yj = y->getY();
+ float zi = z->getX();
+ float zj = z->getY();
+ float xi = x->getX();
+ float xj = x->getY();
+ float ti = t->getX();
+ float tj = t->getY();
+
+ std::vector][ > corners(4);
+ if (yi < (float)width_/2) {
+ Ref pointA(new ResultPoint(ti - CORR, tj + CORR));
+ Ref pointB(new ResultPoint(zi + CORR, zj + CORR));
+ Ref pointC(new ResultPoint(xi - CORR, xj - CORR));
+ Ref pointD(new ResultPoint(yi + CORR, yj - CORR));
+ corners[0].reset(pointA);
+ corners[1].reset(pointB);
+ corners[2].reset(pointC);
+ corners[3].reset(pointD);
+ } else {
+ Ref pointA(new ResultPoint(ti + CORR, tj + CORR));
+ Ref pointB(new ResultPoint(zi + CORR, zj - CORR));
+ Ref pointC(new ResultPoint(xi - CORR, xj + CORR));
+ Ref pointD(new ResultPoint(yi - CORR, yj - CORR));
+ corners[0].reset(pointA);
+ corners[1].reset(pointB);
+ corners[2].reset(pointC);
+ corners[3].reset(pointD);
+ }
+ return corners;
+}
+
+/**
+ * Determines whether a segment contains a black point
+ *
+ * @param a min value of the scanned coordinate
+ * @param b max value of the scanned coordinate
+ * @param fixed value of fixed coordinate
+ * @param horizontal set to true if scan must be horizontal, false if vertical
+ * @return true if a black point has been found, else false.
+ */
+bool WhiteRectangleDetector::containsBlackPoint(int a, int b, int fixed, bool horizontal) {
+ if (horizontal) {
+ for (int x = a; x <= b; x++) {
+ if (image_->get(x, fixed)) {
+ return true;
+ }
+ }
+ } else {
+ for (int y = a; y <= b; y++) {
+ if (image_->get(fixed, y)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+}
+
+// file: zxing/common/reedsolomon/GF256.cpp
+
+/*
+ * 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 ]