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.

ZXPlanarYUVLuminanceSource.m 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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 "ZXByteArray.h"
  17. #import "ZXPlanarYUVLuminanceSource.h"
  18. const int THUMBNAIL_SCALE_FACTOR = 2;
  19. @interface ZXPlanarYUVLuminanceSource ()
  20. @property (nonatomic, strong, readonly) ZXByteArray *yuvData;
  21. @property (nonatomic, assign, readonly) int dataWidth;
  22. @property (nonatomic, assign, readonly) int dataHeight;
  23. @property (nonatomic, assign, readonly) int left;
  24. @property (nonatomic, assign, readonly) int top;
  25. @end
  26. @implementation ZXPlanarYUVLuminanceSource
  27. - (id)initWithYuvData:(int8_t *)yuvData yuvDataLen:(int)yuvDataLen dataWidth:(int)dataWidth
  28. dataHeight:(int)dataHeight left:(int)left top:(int)top width:(int)width height:(int)height
  29. reverseHorizontal:(BOOL)reverseHorizontal {
  30. if (self = [super initWithWidth:width height:height]) {
  31. if (left + width > dataWidth || top + height > dataHeight) {
  32. [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."];
  33. }
  34. _yuvData = [[ZXByteArray alloc] initWithLength:yuvDataLen];
  35. memcpy(_yuvData.array, yuvData, yuvDataLen * sizeof(int8_t));
  36. _dataWidth = dataWidth;
  37. _dataHeight = dataHeight;
  38. _left = left;
  39. _top = top;
  40. if (reverseHorizontal) {
  41. [self reverseHorizontal:width height:height];
  42. }
  43. }
  44. return self;
  45. }
  46. - (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row {
  47. if (y < 0 || y >= self.height) {
  48. [NSException raise:NSInvalidArgumentException
  49. format:@"Requested row is outside the image: %d", y];
  50. }
  51. int width = self.width;
  52. if (!row || row.length < width) {
  53. row = [[ZXByteArray alloc] initWithLength:width];
  54. }
  55. int offset = (y + self.top) * self.dataWidth + self.left;
  56. memcpy(row.array, self.yuvData.array + offset, self.width * sizeof(int8_t));
  57. return row;
  58. }
  59. - (ZXByteArray *)matrix {
  60. int width = self.width;
  61. int height = self.height;
  62. // If the caller asks for the entire underlying image, save the copy and give them the
  63. // original data. The docs specifically warn that result.length must be ignored.
  64. if (width == self.dataWidth && height == self.dataHeight) {
  65. return self.yuvData;
  66. }
  67. int area = self.width * self.height;
  68. ZXByteArray *matrix = [[ZXByteArray alloc] initWithLength:area];
  69. int inputOffset = self.top * self.dataWidth + self.left;
  70. // If the width matches the full width of the underlying data, perform a single copy.
  71. if (self.width == self.dataWidth) {
  72. memcpy(matrix.array, self.yuvData.array + inputOffset, (area - inputOffset) * sizeof(int8_t));
  73. return matrix;
  74. }
  75. // Otherwise copy one cropped row at a time.
  76. ZXByteArray *yuvData = self.yuvData;
  77. for (int y = 0; y < self.height; y++) {
  78. int outputOffset = y * self.width;
  79. memcpy(matrix.array + outputOffset, yuvData.array + inputOffset, self.width * sizeof(int8_t));
  80. inputOffset += self.dataWidth;
  81. }
  82. return matrix;
  83. }
  84. - (BOOL)cropSupported {
  85. return YES;
  86. }
  87. - (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)width height:(int)height {
  88. return [[[self class] alloc] initWithYuvData:self.yuvData.array yuvDataLen:self.yuvData.length dataWidth:self.dataWidth
  89. dataHeight:self.dataHeight left:self.left + left top:self.top + top
  90. width:width height:height reverseHorizontal:NO];
  91. }
  92. - (int *)renderThumbnail {
  93. int thumbWidth = self.width / THUMBNAIL_SCALE_FACTOR;
  94. int thumbHeight = self.height / THUMBNAIL_SCALE_FACTOR;
  95. int *pixels = (int *)malloc(thumbWidth * thumbHeight * sizeof(int));
  96. int inputOffset = self.top * self.dataWidth + self.left;
  97. for (int y = 0; y < self.height; y++) {
  98. int outputOffset = y * self.width;
  99. for (int x = 0; x < self.width; x++) {
  100. int grey = self.yuvData.array[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff;
  101. pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
  102. }
  103. inputOffset += self.dataWidth * THUMBNAIL_SCALE_FACTOR;
  104. }
  105. return pixels;
  106. }
  107. - (int)thumbnailWidth {
  108. return self.width / THUMBNAIL_SCALE_FACTOR;
  109. }
  110. - (int)thumbnailHeight {
  111. return self.height / THUMBNAIL_SCALE_FACTOR;
  112. }
  113. - (void)reverseHorizontal:(int)width height:(int)height {
  114. for (int y = 0, rowStart = self.top * self.dataWidth + self.left; y < height; y++, rowStart += self.dataWidth) {
  115. int middle = rowStart + width / 2;
  116. for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) {
  117. int8_t temp = self.yuvData.array[x1];
  118. self.yuvData.array[x1] = self.yuvData.array[x2];
  119. self.yuvData.array[x2] = temp;
  120. }
  121. }
  122. }
  123. @end