You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.2 KiB
175 lines
4.2 KiB
/* |
|
* Copyright 2016 Nu-book Inc. |
|
* Copyright 2016 ZXing authors |
|
*/ |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#include "BitMatrix.h" |
|
|
|
#include "Pattern.h" |
|
|
|
#include <algorithm> |
|
#include <stdexcept> |
|
#include <utility> |
|
|
|
namespace ZXing { |
|
|
|
void |
|
BitMatrix::setRegion(int left, int top, int width, int height) |
|
{ |
|
if (top < 0 || left < 0) { |
|
throw std::invalid_argument("BitMatrix::setRegion(): Left and top must be nonnegative"); |
|
} |
|
if (height < 1 || width < 1) { |
|
throw std::invalid_argument("BitMatrix::setRegion(): Height and width must be at least 1"); |
|
} |
|
int right = left + width; |
|
int bottom = top + height; |
|
if (bottom > _height || right > _width) { |
|
throw std::invalid_argument("BitMatrix::setRegion(): The region must fit inside the matrix"); |
|
} |
|
for (int y = top; y < bottom; y++) { |
|
auto offset = y * _width; |
|
for (int x = left; x < right; x++) { |
|
_bits[offset + x] = SET_V; |
|
} |
|
} |
|
} |
|
|
|
void |
|
BitMatrix::rotate90() |
|
{ |
|
BitMatrix result(height(), width()); |
|
for (int x = 0; x < width(); ++x) { |
|
for (int y = 0; y < height(); ++y) { |
|
if (get(x, y)) { |
|
result.set(y, width() - x - 1); |
|
} |
|
} |
|
} |
|
*this = std::move(result); |
|
} |
|
|
|
void |
|
BitMatrix::rotate180() |
|
{ |
|
std::reverse(_bits.begin(), _bits.end()); |
|
} |
|
|
|
void |
|
BitMatrix::mirror() |
|
{ |
|
for (int x = 0; x < _width; x++) { |
|
for (int y = x + 1; y < _height; y++) { |
|
if (get(x, y) != get(y, x)) { |
|
flip(y, x); |
|
flip(x, y); |
|
} |
|
} |
|
} |
|
} |
|
|
|
bool |
|
BitMatrix::findBoundingBox(int &left, int& top, int& width, int& height, int minSize) const |
|
{ |
|
int right, bottom; |
|
if (!getTopLeftOnBit(left, top) || !getBottomRightOnBit(right, bottom) || bottom - top + 1 < minSize) |
|
return false; |
|
|
|
for (int y = top; y <= bottom; y++ ) { |
|
for (int x = 0; x < left; ++x) |
|
if (get(x, y)) { |
|
left = x; |
|
break; |
|
} |
|
for (int x = _width-1; x > right; x--) |
|
if (get(x, y)) { |
|
right = x; |
|
break; |
|
} |
|
} |
|
|
|
width = right - left + 1; |
|
height = bottom - top + 1; |
|
return width >= minSize && height >= minSize; |
|
} |
|
|
|
static auto isSet = [](auto v) { return bool(v); }; |
|
|
|
bool |
|
BitMatrix::getTopLeftOnBit(int& left, int& top) const |
|
{ |
|
int bitsOffset = (int)std::distance(_bits.begin(), std::find_if(_bits.begin(), _bits.end(), isSet)); |
|
if (bitsOffset == Size(_bits)) { |
|
return false; |
|
} |
|
top = bitsOffset / _width; |
|
left = (bitsOffset % _width); |
|
return true; |
|
} |
|
|
|
bool |
|
BitMatrix::getBottomRightOnBit(int& right, int& bottom) const |
|
{ |
|
int bitsOffset = Size(_bits) - 1 - (int)std::distance(_bits.rbegin(), std::find_if(_bits.rbegin(), _bits.rend(), isSet)); |
|
if (bitsOffset < 0) { |
|
return false; |
|
} |
|
|
|
bottom = bitsOffset / _width; |
|
right = (bitsOffset % _width); |
|
return true; |
|
} |
|
|
|
void GetPatternRow(const BitMatrix& matrix, int r, std::vector<uint16_t>& pr, bool transpose) |
|
{ |
|
if (transpose) |
|
GetPatternRow(matrix.col(r), pr); |
|
else |
|
GetPatternRow(matrix.row(r), pr); |
|
} |
|
|
|
BitMatrix Inflate(BitMatrix&& input, int width, int height, int quietZone) |
|
{ |
|
const int codeWidth = input.width(); |
|
const int codeHeight = input.height(); |
|
const int outputWidth = std::max(width, codeWidth + 2 * quietZone); |
|
const int outputHeight = std::max(height, codeHeight + 2 * quietZone); |
|
|
|
if (input.width() == outputWidth && input.height() == outputHeight) |
|
return std::move(input); |
|
|
|
const int scale = std::min((outputWidth - 2*quietZone) / codeWidth, (outputHeight - 2*quietZone) / codeHeight); |
|
// Padding includes both the quiet zone and the extra white pixels to |
|
// accommodate the requested dimensions. |
|
const int leftPadding = (outputWidth - (codeWidth * scale)) / 2; |
|
const int topPadding = (outputHeight - (codeHeight * scale)) / 2; |
|
|
|
BitMatrix result(outputWidth, outputHeight); |
|
|
|
for (int inputY = 0, outputY = topPadding; inputY < input.height(); ++inputY, outputY += scale) { |
|
for (int inputX = 0, outputX = leftPadding; inputX < input.width(); ++inputX, outputX += scale) { |
|
if (input.get(inputX, inputY)) |
|
result.setRegion(outputX, outputY, scale, scale); |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
BitMatrix Deflate(const BitMatrix& input, int width, int height, float top, float left, float subSampling) |
|
{ |
|
BitMatrix result(width, height); |
|
|
|
for (int y = 0; y < result.height(); y++) { |
|
auto yOffset = top + y * subSampling; |
|
for (int x = 0; x < result.width(); x++) { |
|
if (input.get(PointF(left + x * subSampling, yOffset))) |
|
result.set(x, y); |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
} // ZXing
|
|
|