/*
|
* Copyright 2013 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 "ZXPDF417CodewordDecoder.h"
|
#import "ZXPDF417Common.h"
|
|
static float ZX_PDF417_RATIOS_TABLE[ZX_PDF417_SYMBOL_TABLE_LEN][ZX_PDF417_BARS_IN_MODULE];
|
|
@implementation ZXPDF417CodewordDecoder
|
|
+ (void)initialize {
|
if ([self class] != [ZXPDF417CodewordDecoder class]) return;
|
|
// Pre-computes the symbol ratio table.
|
for (int i = 0; i < ZX_PDF417_SYMBOL_TABLE_LEN; i++) {
|
int currentSymbol = ZX_PDF417_SYMBOL_TABLE[i];
|
int currentBit = currentSymbol & 0x1;
|
for (int j = 0; j < ZX_PDF417_BARS_IN_MODULE; j++) {
|
float size = 0.0f;
|
while ((currentSymbol & 0x1) == currentBit) {
|
size += 1.0f;
|
currentSymbol >>= 1;
|
}
|
currentBit = currentSymbol & 0x1;
|
ZX_PDF417_RATIOS_TABLE[i][ZX_PDF417_BARS_IN_MODULE - j - 1] = size / ZX_PDF417_MODULES_IN_CODEWORD;
|
}
|
}
|
}
|
|
+ (int)decodedValue:(NSArray *)moduleBitCount {
|
int decodedValue = [self decodedCodewordValue:[self sampleBitCounts:moduleBitCount]];
|
if (decodedValue != -1) {
|
return decodedValue;
|
}
|
return [self closestDecodedValue:moduleBitCount];
|
}
|
|
+ (NSArray *)sampleBitCounts:(NSArray *)moduleBitCount {
|
float bitCountSum = [ZXPDF417Common bitCountSum:moduleBitCount];
|
NSMutableArray *result = [NSMutableArray arrayWithCapacity:ZX_PDF417_BARS_IN_MODULE];
|
for (int i = 0; i < ZX_PDF417_BARS_IN_MODULE; i++) {
|
[result addObject:@0];
|
}
|
|
int bitCountIndex = 0;
|
int sumPreviousBits = 0;
|
for (int i = 0; i < ZX_PDF417_MODULES_IN_CODEWORD; i++) {
|
float sampleIndex =
|
bitCountSum / (2 * ZX_PDF417_MODULES_IN_CODEWORD) +
|
(i * bitCountSum) / ZX_PDF417_MODULES_IN_CODEWORD;
|
if (sumPreviousBits + [moduleBitCount[bitCountIndex] intValue] <= sampleIndex) {
|
sumPreviousBits += [moduleBitCount[bitCountIndex] intValue];
|
bitCountIndex++;
|
}
|
result[bitCountIndex] = @([result[bitCountIndex] intValue] + 1);
|
}
|
return result;
|
}
|
|
+ (int)decodedCodewordValue:(NSArray *)moduleBitCount {
|
int decodedValue = [self bitValue:moduleBitCount];
|
return [ZXPDF417Common codeword:decodedValue] == -1 ? -1 : decodedValue;
|
}
|
|
+ (int)bitValue:(NSArray *)moduleBitCount {
|
long result = 0;
|
for (int i = 0; i < [moduleBitCount count]; i++) {
|
for (int bit = 0; bit < [moduleBitCount[i] intValue]; bit++) {
|
result = (result << 1) | (i % 2 == 0 ? 1 : 0);
|
}
|
}
|
return (int) result;
|
}
|
|
+ (int)closestDecodedValue:(NSArray *)moduleBitCount {
|
int bitCountSum = [ZXPDF417Common bitCountSum:moduleBitCount];
|
float bitCountRatios[ZX_PDF417_BARS_IN_MODULE];
|
for (int i = 0; i < ZX_PDF417_BARS_IN_MODULE; i++) {
|
bitCountRatios[i] = [moduleBitCount[i] intValue] / (float) bitCountSum;
|
}
|
float bestMatchError = MAXFLOAT;
|
int bestMatch = -1;
|
for (int j = 0; j < ZX_PDF417_SYMBOL_TABLE_LEN; j++) {
|
float error = 0.0f;
|
float *ratioTableRow = ZX_PDF417_RATIOS_TABLE[j];
|
for (int k = 0; k < ZX_PDF417_BARS_IN_MODULE; k++) {
|
float diff = ratioTableRow[k] - bitCountRatios[k];
|
error += diff * diff;
|
if (error >= bestMatchError) {
|
break;
|
}
|
}
|
if (error < bestMatchError) {
|
bestMatchError = error;
|
bestMatch = ZX_PDF417_SYMBOL_TABLE[j];
|
}
|
}
|
return bestMatch;
|
}
|
|
@end
|