123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /*
- * Copyright 2012 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.
- */
-
- #import "ZXBitArray.h"
- #import "ZXBitMatrix.h"
- #import "ZXBoolArray.h"
- #import "ZXIntArray.h"
-
- @interface ZXBitMatrix ()
-
- @property (nonatomic, assign, readonly) int bitsSize;
-
- @end
-
- @implementation ZXBitMatrix
-
- - (id)initWithDimension:(int)dimension {
- return [self initWithWidth:dimension height:dimension];
- }
-
- - (id)initWithWidth:(int)width height:(int)height {
- if (self = [super init]) {
- if (width < 1 || height < 1) {
- @throw [NSException exceptionWithName:NSInvalidArgumentException
- reason:@"Both dimensions must be greater than 0"
- userInfo:nil];
- }
- _width = width;
- _height = height;
- _rowSize = (_width + 31) / 32;
- _bitsSize = _rowSize * _height;
- _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t));
- [self clear];
- }
-
- return self;
- }
-
- - (id)initWithWidth:(int)width height:(int)height rowSize:(int)rowSize bits:(int32_t *)bits {
- if (self = [super init]) {
- _width = width;
- _height = height;
- _rowSize = rowSize;
- _bitsSize = _rowSize * _height;
- _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t));
- memcpy(_bits, bits, _bitsSize * sizeof(int32_t));
- }
-
- return self;
- }
-
- - (void)dealloc {
- if (_bits != NULL) {
- free(_bits);
- _bits = NULL;
- }
- }
-
- + (ZXBitMatrix *)parse:(NSString *)stringRepresentation
- setString:(NSString *)setString
- unsetString:(NSString *)unsetString {
- if (!stringRepresentation) {
- @throw [NSException exceptionWithName:@"IllegalArgumentException"
- reason:@"stringRepresentation is required"
- userInfo:nil];
- }
-
- ZXBoolArray *bits = [[ZXBoolArray alloc] initWithLength:(unsigned int)stringRepresentation.length];
- int bitsPos = 0;
- int rowStartPos = 0;
- int rowLength = -1;
- int nRows = 0;
- int pos = 0;
- while (pos < stringRepresentation.length) {
- if ([stringRepresentation characterAtIndex:pos] == '\n' ||
- [stringRepresentation characterAtIndex:pos] == '\r') {
- if (bitsPos > rowStartPos) {
- if(rowLength == -1) {
- rowLength = bitsPos - rowStartPos;
- } else if (bitsPos - rowStartPos != rowLength) {
- @throw [NSException exceptionWithName:@"IllegalArgumentException"
- reason:@"row lengths do not match"
- userInfo:nil];
- }
- rowStartPos = bitsPos;
- nRows++;
- }
- pos++;
- } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, setString.length)] isEqualToString:setString]) {
- pos += setString.length;
- bits.array[bitsPos] = YES;
- bitsPos++;
- } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, unsetString.length)] isEqualToString:unsetString]) {
- pos += unsetString.length;
- bits.array[bitsPos] = NO;
- bitsPos++;
- } else {
- @throw [NSException exceptionWithName:@"IllegalArgumentException"
- reason:[NSString stringWithFormat:@"illegal character encountered: %@", [stringRepresentation substringFromIndex:pos]]
- userInfo:nil];
- }
- }
-
- // no EOL at end?
- if (bitsPos > rowStartPos) {
- if (rowLength == -1) {
- rowLength = bitsPos - rowStartPos;
- } else if (bitsPos - rowStartPos != rowLength) {
- @throw [NSException exceptionWithName:@"IllegalArgumentException"
- reason:@"row lengths do not match"
- userInfo:nil];
- }
- nRows++;
- }
-
- ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithWidth:rowLength height:nRows];
- for (int i = 0; i < bitsPos; i++) {
- if (bits.array[i]) {
- [matrix setX:i % rowLength y:i / rowLength];
- }
- }
- return matrix;
- }
-
- - (BOOL)getX:(int)x y:(int)y {
- NSInteger offset = y * self.rowSize + (x / 32);
- return ((_bits[offset] >> (x & 0x1f)) & 1) != 0;
- }
-
- - (void)setX:(int)x y:(int)y {
- NSInteger offset = y * self.rowSize + (x / 32);
- _bits[offset] |= 1 << (x & 0x1f);
- }
-
- - (void)unsetX:(int)x y:(int)y {
- int offset = y * self.rowSize + (x / 32);
- _bits[offset] &= ~(1 << (x & 0x1f));
- }
-
- - (void)flipX:(int)x y:(int)y {
- NSUInteger offset = y * self.rowSize + (x / 32);
- _bits[offset] ^= 1 << (x & 0x1f);
- }
-
- - (void)xor:(ZXBitMatrix *)mask {
- if (self.width != mask.width || self.height != mask.height
- || self.rowSize != mask.rowSize) {
- @throw [NSException exceptionWithName:NSInvalidArgumentException
- reason:@"input matrix dimensions do not match"
- userInfo:nil];
- }
- ZXBitArray *rowArray = [[ZXBitArray alloc] initWithSize:self.width];
- for (int y = 0; y < self.height; y++) {
- int offset = y * self.rowSize;
- int32_t *row = [mask rowAtY:y row:rowArray].bits;
- for (int x = 0; x < self.rowSize; x++) {
- self.bits[offset + x] ^= row[x];
- }
- }
- }
-
- - (void)clear {
- NSInteger max = self.bitsSize;
- memset(_bits, 0, max * sizeof(int32_t));
- }
-
- - (void)setRegionAtLeft:(int)left top:(int)top width:(int)aWidth height:(int)aHeight {
- if (aHeight < 1 || aWidth < 1) {
- @throw [NSException exceptionWithName:NSInvalidArgumentException
- reason:@"Height and width must be at least 1"
- userInfo:nil];
- }
- NSUInteger right = left + aWidth;
- NSUInteger bottom = top + aHeight;
- if (bottom > self.height || right > self.width) {
- @throw [NSException exceptionWithName:NSInvalidArgumentException
- reason:@"The region must fit inside the matrix"
- userInfo:nil];
- }
- for (NSUInteger y = top; y < bottom; y++) {
- NSUInteger offset = y * self.rowSize;
- for (NSInteger x = left; x < right; x++) {
- _bits[offset + (x / 32)] |= 1 << (x & 0x1f);
- }
- }
- }
-
- - (ZXBitArray *)rowAtY:(int)y row:(ZXBitArray *)row {
- if (row == nil || [row size] < self.width) {
- row = [[ZXBitArray alloc] initWithSize:self.width];
- } else {
- [row clear];
- }
- int offset = y * self.rowSize;
- for (int x = 0; x < self.rowSize; x++) {
- [row setBulk:x * 32 newBits:_bits[offset + x]];
- }
-
- return row;
- }
-
- - (void)setRowAtY:(int)y row:(ZXBitArray *)row {
- for (NSUInteger i = 0; i < self.rowSize; i++) {
- _bits[(y * self.rowSize) + i] = row.bits[i];
- }
- }
-
- - (void)rotate180 {
- int width = self.width;
- int height = self.height;
- ZXBitArray *topRow = [[ZXBitArray alloc] initWithSize:width];
- ZXBitArray *bottomRow = [[ZXBitArray alloc] initWithSize:width];
- for (int i = 0; i < (height+1) / 2; i++) {
- topRow = [self rowAtY:i row:topRow];
- bottomRow = [self rowAtY:height - 1 - i row:bottomRow];
- [topRow reverse];
- [bottomRow reverse];
- [self setRowAtY:i row:bottomRow];
- [self setRowAtY:height - 1 - i row:topRow];
- }
- }
-
- - (ZXIntArray *)enclosingRectangle {
- int left = self.width;
- int top = self.height;
- int right = -1;
- int bottom = -1;
-
- for (int y = 0; y < self.height; y++) {
- for (int x32 = 0; x32 < self.rowSize; x32++) {
- int32_t theBits = _bits[y * self.rowSize + x32];
- if (theBits != 0) {
- if (y < top) {
- top = y;
- }
- if (y > bottom) {
- bottom = y;
- }
- if (x32 * 32 < left) {
- int32_t bit = 0;
- while ((theBits << (31 - bit)) == 0) {
- bit++;
- }
- if ((x32 * 32 + bit) < left) {
- left = x32 * 32 + bit;
- }
- }
- if (x32 * 32 + 31 > right) {
- int bit = 31;
- while ((theBits >> bit) == 0) {
- bit--;
- }
- if ((x32 * 32 + bit) > right) {
- right = x32 * 32 + bit;
- }
- }
- }
- }
- }
-
- NSInteger width = right - left;
- NSInteger height = bottom - top;
-
- if (width < 0 || height < 0) {
- return nil;
- }
-
- return [[ZXIntArray alloc] initWithInts:left, top, width, height, -1];
- }
-
- - (ZXIntArray *)topLeftOnBit {
- int bitsOffset = 0;
- while (bitsOffset < self.bitsSize && _bits[bitsOffset] == 0) {
- bitsOffset++;
- }
- if (bitsOffset == self.bitsSize) {
- return nil;
- }
- int y = bitsOffset / self.rowSize;
- int x = (bitsOffset % self.rowSize) * 32;
-
- int32_t theBits = _bits[bitsOffset];
- int32_t bit = 0;
- while ((theBits << (31 - bit)) == 0) {
- bit++;
- }
- x += bit;
- return [[ZXIntArray alloc] initWithInts:x, y, -1];
- }
-
- - (ZXIntArray *)bottomRightOnBit {
- int bitsOffset = self.bitsSize - 1;
- while (bitsOffset >= 0 && _bits[bitsOffset] == 0) {
- bitsOffset--;
- }
- if (bitsOffset < 0) {
- return nil;
- }
-
- int y = bitsOffset / self.rowSize;
- int x = (bitsOffset % self.rowSize) * 32;
-
- int32_t theBits = _bits[bitsOffset];
- int32_t bit = 31;
- while ((theBits >> bit) == 0) {
- bit--;
- }
- x += bit;
-
- return [[ZXIntArray alloc] initWithInts:x, y, -1];
- }
-
- - (BOOL)isEqual:(NSObject *)o {
- if (!([o isKindOfClass:[ZXBitMatrix class]])) {
- return NO;
- }
- ZXBitMatrix *other = (ZXBitMatrix *)o;
- for (int i = 0; i < self.bitsSize; i++) {
- if (_bits[i] != other.bits[i]) {
- return NO;
- }
- }
- return self.width == other.width && self.height == other.height && self.rowSize == other.rowSize && self.bitsSize == other.bitsSize;
- }
-
- - (NSUInteger)hash {
- NSInteger hash = self.width;
- hash = 31 * hash + self.width;
- hash = 31 * hash + self.height;
- hash = 31 * hash + self.rowSize;
- for (NSUInteger i = 0; i < self.bitsSize; i++) {
- hash = 31 * hash + _bits[i];
- }
- return hash;
- }
-
- - (NSString *)description {
- return [self descriptionWithSetString:@"X " unsetString:@" "];
- }
-
- - (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString {
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- return [self descriptionWithSetString:setString unsetString:unsetString lineSeparator:@"\n"];
- #pragma GCC diagnostic pop
- }
-
- - (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString
- lineSeparator:(NSString *)lineSeparator {
- NSMutableString *result = [NSMutableString stringWithCapacity:self.height * (self.width + 1)];
- for (int y = 0; y < self.height; y++) {
- for (int x = 0; x < self.width; x++) {
- [result appendString:[self getX:x y:y] ? setString : unsetString];
- }
- [result appendString:lineSeparator];
- }
- return result;
- }
-
- - (id)copyWithZone:(NSZone *)zone {
- return [[ZXBitMatrix allocWithZone:zone] initWithWidth:self.width height:self.height rowSize:self.rowSize bits:self.bits];
- }
-
- @end
|