/*
|
* 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 "ZXByteArray.h"
|
#import "ZXDecoderResult.h"
|
#import "ZXDetectorResult.h"
|
#import "ZXMultiDetector.h"
|
#import "ZXQRCodeDecoder.h"
|
#import "ZXQRCodeDecoderMetaData.h"
|
#import "ZXQRCodeMultiReader.h"
|
#import "ZXResult.h"
|
|
@implementation ZXQRCodeMultiReader
|
|
- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error {
|
return [self decodeMultiple:image hints:nil error:error];
|
}
|
|
- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error {
|
ZXBitMatrix *matrix = [image blackMatrixWithError:error];
|
if (!matrix) {
|
return nil;
|
}
|
NSMutableArray *results = [NSMutableArray array];
|
NSArray *detectorResults = [[[ZXMultiDetector alloc] initWithImage:matrix] detectMulti:hints error:error];
|
if (!detectorResults) {
|
return nil;
|
}
|
for (ZXDetectorResult *detectorResult in detectorResults) {
|
ZXDecoderResult *decoderResult = [[self decoder] decodeMatrix:[detectorResult bits] hints:hints error:nil];
|
if (decoderResult) {
|
NSMutableArray *points = [[detectorResult points] mutableCopy];
|
// If the code was mirrored: swap the bottom-left and the top-right points.
|
if ([decoderResult.other isKindOfClass:[ZXQRCodeDecoderMetaData class]]) {
|
[(ZXQRCodeDecoderMetaData *)decoderResult.other applyMirroredCorrection:points];
|
}
|
ZXResult *result = [ZXResult resultWithText:decoderResult.text
|
rawBytes:decoderResult.rawBytes
|
resultPoints:points
|
format:kBarcodeFormatQRCode];
|
NSMutableArray *byteSegments = decoderResult.byteSegments;
|
if (byteSegments != nil) {
|
[result putMetadata:kResultMetadataTypeByteSegments value:byteSegments];
|
}
|
NSString *ecLevel = decoderResult.ecLevel;
|
if (ecLevel != nil) {
|
[result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:ecLevel];
|
}
|
if ([decoderResult hasStructuredAppend]) {
|
[result putMetadata:kResultMetadataTypeStructuredAppendSequence
|
value:@(decoderResult.structuredAppendSequenceNumber)];
|
[result putMetadata:kResultMetadataTypeStructuredAppendParity
|
value:@(decoderResult.structuredAppendParity)];
|
}
|
[results addObject:result];
|
}
|
}
|
|
results = [self processStructuredAppend:results];
|
return results;
|
}
|
|
- (NSMutableArray *)processStructuredAppend:(NSMutableArray *)results {
|
BOOL hasSA = NO;
|
|
// first, check, if there is at least on SA result in the list
|
for (ZXResult *result in results) {
|
if (result.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)]) {
|
hasSA = YES;
|
break;
|
}
|
}
|
if (!hasSA) {
|
return results;
|
}
|
|
// it is, second, split the lists and built a new result list
|
NSMutableArray *newResults = [NSMutableArray array];
|
NSMutableArray *saResults = [NSMutableArray array];
|
for (ZXResult *result in results) {
|
[newResults addObject:result];
|
if (result.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)]) {
|
[saResults addObject:result];
|
}
|
}
|
// sort and concatenate the SA list items
|
[saResults sortUsingComparator:^NSComparisonResult(ZXResult *a, ZXResult *b) {
|
int aNumber = [a.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)] intValue];
|
int bNumber = [b.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)] intValue];
|
if (aNumber < bNumber) {
|
return NSOrderedAscending;
|
}
|
if (aNumber > bNumber) {
|
return NSOrderedDescending;
|
}
|
return NSOrderedSame;
|
}];
|
NSMutableString *concatedText = [NSMutableString string];
|
int rawBytesLen = 0;
|
int byteSegmentLength = 0;
|
for (ZXResult *saResult in saResults) {
|
[concatedText appendString:saResult.text];
|
rawBytesLen += saResult.rawBytes.length;
|
if (saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) {
|
for (ZXByteArray *segment in saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) {
|
byteSegmentLength += segment.length;
|
}
|
}
|
}
|
ZXByteArray *newRawBytes = [[ZXByteArray alloc] initWithLength:rawBytesLen];
|
ZXByteArray *newByteSegment = [[ZXByteArray alloc] initWithLength:byteSegmentLength];
|
int newRawBytesIndex = 0;
|
int byteSegmentIndex = 0;
|
for (ZXResult *saResult in saResults) {
|
memcpy(newRawBytes.array, saResult.rawBytes.array, saResult.rawBytes.length * sizeof(int8_t));
|
newRawBytesIndex += saResult.rawBytes.length;
|
if (saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) {
|
for (ZXByteArray *segment in saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) {
|
memcpy(newByteSegment.array, segment.array, segment.length * sizeof(int8_t));
|
byteSegmentIndex += segment.length;
|
}
|
}
|
}
|
ZXResult *newResult = [[ZXResult alloc] initWithText:concatedText rawBytes:newRawBytes resultPoints:@[] format:kBarcodeFormatQRCode];
|
if (byteSegmentLength > 0) {
|
NSMutableArray *byteSegmentList = [NSMutableArray array];
|
[byteSegmentList addObject:newByteSegment];
|
[newResult putMetadata:kResultMetadataTypeByteSegments value:byteSegmentList];
|
}
|
[newResults addObject:newResult];
|
return newResults;
|
}
|
|
@end
|