您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ZXBitMatrix.m 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * Copyright 2012 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "ZXBitArray.h"
  17. #import "ZXBitMatrix.h"
  18. #import "ZXBoolArray.h"
  19. #import "ZXIntArray.h"
  20. @interface ZXBitMatrix ()
  21. @property (nonatomic, assign, readonly) int bitsSize;
  22. @end
  23. @implementation ZXBitMatrix
  24. - (id)initWithDimension:(int)dimension {
  25. return [self initWithWidth:dimension height:dimension];
  26. }
  27. - (id)initWithWidth:(int)width height:(int)height {
  28. if (self = [super init]) {
  29. if (width < 1 || height < 1) {
  30. @throw [NSException exceptionWithName:NSInvalidArgumentException
  31. reason:@"Both dimensions must be greater than 0"
  32. userInfo:nil];
  33. }
  34. _width = width;
  35. _height = height;
  36. _rowSize = (_width + 31) / 32;
  37. _bitsSize = _rowSize * _height;
  38. _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t));
  39. [self clear];
  40. }
  41. return self;
  42. }
  43. - (id)initWithWidth:(int)width height:(int)height rowSize:(int)rowSize bits:(int32_t *)bits {
  44. if (self = [super init]) {
  45. _width = width;
  46. _height = height;
  47. _rowSize = rowSize;
  48. _bitsSize = _rowSize * _height;
  49. _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t));
  50. memcpy(_bits, bits, _bitsSize * sizeof(int32_t));
  51. }
  52. return self;
  53. }
  54. - (void)dealloc {
  55. if (_bits != NULL) {
  56. free(_bits);
  57. _bits = NULL;
  58. }
  59. }
  60. + (ZXBitMatrix *)parse:(NSString *)stringRepresentation
  61. setString:(NSString *)setString
  62. unsetString:(NSString *)unsetString {
  63. if (!stringRepresentation) {
  64. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  65. reason:@"stringRepresentation is required"
  66. userInfo:nil];
  67. }
  68. ZXBoolArray *bits = [[ZXBoolArray alloc] initWithLength:(unsigned int)stringRepresentation.length];
  69. int bitsPos = 0;
  70. int rowStartPos = 0;
  71. int rowLength = -1;
  72. int nRows = 0;
  73. int pos = 0;
  74. while (pos < stringRepresentation.length) {
  75. if ([stringRepresentation characterAtIndex:pos] == '\n' ||
  76. [stringRepresentation characterAtIndex:pos] == '\r') {
  77. if (bitsPos > rowStartPos) {
  78. if(rowLength == -1) {
  79. rowLength = bitsPos - rowStartPos;
  80. } else if (bitsPos - rowStartPos != rowLength) {
  81. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  82. reason:@"row lengths do not match"
  83. userInfo:nil];
  84. }
  85. rowStartPos = bitsPos;
  86. nRows++;
  87. }
  88. pos++;
  89. } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, setString.length)] isEqualToString:setString]) {
  90. pos += setString.length;
  91. bits.array[bitsPos] = YES;
  92. bitsPos++;
  93. } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, unsetString.length)] isEqualToString:unsetString]) {
  94. pos += unsetString.length;
  95. bits.array[bitsPos] = NO;
  96. bitsPos++;
  97. } else {
  98. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  99. reason:[NSString stringWithFormat:@"illegal character encountered: %@", [stringRepresentation substringFromIndex:pos]]
  100. userInfo:nil];
  101. }
  102. }
  103. // no EOL at end?
  104. if (bitsPos > rowStartPos) {
  105. if (rowLength == -1) {
  106. rowLength = bitsPos - rowStartPos;
  107. } else if (bitsPos - rowStartPos != rowLength) {
  108. @throw [NSException exceptionWithName:@"IllegalArgumentException"
  109. reason:@"row lengths do not match"
  110. userInfo:nil];
  111. }
  112. nRows++;
  113. }
  114. ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithWidth:rowLength height:nRows];
  115. for (int i = 0; i < bitsPos; i++) {
  116. if (bits.array[i]) {
  117. [matrix setX:i % rowLength y:i / rowLength];
  118. }
  119. }
  120. return matrix;
  121. }
  122. - (BOOL)getX:(int)x y:(int)y {
  123. NSInteger offset = y * self.rowSize + (x / 32);
  124. return ((_bits[offset] >> (x & 0x1f)) & 1) != 0;
  125. }
  126. - (void)setX:(int)x y:(int)y {
  127. NSInteger offset = y * self.rowSize + (x / 32);
  128. _bits[offset] |= 1 << (x & 0x1f);
  129. }
  130. - (void)unsetX:(int)x y:(int)y {
  131. int offset = y * self.rowSize + (x / 32);
  132. _bits[offset] &= ~(1 << (x & 0x1f));
  133. }
  134. - (void)flipX:(int)x y:(int)y {
  135. NSUInteger offset = y * self.rowSize + (x / 32);
  136. _bits[offset] ^= 1 << (x & 0x1f);
  137. }
  138. - (void)xor:(ZXBitMatrix *)mask {
  139. if (self.width != mask.width || self.height != mask.height
  140. || self.rowSize != mask.rowSize) {
  141. @throw [NSException exceptionWithName:NSInvalidArgumentException
  142. reason:@"input matrix dimensions do not match"
  143. userInfo:nil];
  144. }
  145. ZXBitArray *rowArray = [[ZXBitArray alloc] initWithSize:self.width];
  146. for (int y = 0; y < self.height; y++) {
  147. int offset = y * self.rowSize;
  148. int32_t *row = [mask rowAtY:y row:rowArray].bits;
  149. for (int x = 0; x < self.rowSize; x++) {
  150. self.bits[offset + x] ^= row[x];
  151. }
  152. }
  153. }
  154. - (void)clear {
  155. NSInteger max = self.bitsSize;
  156. memset(_bits, 0, max * sizeof(int32_t));
  157. }
  158. - (void)setRegionAtLeft:(int)left top:(int)top width:(int)aWidth height:(int)aHeight {
  159. if (aHeight < 1 || aWidth < 1) {
  160. @throw [NSException exceptionWithName:NSInvalidArgumentException
  161. reason:@"Height and width must be at least 1"
  162. userInfo:nil];
  163. }
  164. NSUInteger right = left + aWidth;
  165. NSUInteger bottom = top + aHeight;
  166. if (bottom > self.height || right > self.width) {
  167. @throw [NSException exceptionWithName:NSInvalidArgumentException
  168. reason:@"The region must fit inside the matrix"
  169. userInfo:nil];
  170. }
  171. for (NSUInteger y = top; y < bottom; y++) {
  172. NSUInteger offset = y * self.rowSize;
  173. for (NSInteger x = left; x < right; x++) {
  174. _bits[offset + (x / 32)] |= 1 << (x & 0x1f);
  175. }
  176. }
  177. }
  178. - (ZXBitArray *)rowAtY:(int)y row:(ZXBitArray *)row {
  179. if (row == nil || [row size] < self.width) {
  180. row = [[ZXBitArray alloc] initWithSize:self.width];
  181. } else {
  182. [row clear];
  183. }
  184. int offset = y * self.rowSize;
  185. for (int x = 0; x < self.rowSize; x++) {
  186. [row setBulk:x * 32 newBits:_bits[offset + x]];
  187. }
  188. return row;
  189. }
  190. - (void)setRowAtY:(int)y row:(ZXBitArray *)row {
  191. for (NSUInteger i = 0; i < self.rowSize; i++) {
  192. _bits[(y * self.rowSize) + i] = row.bits[i];
  193. }
  194. }
  195. - (void)rotate180 {
  196. int width = self.width;
  197. int height = self.height;
  198. ZXBitArray *topRow = [[ZXBitArray alloc] initWithSize:width];
  199. ZXBitArray *bottomRow = [[ZXBitArray alloc] initWithSize:width];
  200. for (int i = 0; i < (height+1) / 2; i++) {
  201. topRow = [self rowAtY:i row:topRow];
  202. bottomRow = [self rowAtY:height - 1 - i row:bottomRow];
  203. [topRow reverse];
  204. [bottomRow reverse];
  205. [self setRowAtY:i row:bottomRow];
  206. [self setRowAtY:height - 1 - i row:topRow];
  207. }
  208. }
  209. - (ZXIntArray *)enclosingRectangle {
  210. int left = self.width;
  211. int top = self.height;
  212. int right = -1;
  213. int bottom = -1;
  214. for (int y = 0; y < self.height; y++) {
  215. for (int x32 = 0; x32 < self.rowSize; x32++) {
  216. int32_t theBits = _bits[y * self.rowSize + x32];
  217. if (theBits != 0) {
  218. if (y < top) {
  219. top = y;
  220. }
  221. if (y > bottom) {
  222. bottom = y;
  223. }
  224. if (x32 * 32 < left) {
  225. int32_t bit = 0;
  226. while ((theBits << (31 - bit)) == 0) {
  227. bit++;
  228. }
  229. if ((x32 * 32 + bit) < left) {
  230. left = x32 * 32 + bit;
  231. }
  232. }
  233. if (x32 * 32 + 31 > right) {
  234. int bit = 31;
  235. while ((theBits >> bit) == 0) {
  236. bit--;
  237. }
  238. if ((x32 * 32 + bit) > right) {
  239. right = x32 * 32 + bit;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. NSInteger width = right - left;
  246. NSInteger height = bottom - top;
  247. if (width < 0 || height < 0) {
  248. return nil;
  249. }
  250. return [[ZXIntArray alloc] initWithInts:left, top, width, height, -1];
  251. }
  252. - (ZXIntArray *)topLeftOnBit {
  253. int bitsOffset = 0;
  254. while (bitsOffset < self.bitsSize && _bits[bitsOffset] == 0) {
  255. bitsOffset++;
  256. }
  257. if (bitsOffset == self.bitsSize) {
  258. return nil;
  259. }
  260. int y = bitsOffset / self.rowSize;
  261. int x = (bitsOffset % self.rowSize) * 32;
  262. int32_t theBits = _bits[bitsOffset];
  263. int32_t bit = 0;
  264. while ((theBits << (31 - bit)) == 0) {
  265. bit++;
  266. }
  267. x += bit;
  268. return [[ZXIntArray alloc] initWithInts:x, y, -1];
  269. }
  270. - (ZXIntArray *)bottomRightOnBit {
  271. int bitsOffset = self.bitsSize - 1;
  272. while (bitsOffset >= 0 && _bits[bitsOffset] == 0) {
  273. bitsOffset--;
  274. }
  275. if (bitsOffset < 0) {
  276. return nil;
  277. }
  278. int y = bitsOffset / self.rowSize;
  279. int x = (bitsOffset % self.rowSize) * 32;
  280. int32_t theBits = _bits[bitsOffset];
  281. int32_t bit = 31;
  282. while ((theBits >> bit) == 0) {
  283. bit--;
  284. }
  285. x += bit;
  286. return [[ZXIntArray alloc] initWithInts:x, y, -1];
  287. }
  288. - (BOOL)isEqual:(NSObject *)o {
  289. if (!([o isKindOfClass:[ZXBitMatrix class]])) {
  290. return NO;
  291. }
  292. ZXBitMatrix *other = (ZXBitMatrix *)o;
  293. for (int i = 0; i < self.bitsSize; i++) {
  294. if (_bits[i] != other.bits[i]) {
  295. return NO;
  296. }
  297. }
  298. return self.width == other.width && self.height == other.height && self.rowSize == other.rowSize && self.bitsSize == other.bitsSize;
  299. }
  300. - (NSUInteger)hash {
  301. NSInteger hash = self.width;
  302. hash = 31 * hash + self.width;
  303. hash = 31 * hash + self.height;
  304. hash = 31 * hash + self.rowSize;
  305. for (NSUInteger i = 0; i < self.bitsSize; i++) {
  306. hash = 31 * hash + _bits[i];
  307. }
  308. return hash;
  309. }
  310. - (NSString *)description {
  311. return [self descriptionWithSetString:@"X " unsetString:@" "];
  312. }
  313. - (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString {
  314. #pragma GCC diagnostic push
  315. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  316. return [self descriptionWithSetString:setString unsetString:unsetString lineSeparator:@"\n"];
  317. #pragma GCC diagnostic pop
  318. }
  319. - (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString
  320. lineSeparator:(NSString *)lineSeparator {
  321. NSMutableString *result = [NSMutableString stringWithCapacity:self.height * (self.width + 1)];
  322. for (int y = 0; y < self.height; y++) {
  323. for (int x = 0; x < self.width; x++) {
  324. [result appendString:[self getX:x y:y] ? setString : unsetString];
  325. }
  326. [result appendString:lineSeparator];
  327. }
  328. return result;
  329. }
  330. - (id)copyWithZone:(NSZone *)zone {
  331. return [[ZXBitMatrix allocWithZone:zone] initWithWidth:self.width height:self.height rowSize:self.rowSize bits:self.bits];
  332. }
  333. @end