mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
rss_14 ported but does not pass integration
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use super::rss::RSS14Reader;
|
||||||
use super::CodaBarReader;
|
use super::CodaBarReader;
|
||||||
use super::Code128Reader;
|
use super::Code128Reader;
|
||||||
use super::Code39Reader;
|
use super::Code39Reader;
|
||||||
@@ -86,9 +87,9 @@ impl MultiFormatOneDReader {
|
|||||||
if possibleFormats.contains(&BarcodeFormat::CODABAR) {
|
if possibleFormats.contains(&BarcodeFormat::CODABAR) {
|
||||||
readers.push(Box::new(CodaBarReader::new()));
|
readers.push(Box::new(CodaBarReader::new()));
|
||||||
}
|
}
|
||||||
// if (possibleFormats.contains(&BarcodeFormat::RSS_14)) {
|
if possibleFormats.contains(&BarcodeFormat::RSS_14) {
|
||||||
// readers.add(new RSS14Reader());
|
readers.push(Box::new(RSS14Reader::new()));
|
||||||
// }
|
}
|
||||||
// if (possibleFormats.contains(&BarcodeFormat::RSS_EXPANDED)) {
|
// if (possibleFormats.contains(&BarcodeFormat::RSS_EXPANDED)) {
|
||||||
// readers.add(new RSSExpandedReader());
|
// readers.add(new RSSExpandedReader());
|
||||||
// }
|
// }
|
||||||
@@ -100,7 +101,7 @@ impl MultiFormatOneDReader {
|
|||||||
readers.push(Box::new(Code93Reader::new()));
|
readers.push(Box::new(Code93Reader::new()));
|
||||||
readers.push(Box::new(Code128Reader {}));
|
readers.push(Box::new(Code128Reader {}));
|
||||||
readers.push(Box::new(ITFReader::default()));
|
readers.push(Box::new(ITFReader::default()));
|
||||||
// readers.push(new RSS14Reader());
|
readers.push(Box::new(RSS14Reader::new()));
|
||||||
// readers.push(new RSSExpandedReader());
|
// readers.push(new RSSExpandedReader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.common.detector.MathUtils;
|
|
||||||
import com.google.zxing.oned.OneDReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Superclass of {@link OneDReader} implementations that read barcodes in the RSS family
|
|
||||||
* of formats.
|
|
||||||
*/
|
|
||||||
public abstract class AbstractRSSReader extends OneDReader {
|
|
||||||
|
|
||||||
private static final float MAX_AVG_VARIANCE = 0.2f;
|
|
||||||
private static final float MAX_INDIVIDUAL_VARIANCE = 0.45f;
|
|
||||||
|
|
||||||
private static final float MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f;
|
|
||||||
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;
|
|
||||||
|
|
||||||
private final int[] decodeFinderCounters;
|
|
||||||
private final int[] dataCharacterCounters;
|
|
||||||
private final float[] oddRoundingErrors;
|
|
||||||
private final float[] evenRoundingErrors;
|
|
||||||
private final int[] oddCounts;
|
|
||||||
private final int[] evenCounts;
|
|
||||||
|
|
||||||
protected AbstractRSSReader() {
|
|
||||||
decodeFinderCounters = new int[4];
|
|
||||||
dataCharacterCounters = new int[8];
|
|
||||||
oddRoundingErrors = new float[4];
|
|
||||||
evenRoundingErrors = new float[4];
|
|
||||||
oddCounts = new int[dataCharacterCounters.length / 2];
|
|
||||||
evenCounts = new int[dataCharacterCounters.length / 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int[] getDecodeFinderCounters() {
|
|
||||||
return decodeFinderCounters;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int[] getDataCharacterCounters() {
|
|
||||||
return dataCharacterCounters;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final float[] getOddRoundingErrors() {
|
|
||||||
return oddRoundingErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final float[] getEvenRoundingErrors() {
|
|
||||||
return evenRoundingErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int[] getOddCounts() {
|
|
||||||
return oddCounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int[] getEvenCounts() {
|
|
||||||
return evenCounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int parseFinderValue(int[] counters,
|
|
||||||
int[][] finderPatterns) throws NotFoundException {
|
|
||||||
for (int value = 0; value < finderPatterns.length; value++) {
|
|
||||||
if (patternMatchVariance(counters, finderPatterns[value], MAX_INDIVIDUAL_VARIANCE) <
|
|
||||||
MAX_AVG_VARIANCE) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array values to sum
|
|
||||||
* @return sum of values
|
|
||||||
* @deprecated call {@link MathUtils#sum(int[])}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected static int count(int[] array) {
|
|
||||||
return MathUtils.sum(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void increment(int[] array, float[] errors) {
|
|
||||||
int index = 0;
|
|
||||||
float biggestError = errors[0];
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
if (errors[i] > biggestError) {
|
|
||||||
biggestError = errors[i];
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
array[index]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void decrement(int[] array, float[] errors) {
|
|
||||||
int index = 0;
|
|
||||||
float biggestError = errors[0];
|
|
||||||
for (int i = 1; i < array.length; i++) {
|
|
||||||
if (errors[i] < biggestError) {
|
|
||||||
biggestError = errors[i];
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
array[index]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean isFinderPattern(int[] counters) {
|
|
||||||
int firstTwoSum = counters[0] + counters[1];
|
|
||||||
int sum = firstTwoSum + counters[2] + counters[3];
|
|
||||||
float ratio = firstTwoSum / (float) sum;
|
|
||||||
if (ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO) {
|
|
||||||
// passes ratio test in spec, but see if the counts are unreasonable
|
|
||||||
int minCounter = Integer.MAX_VALUE;
|
|
||||||
int maxCounter = Integer.MIN_VALUE;
|
|
||||||
for (int counter : counters) {
|
|
||||||
if (counter > maxCounter) {
|
|
||||||
maxCounter = counter;
|
|
||||||
}
|
|
||||||
if (counter < minCounter) {
|
|
||||||
minCounter = counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return maxCounter < 10 * minCounter;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates a since character value in an RSS barcode, including its checksum information.
|
|
||||||
*/
|
|
||||||
public class DataCharacter {
|
|
||||||
|
|
||||||
private final int value;
|
|
||||||
private final int checksumPortion;
|
|
||||||
|
|
||||||
public DataCharacter(int value, int checksumPortion) {
|
|
||||||
this.value = value;
|
|
||||||
this.checksumPortion = checksumPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getChecksumPortion() {
|
|
||||||
return checksumPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return value + "(" + checksumPortion + ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(Object o) {
|
|
||||||
if (!(o instanceof DataCharacter)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DataCharacter that = (DataCharacter) o;
|
|
||||||
return value == that.value && checksumPortion == that.checksumPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
return value ^ checksumPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates an RSS barcode finder pattern, including its start/end position and row.
|
|
||||||
*/
|
|
||||||
public final class FinderPattern {
|
|
||||||
|
|
||||||
private final int value;
|
|
||||||
private final int[] startEnd;
|
|
||||||
private final RXingResultPoint[] resultPoints;
|
|
||||||
|
|
||||||
public FinderPattern(int value, int[] startEnd, int start, int end, int rowNumber) {
|
|
||||||
this.value = value;
|
|
||||||
this.startEnd = startEnd;
|
|
||||||
this.resultPoints = new RXingResultPoint[] {
|
|
||||||
new RXingResultPoint(start, rowNumber),
|
|
||||||
new RXingResultPoint(end, rowNumber),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getStartEnd() {
|
|
||||||
return startEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RXingResultPoint[] getRXingResultPoints() {
|
|
||||||
return resultPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof FinderPattern)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
FinderPattern that = (FinderPattern) o;
|
|
||||||
return value == that.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
final class Pair extends DataCharacter {
|
|
||||||
|
|
||||||
private final FinderPattern finderPattern;
|
|
||||||
private int count;
|
|
||||||
|
|
||||||
Pair(int value, int checksumPortion, FinderPattern finderPattern) {
|
|
||||||
super(value, checksumPortion);
|
|
||||||
this.finderPattern = finderPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
FinderPattern getFinderPattern() {
|
|
||||||
return finderPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void incrementCount() {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,471 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.DecodeHintType;
|
|
||||||
import com.google.zxing.NotFoundException;
|
|
||||||
import com.google.zxing.RXingResult;
|
|
||||||
import com.google.zxing.RXingResultMetadataType;
|
|
||||||
import com.google.zxing.RXingResultPoint;
|
|
||||||
import com.google.zxing.RXingResultPointCallback;
|
|
||||||
import com.google.zxing.common.BitArray;
|
|
||||||
import com.google.zxing.common.detector.MathUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006.
|
|
||||||
*/
|
|
||||||
public final class RSS14Reader extends AbstractRSSReader {
|
|
||||||
|
|
||||||
private static final int[] OUTSIDE_EVEN_TOTAL_SUBSET = {1,10,34,70,126};
|
|
||||||
private static final int[] INSIDE_ODD_TOTAL_SUBSET = {4,20,48,81};
|
|
||||||
private static final int[] OUTSIDE_GSUM = {0,161,961,2015,2715};
|
|
||||||
private static final int[] INSIDE_GSUM = {0,336,1036,1516};
|
|
||||||
private static final int[] OUTSIDE_ODD_WIDEST = {8,6,4,3,1};
|
|
||||||
private static final int[] INSIDE_ODD_WIDEST = {2,4,6,8};
|
|
||||||
|
|
||||||
private static final int[][] FINDER_PATTERNS = {
|
|
||||||
{3,8,2,1},
|
|
||||||
{3,5,5,1},
|
|
||||||
{3,3,7,1},
|
|
||||||
{3,1,9,1},
|
|
||||||
{2,7,4,1},
|
|
||||||
{2,5,6,1},
|
|
||||||
{2,3,8,1},
|
|
||||||
{1,5,7,1},
|
|
||||||
{1,3,9,1},
|
|
||||||
};
|
|
||||||
|
|
||||||
private final List<Pair> possibleLeftPairs;
|
|
||||||
private final List<Pair> possibleRightPairs;
|
|
||||||
|
|
||||||
public RSS14Reader() {
|
|
||||||
possibleLeftPairs = new ArrayList<>();
|
|
||||||
possibleRightPairs = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RXingResult decodeRow(int rowNumber,
|
|
||||||
BitArray row,
|
|
||||||
Map<DecodeHintType,?> hints) throws NotFoundException {
|
|
||||||
Pair leftPair = decodePair(row, false, rowNumber, hints);
|
|
||||||
addOrTally(possibleLeftPairs, leftPair);
|
|
||||||
row.reverse();
|
|
||||||
Pair rightPair = decodePair(row, true, rowNumber, hints);
|
|
||||||
addOrTally(possibleRightPairs, rightPair);
|
|
||||||
row.reverse();
|
|
||||||
for (Pair left : possibleLeftPairs) {
|
|
||||||
if (left.getCount() > 1) {
|
|
||||||
for (Pair right : possibleRightPairs) {
|
|
||||||
if (right.getCount() > 1 && checkChecksum(left, right)) {
|
|
||||||
return constructRXingResult(left, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addOrTally(Collection<Pair> possiblePairs, Pair pair) {
|
|
||||||
if (pair == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boolean found = false;
|
|
||||||
for (Pair other : possiblePairs) {
|
|
||||||
if (other.getValue() == pair.getValue()) {
|
|
||||||
other.incrementCount();
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
possiblePairs.add(pair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
possibleLeftPairs.clear();
|
|
||||||
possibleRightPairs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RXingResult constructRXingResult(Pair leftPair, Pair rightPair) {
|
|
||||||
long symbolValue = 4537077L * leftPair.getValue() + rightPair.getValue();
|
|
||||||
String text = String.valueOf(symbolValue);
|
|
||||||
|
|
||||||
StringBuilder buffer = new StringBuilder(14);
|
|
||||||
for (int i = 13 - text.length(); i > 0; i--) {
|
|
||||||
buffer.append('0');
|
|
||||||
}
|
|
||||||
buffer.append(text);
|
|
||||||
|
|
||||||
int checkDigit = 0;
|
|
||||||
for (int i = 0; i < 13; i++) {
|
|
||||||
int digit = buffer.charAt(i) - '0';
|
|
||||||
checkDigit += (i & 0x01) == 0 ? 3 * digit : digit;
|
|
||||||
}
|
|
||||||
checkDigit = 10 - (checkDigit % 10);
|
|
||||||
if (checkDigit == 10) {
|
|
||||||
checkDigit = 0;
|
|
||||||
}
|
|
||||||
buffer.append(checkDigit);
|
|
||||||
|
|
||||||
RXingResultPoint[] leftPoints = leftPair.getFinderPattern().getRXingResultPoints();
|
|
||||||
RXingResultPoint[] rightPoints = rightPair.getFinderPattern().getRXingResultPoints();
|
|
||||||
RXingResult result = new RXingResult(
|
|
||||||
buffer.toString(),
|
|
||||||
null,
|
|
||||||
new RXingResultPoint[] { leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1], },
|
|
||||||
BarcodeFormat.RSS_14);
|
|
||||||
result.putMetadata(RXingResultMetadataType.SYMBOLOGY_IDENTIFIER, "]e0");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkChecksum(Pair leftPair, Pair rightPair) {
|
|
||||||
int checkValue = (leftPair.getChecksumPortion() + 16 * rightPair.getChecksumPortion()) % 79;
|
|
||||||
int targetCheckValue =
|
|
||||||
9 * leftPair.getFinderPattern().getValue() + rightPair.getFinderPattern().getValue();
|
|
||||||
if (targetCheckValue > 72) {
|
|
||||||
targetCheckValue--;
|
|
||||||
}
|
|
||||||
if (targetCheckValue > 8) {
|
|
||||||
targetCheckValue--;
|
|
||||||
}
|
|
||||||
return checkValue == targetCheckValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pair decodePair(BitArray row, boolean right, int rowNumber, Map<DecodeHintType,?> hints) {
|
|
||||||
try {
|
|
||||||
int[] startEnd = findFinderPattern(row, right);
|
|
||||||
FinderPattern pattern = parseFoundFinderPattern(row, rowNumber, right, startEnd);
|
|
||||||
|
|
||||||
RXingResultPointCallback resultPointCallback = hints == null ? null :
|
|
||||||
(RXingResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
|
||||||
|
|
||||||
if (resultPointCallback != null) {
|
|
||||||
startEnd = pattern.getStartEnd();
|
|
||||||
float center = (startEnd[0] + startEnd[1] - 1) / 2.0f;
|
|
||||||
if (right) {
|
|
||||||
// row is actually reversed
|
|
||||||
center = row.getSize() - 1 - center;
|
|
||||||
}
|
|
||||||
resultPointCallback.foundPossibleRXingResultPoint(new RXingResultPoint(center, rowNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataCharacter outside = decodeDataCharacter(row, pattern, true);
|
|
||||||
DataCharacter inside = decodeDataCharacter(row, pattern, false);
|
|
||||||
return new Pair(1597 * outside.getValue() + inside.getValue(),
|
|
||||||
outside.getChecksumPortion() + 4 * inside.getChecksumPortion(),
|
|
||||||
pattern);
|
|
||||||
} catch (NotFoundException ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataCharacter decodeDataCharacter(BitArray row, FinderPattern pattern, boolean outsideChar)
|
|
||||||
throws NotFoundException {
|
|
||||||
|
|
||||||
int[] counters = getDataCharacterCounters();
|
|
||||||
Arrays.fill(counters, 0);
|
|
||||||
|
|
||||||
if (outsideChar) {
|
|
||||||
recordPatternInReverse(row, pattern.getStartEnd()[0], counters);
|
|
||||||
} else {
|
|
||||||
recordPattern(row, pattern.getStartEnd()[1], counters);
|
|
||||||
// reverse it
|
|
||||||
for (int i = 0, j = counters.length - 1; i < j; i++, j--) {
|
|
||||||
int temp = counters[i];
|
|
||||||
counters[i] = counters[j];
|
|
||||||
counters[j] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int numModules = outsideChar ? 16 : 15;
|
|
||||||
float elementWidth = MathUtils.sum(counters) / (float) numModules;
|
|
||||||
|
|
||||||
int[] oddCounts = this.getOddCounts();
|
|
||||||
int[] evenCounts = this.getEvenCounts();
|
|
||||||
float[] oddRoundingErrors = this.getOddRoundingErrors();
|
|
||||||
float[] evenRoundingErrors = this.getEvenRoundingErrors();
|
|
||||||
|
|
||||||
for (int i = 0; i < counters.length; i++) {
|
|
||||||
float value = counters[i] / elementWidth;
|
|
||||||
int count = (int) (value + 0.5f); // Round
|
|
||||||
if (count < 1) {
|
|
||||||
count = 1;
|
|
||||||
} else if (count > 8) {
|
|
||||||
count = 8;
|
|
||||||
}
|
|
||||||
int offset = i / 2;
|
|
||||||
if ((i & 0x01) == 0) {
|
|
||||||
oddCounts[offset] = count;
|
|
||||||
oddRoundingErrors[offset] = value - count;
|
|
||||||
} else {
|
|
||||||
evenCounts[offset] = count;
|
|
||||||
evenRoundingErrors[offset] = value - count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustOddEvenCounts(outsideChar, numModules);
|
|
||||||
|
|
||||||
int oddSum = 0;
|
|
||||||
int oddChecksumPortion = 0;
|
|
||||||
for (int i = oddCounts.length - 1; i >= 0; i--) {
|
|
||||||
oddChecksumPortion *= 9;
|
|
||||||
oddChecksumPortion += oddCounts[i];
|
|
||||||
oddSum += oddCounts[i];
|
|
||||||
}
|
|
||||||
int evenChecksumPortion = 0;
|
|
||||||
int evenSum = 0;
|
|
||||||
for (int i = evenCounts.length - 1; i >= 0; i--) {
|
|
||||||
evenChecksumPortion *= 9;
|
|
||||||
evenChecksumPortion += evenCounts[i];
|
|
||||||
evenSum += evenCounts[i];
|
|
||||||
}
|
|
||||||
int checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion;
|
|
||||||
|
|
||||||
if (outsideChar) {
|
|
||||||
if ((oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
int group = (12 - oddSum) / 2;
|
|
||||||
int oddWidest = OUTSIDE_ODD_WIDEST[group];
|
|
||||||
int evenWidest = 9 - oddWidest;
|
|
||||||
int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, false);
|
|
||||||
int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, true);
|
|
||||||
int tEven = OUTSIDE_EVEN_TOTAL_SUBSET[group];
|
|
||||||
int gSum = OUTSIDE_GSUM[group];
|
|
||||||
return new DataCharacter(vOdd * tEven + vEven + gSum, checksumPortion);
|
|
||||||
} else {
|
|
||||||
if ((evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
int group = (10 - evenSum) / 2;
|
|
||||||
int oddWidest = INSIDE_ODD_WIDEST[group];
|
|
||||||
int evenWidest = 9 - oddWidest;
|
|
||||||
int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true);
|
|
||||||
int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false);
|
|
||||||
int tOdd = INSIDE_ODD_TOTAL_SUBSET[group];
|
|
||||||
int gSum = INSIDE_GSUM[group];
|
|
||||||
return new DataCharacter(vEven * tOdd + vOdd + gSum, checksumPortion);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] findFinderPattern(BitArray row, boolean rightFinderPattern)
|
|
||||||
throws NotFoundException {
|
|
||||||
|
|
||||||
int[] counters = getDecodeFinderCounters();
|
|
||||||
counters[0] = 0;
|
|
||||||
counters[1] = 0;
|
|
||||||
counters[2] = 0;
|
|
||||||
counters[3] = 0;
|
|
||||||
|
|
||||||
int width = row.getSize();
|
|
||||||
boolean isWhite = false;
|
|
||||||
int rowOffset = 0;
|
|
||||||
while (rowOffset < width) {
|
|
||||||
isWhite = !row.get(rowOffset);
|
|
||||||
if (rightFinderPattern == isWhite) {
|
|
||||||
// Will encounter white first when searching for right finder pattern
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rowOffset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int counterPosition = 0;
|
|
||||||
int patternStart = rowOffset;
|
|
||||||
for (int x = rowOffset; x < width; x++) {
|
|
||||||
if (row.get(x) != isWhite) {
|
|
||||||
counters[counterPosition]++;
|
|
||||||
} else {
|
|
||||||
if (counterPosition == 3) {
|
|
||||||
if (isFinderPattern(counters)) {
|
|
||||||
return new int[]{patternStart, x};
|
|
||||||
}
|
|
||||||
patternStart += counters[0] + counters[1];
|
|
||||||
counters[0] = counters[2];
|
|
||||||
counters[1] = counters[3];
|
|
||||||
counters[2] = 0;
|
|
||||||
counters[3] = 0;
|
|
||||||
counterPosition--;
|
|
||||||
} else {
|
|
||||||
counterPosition++;
|
|
||||||
}
|
|
||||||
counters[counterPosition] = 1;
|
|
||||||
isWhite = !isWhite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, boolean right, int[] startEnd)
|
|
||||||
throws NotFoundException {
|
|
||||||
// Actually we found elements 2-5
|
|
||||||
boolean firstIsBlack = row.get(startEnd[0]);
|
|
||||||
int firstElementStart = startEnd[0] - 1;
|
|
||||||
// Locate element 1
|
|
||||||
while (firstElementStart >= 0 && firstIsBlack != row.get(firstElementStart)) {
|
|
||||||
firstElementStart--;
|
|
||||||
}
|
|
||||||
firstElementStart++;
|
|
||||||
int firstCounter = startEnd[0] - firstElementStart;
|
|
||||||
// Make 'counters' hold 1-4
|
|
||||||
int[] counters = getDecodeFinderCounters();
|
|
||||||
System.arraycopy(counters, 0, counters, 1, counters.length - 1);
|
|
||||||
counters[0] = firstCounter;
|
|
||||||
int value = parseFinderValue(counters, FINDER_PATTERNS);
|
|
||||||
int start = firstElementStart;
|
|
||||||
int end = startEnd[1];
|
|
||||||
if (right) {
|
|
||||||
// row is actually reversed
|
|
||||||
start = row.getSize() - 1 - start;
|
|
||||||
end = row.getSize() - 1 - end;
|
|
||||||
}
|
|
||||||
return new FinderPattern(value, new int[] {firstElementStart, startEnd[1]}, start, end, rowNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void adjustOddEvenCounts(boolean outsideChar, int numModules) throws NotFoundException {
|
|
||||||
|
|
||||||
int oddSum = MathUtils.sum(getOddCounts());
|
|
||||||
int evenSum = MathUtils.sum(getEvenCounts());
|
|
||||||
|
|
||||||
boolean incrementOdd = false;
|
|
||||||
boolean decrementOdd = false;
|
|
||||||
boolean incrementEven = false;
|
|
||||||
boolean decrementEven = false;
|
|
||||||
|
|
||||||
if (outsideChar) {
|
|
||||||
if (oddSum > 12) {
|
|
||||||
decrementOdd = true;
|
|
||||||
} else if (oddSum < 4) {
|
|
||||||
incrementOdd = true;
|
|
||||||
}
|
|
||||||
if (evenSum > 12) {
|
|
||||||
decrementEven = true;
|
|
||||||
} else if (evenSum < 4) {
|
|
||||||
incrementEven = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (oddSum > 11) {
|
|
||||||
decrementOdd = true;
|
|
||||||
} else if (oddSum < 5) {
|
|
||||||
incrementOdd = true;
|
|
||||||
}
|
|
||||||
if (evenSum > 10) {
|
|
||||||
decrementEven = true;
|
|
||||||
} else if (evenSum < 4) {
|
|
||||||
incrementEven = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int mismatch = oddSum + evenSum - numModules;
|
|
||||||
boolean oddParityBad = (oddSum & 0x01) == (outsideChar ? 1 : 0);
|
|
||||||
boolean evenParityBad = (evenSum & 0x01) == 1;
|
|
||||||
/*if (mismatch == 2) {
|
|
||||||
if (!(oddParityBad && evenParityBad)) {
|
|
||||||
throw ReaderException.getInstance();
|
|
||||||
}
|
|
||||||
decrementOdd = true;
|
|
||||||
decrementEven = true;
|
|
||||||
} else if (mismatch == -2) {
|
|
||||||
if (!(oddParityBad && evenParityBad)) {
|
|
||||||
throw ReaderException.getInstance();
|
|
||||||
}
|
|
||||||
incrementOdd = true;
|
|
||||||
incrementEven = true;
|
|
||||||
} else */
|
|
||||||
switch (mismatch) {
|
|
||||||
case 1:
|
|
||||||
if (oddParityBad) {
|
|
||||||
if (evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
decrementOdd = true;
|
|
||||||
} else {
|
|
||||||
if (!evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
decrementEven = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
if (oddParityBad) {
|
|
||||||
if (evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
incrementOdd = true;
|
|
||||||
} else {
|
|
||||||
if (!evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
incrementEven = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
if (oddParityBad) {
|
|
||||||
if (!evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
// Both bad
|
|
||||||
if (oddSum < evenSum) {
|
|
||||||
incrementOdd = true;
|
|
||||||
decrementEven = true;
|
|
||||||
} else {
|
|
||||||
decrementOdd = true;
|
|
||||||
incrementEven = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (evenParityBad) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
// Nothing to do!
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (incrementOdd) {
|
|
||||||
if (decrementOdd) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
increment(getOddCounts(), getOddRoundingErrors());
|
|
||||||
}
|
|
||||||
if (decrementOdd) {
|
|
||||||
decrement(getOddCounts(), getOddRoundingErrors());
|
|
||||||
}
|
|
||||||
if (incrementEven) {
|
|
||||||
if (decrementEven) {
|
|
||||||
throw NotFoundException.getNotFoundInstance();
|
|
||||||
}
|
|
||||||
increment(getEvenCounts(), getOddRoundingErrors());
|
|
||||||
}
|
|
||||||
if (decrementEven) {
|
|
||||||
decrement(getEvenCounts(), getEvenRoundingErrors());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
/** Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. */
|
|
||||||
public final class RSSUtils {
|
|
||||||
|
|
||||||
private RSSUtils() {}
|
|
||||||
|
|
||||||
public static int getRSSvalue(int[] widths, int maxWidth, boolean noNarrow) {
|
|
||||||
int n = 0;
|
|
||||||
for (int width : widths) {
|
|
||||||
n += width;
|
|
||||||
}
|
|
||||||
int val = 0;
|
|
||||||
int narrowMask = 0;
|
|
||||||
int elements = widths.length;
|
|
||||||
for (int bar = 0; bar < elements - 1; bar++) {
|
|
||||||
int elmWidth;
|
|
||||||
for (elmWidth = 1, narrowMask |= 1 << bar;
|
|
||||||
elmWidth < widths[bar];
|
|
||||||
elmWidth++, narrowMask &= ~(1 << bar)) {
|
|
||||||
int subVal = combins(n - elmWidth - 1, elements - bar - 2);
|
|
||||||
if (noNarrow && (narrowMask == 0) &&
|
|
||||||
(n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) {
|
|
||||||
subVal -= combins(n - elmWidth - (elements - bar),
|
|
||||||
elements - bar - 2);
|
|
||||||
}
|
|
||||||
if (elements - bar - 1 > 1) {
|
|
||||||
int lessVal = 0;
|
|
||||||
for (int mxwElement = n - elmWidth - (elements - bar - 2);
|
|
||||||
mxwElement > maxWidth; mxwElement--) {
|
|
||||||
lessVal += combins(n - elmWidth - mxwElement - 1,
|
|
||||||
elements - bar - 3);
|
|
||||||
}
|
|
||||||
subVal -= lessVal * (elements - 1 - bar);
|
|
||||||
} else if (n - elmWidth > maxWidth) {
|
|
||||||
subVal--;
|
|
||||||
}
|
|
||||||
val += subVal;
|
|
||||||
}
|
|
||||||
n -= elmWidth;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int combins(int n, int r) {
|
|
||||||
int maxDenom;
|
|
||||||
int minDenom;
|
|
||||||
if (n - r > r) {
|
|
||||||
minDenom = r;
|
|
||||||
maxDenom = n - r;
|
|
||||||
} else {
|
|
||||||
minDenom = n - r;
|
|
||||||
maxDenom = r;
|
|
||||||
}
|
|
||||||
int val = 1;
|
|
||||||
int j = 1;
|
|
||||||
for (int i = n; i > maxDenom; i--) {
|
|
||||||
val *= i;
|
|
||||||
if (j <= minDenom) {
|
|
||||||
val /= j;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (j <= minDenom) {
|
|
||||||
val /= j;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
134
src/oned/rss/abstract_rss_reader.rs
Normal file
134
src/oned/rss/abstract_rss_reader.rs
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::{oned::OneDReader, Exceptions};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of {@link OneDReader} implementations that read barcodes in the RSS family
|
||||||
|
* of formats.
|
||||||
|
*/
|
||||||
|
pub trait AbstractRSSReaderTrait: OneDReader {
|
||||||
|
const MAX_AVG_VARIANCE: f32 = 0.2;
|
||||||
|
const MAX_INDIVIDUAL_VARIANCE: f32 = 0.45;
|
||||||
|
|
||||||
|
const MIN_FINDER_PATTERN_RATIO: f32 = 9.5 / 12.0;
|
||||||
|
const MAX_FINDER_PATTERN_RATIO: f32 = 12.5 / 14.0;
|
||||||
|
|
||||||
|
// private final int[] decodeFinderCounters;
|
||||||
|
// private final int[] dataCharacterCounters;
|
||||||
|
// private final float[] oddRoundingErrors;
|
||||||
|
// private final float[] evenRoundingErrors;
|
||||||
|
// private final int[] oddCounts;
|
||||||
|
// private final int[] evenCounts;
|
||||||
|
|
||||||
|
// protected AbstractRSSReader() {
|
||||||
|
// decodeFinderCounters = new int[4];
|
||||||
|
// dataCharacterCounters = new int[8];
|
||||||
|
// oddRoundingErrors = new float[4];
|
||||||
|
// evenRoundingErrors = new float[4];
|
||||||
|
// oddCounts = new int[dataCharacterCounters.length / 2];
|
||||||
|
// evenCounts = new int[dataCharacterCounters.length / 2];
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn getDecodeFinderCounters(&mut self) -> &mut [u32];
|
||||||
|
|
||||||
|
fn getDataCharacterCounters(&mut self) -> &mut [u32];
|
||||||
|
|
||||||
|
fn getOddRoundingErrors(&mut self) -> &mut [f32];
|
||||||
|
|
||||||
|
fn getEvenRoundingErrors(&mut self) -> &mut [f32];
|
||||||
|
|
||||||
|
fn getOddCounts(&mut self) -> &mut [u32];
|
||||||
|
|
||||||
|
fn getEvenCounts(&mut self) -> &mut [u32];
|
||||||
|
|
||||||
|
fn parseFinderValue(
|
||||||
|
&self,
|
||||||
|
counters: &[u32],
|
||||||
|
finderPatterns: &[[u32; 4]; 9],
|
||||||
|
) -> Result<u32, Exceptions> {
|
||||||
|
for value in 0..finderPatterns.len() {
|
||||||
|
// for (int value = 0; value < finderPatterns.length; value++) {
|
||||||
|
if self.patternMatchVariance(
|
||||||
|
counters,
|
||||||
|
&finderPatterns[value],
|
||||||
|
Self::MAX_INDIVIDUAL_VARIANCE,
|
||||||
|
) < Self::MAX_AVG_VARIANCE
|
||||||
|
{
|
||||||
|
return Ok(value as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Exceptions::NotFoundException("".to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array values to sum
|
||||||
|
* @return sum of values
|
||||||
|
* @deprecated call {@link MathUtils#sum(int[])}
|
||||||
|
*/
|
||||||
|
#[deprecated]
|
||||||
|
fn count(array: &[u32]) -> u32 {
|
||||||
|
array.iter().sum::<u32>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(array: &mut [u32], errors: &[f32]) {
|
||||||
|
let mut index = 0;
|
||||||
|
let mut biggestError = errors[0];
|
||||||
|
for i in 1..array.len() {
|
||||||
|
// for (int i = 1; i < array.length; i++) {
|
||||||
|
if errors[i] > biggestError {
|
||||||
|
biggestError = errors[i];
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array[index] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrement(array: &mut [u32], errors: &[f32]) {
|
||||||
|
let mut index = 0;
|
||||||
|
let mut biggestError = errors[0];
|
||||||
|
for i in 1..array.len() {
|
||||||
|
// for (int i = 1; i < array.length; i++) {
|
||||||
|
if errors[i] < biggestError {
|
||||||
|
biggestError = errors[i];
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array[index] -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isFinderPattern(&self, counters: &[u32]) -> bool {
|
||||||
|
let firstTwoSum = counters[0] + counters[1];
|
||||||
|
let sum = firstTwoSum + counters[2] + counters[3];
|
||||||
|
let ratio: f32 = (firstTwoSum as f32) / (sum as f32);
|
||||||
|
if ratio >= Self::MIN_FINDER_PATTERN_RATIO && ratio <= Self::MAX_FINDER_PATTERN_RATIO {
|
||||||
|
// passes ratio test in spec, but see if the counts are unreasonable
|
||||||
|
let mut minCounter = u32::MAX;
|
||||||
|
let mut maxCounter = u32::MIN;
|
||||||
|
for counter in counters {
|
||||||
|
// for (int counter : counters) {
|
||||||
|
if *counter > maxCounter {
|
||||||
|
maxCounter = *counter;
|
||||||
|
}
|
||||||
|
if *counter < minCounter {
|
||||||
|
minCounter = *counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxCounter < 10 * minCounter;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/oned/rss/data_character.rs
Normal file
54
src/oned/rss/data_character.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::{fmt::Display, hash::Hash};
|
||||||
|
|
||||||
|
pub(crate) trait DataCharacterTrait: Display + Eq + PartialEq + Hash {
|
||||||
|
fn getValue(&self) -> u32;
|
||||||
|
|
||||||
|
fn getChecksumPortion(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a since character value in an RSS barcode, including its checksum information.
|
||||||
|
*/
|
||||||
|
#[derive(Hash, PartialEq, Eq)]
|
||||||
|
pub struct DataCharacter {
|
||||||
|
value: u32,
|
||||||
|
checksumPortion: u32,
|
||||||
|
}
|
||||||
|
impl DataCharacterTrait for DataCharacter {
|
||||||
|
fn getValue(&self) -> u32 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getChecksumPortion(&self) -> u32 {
|
||||||
|
self.checksumPortion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DataCharacter {
|
||||||
|
pub fn new(value: u32, checksumPortion: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
checksumPortion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Display for DataCharacter {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}({})", self.value, self.checksumPortion)
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/oned/rss/finder_pattern.rs
Normal file
65
src/oned/rss/finder_pattern.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use crate::RXingResultPoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates an RSS barcode finder pattern, including its start/end position and row.
|
||||||
|
*/
|
||||||
|
pub struct FinderPattern {
|
||||||
|
value: u32,
|
||||||
|
startEnd: [usize; 2],
|
||||||
|
resultPoints: Vec<RXingResultPoint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FinderPattern {
|
||||||
|
pub fn new(value: u32, startEnd: [usize; 2], start: usize, end: usize, rowNumber: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
startEnd,
|
||||||
|
resultPoints: vec![
|
||||||
|
RXingResultPoint::new(start as f32, rowNumber as f32),
|
||||||
|
RXingResultPoint::new(end as f32, rowNumber as f32),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getValue(&self) -> u32 {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getStartEnd(&self) -> &[usize] {
|
||||||
|
&self.startEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getRXingResultPoints(&self) -> &[RXingResultPoint] {
|
||||||
|
&self.resultPoints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for FinderPattern {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.value == other.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for FinderPattern {}
|
||||||
|
impl Hash for FinderPattern {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.value.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,18 @@
|
|||||||
pub mod expanded;
|
pub mod expanded;
|
||||||
|
|
||||||
|
mod finder_pattern;
|
||||||
|
pub use finder_pattern::*;
|
||||||
|
|
||||||
|
mod pair;
|
||||||
|
pub use pair::*;
|
||||||
|
|
||||||
|
mod data_character;
|
||||||
|
pub use data_character::*;
|
||||||
|
|
||||||
|
pub mod rss_utils;
|
||||||
|
|
||||||
|
mod abstract_rss_reader;
|
||||||
|
pub use abstract_rss_reader::*;
|
||||||
|
|
||||||
|
mod rss_14_reader;
|
||||||
|
pub use rss_14_reader::*;
|
||||||
|
|||||||
63
src/oned/rss/pair.rs
Normal file
63
src/oned/rss/pair.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use super::{DataCharacter, DataCharacterTrait, FinderPattern};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2009 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.
|
||||||
|
*/
|
||||||
|
#[derive(Hash, Eq, PartialEq)]
|
||||||
|
pub struct Pair {
|
||||||
|
finderPattern: FinderPattern,
|
||||||
|
count: u32,
|
||||||
|
internal_data_character: DataCharacter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataCharacterTrait for Pair {
|
||||||
|
fn getValue(&self) -> u32 {
|
||||||
|
self.internal_data_character.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getChecksumPortion(&self) -> u32 {
|
||||||
|
self.internal_data_character.getChecksumPortion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pair {
|
||||||
|
pub fn new(value: u32, checksumPortion: u32, finderPattern: FinderPattern) -> Self {
|
||||||
|
Self {
|
||||||
|
finderPattern,
|
||||||
|
count: 0,
|
||||||
|
internal_data_character: DataCharacter::new(value, checksumPortion),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFinderPattern(&self) -> &FinderPattern {
|
||||||
|
&self.finderPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getCount(&self) -> u32 {
|
||||||
|
self.count
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn incrementCount(&mut self) {
|
||||||
|
self.count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Pair {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.internal_data_character.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
641
src/oned/rss/rss_14_reader.rs
Normal file
641
src/oned/rss/rss_14_reader.rs
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{detector::MathUtils, BitArray},
|
||||||
|
oned::OneDReader,
|
||||||
|
BarcodeFormat, DecodeHintType, DecodingHintDictionary, Exceptions, RXingResult,
|
||||||
|
RXingResultMetadataType, RXingResultMetadataValue, RXingResultPoint, Reader, ResultPoint,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
rss_utils, AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern, Pair,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006.
|
||||||
|
*/
|
||||||
|
pub struct RSS14Reader {
|
||||||
|
possibleLeftPairs: Vec<Pair>,
|
||||||
|
possibleRightPairs: Vec<Pair>,
|
||||||
|
decodeFinderCounters: [u32; 4],
|
||||||
|
dataCharacterCounters: [u32; 8],
|
||||||
|
oddRoundingErrors: [f32; 4],
|
||||||
|
evenRoundingErrors: [f32; 4],
|
||||||
|
oddCounts: [u32; 4],
|
||||||
|
evenCounts: [u32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractRSSReaderTrait for RSS14Reader {
|
||||||
|
fn getDecodeFinderCounters(&mut self) -> &mut [u32] {
|
||||||
|
&mut self.decodeFinderCounters
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getDataCharacterCounters(&mut self) -> &mut [u32] {
|
||||||
|
&mut self.dataCharacterCounters
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getOddRoundingErrors(&mut self) -> &mut [f32] {
|
||||||
|
&mut self.oddRoundingErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getEvenRoundingErrors(&mut self) -> &mut [f32] {
|
||||||
|
&mut self.evenRoundingErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getOddCounts(&mut self) -> &mut [u32] {
|
||||||
|
&mut self.oddCounts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getEvenCounts(&mut self) -> &mut [u32] {
|
||||||
|
&mut self.evenCounts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl OneDReader for RSS14Reader {
|
||||||
|
fn decodeRow(
|
||||||
|
&mut self,
|
||||||
|
rowNumber: u32,
|
||||||
|
row: &crate::common::BitArray,
|
||||||
|
hints: &crate::DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult, crate::Exceptions> {
|
||||||
|
let mut row = row.clone();
|
||||||
|
let leftPair = self.decodePair(&row, false, rowNumber, hints);
|
||||||
|
Self::addOrTally(&mut self.possibleLeftPairs, leftPair);
|
||||||
|
row.reverse();
|
||||||
|
let rightPair = self.decodePair(&row, true, rowNumber, hints);
|
||||||
|
Self::addOrTally(&mut self.possibleRightPairs, rightPair);
|
||||||
|
row.reverse();
|
||||||
|
for left in &self.possibleLeftPairs {
|
||||||
|
// for (Pair left : possibleLeftPairs) {
|
||||||
|
if left.getCount() > 1 {
|
||||||
|
for right in &self.possibleRightPairs {
|
||||||
|
// for (Pair right : possibleRightPairs) {
|
||||||
|
if right.getCount() > 1 && self.checkChecksum(&left, &right) {
|
||||||
|
return Ok(self.constructRXingResult(&left, &right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Reader for RSS14Reader {
|
||||||
|
fn decode(&mut self, image: &crate::BinaryBitmap) -> Result<crate::RXingResult, Exceptions> {
|
||||||
|
self.decode_with_hints(image, &HashMap::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we don't try rotation without the try harder flag, even if rotation was supported.
|
||||||
|
fn decode_with_hints(
|
||||||
|
&mut self,
|
||||||
|
image: &crate::BinaryBitmap,
|
||||||
|
hints: &DecodingHintDictionary,
|
||||||
|
) -> Result<crate::RXingResult, Exceptions> {
|
||||||
|
if let Ok(res) = self.doDecode(image, hints) {
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER);
|
||||||
|
if tryHarder && image.isRotateSupported() {
|
||||||
|
let rotatedImage = image.rotateCounterClockwise();
|
||||||
|
let mut result = self.doDecode(&rotatedImage, hints)?;
|
||||||
|
// Record that we found it rotated 90 degrees CCW / 270 degrees CW
|
||||||
|
let metadata = result.getRXingResultMetadata();
|
||||||
|
let mut orientation = 270;
|
||||||
|
if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
|
||||||
|
// But if we found it reversed in doDecode(), add in that result here:
|
||||||
|
orientation = (orientation
|
||||||
|
+ if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
|
||||||
|
metadata.get(&RXingResultMetadataType::ORIENTATION)
|
||||||
|
{
|
||||||
|
*or
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
% 360;
|
||||||
|
}
|
||||||
|
result.putMetadata(
|
||||||
|
RXingResultMetadataType::ORIENTATION,
|
||||||
|
RXingResultMetadataValue::Orientation(orientation),
|
||||||
|
);
|
||||||
|
// Update result points
|
||||||
|
// let points = result.getRXingResultPoints();
|
||||||
|
// if points != null {
|
||||||
|
let height = rotatedImage.getHeight();
|
||||||
|
// for point in result.getRXingResultPointsMut().iter_mut() {
|
||||||
|
let total_points = result.getRXingResultPoints().len();
|
||||||
|
let points = result.getRXingResultPointsMut();
|
||||||
|
for i in 0..total_points {
|
||||||
|
// for (int i = 0; i < points.length; i++) {
|
||||||
|
points[i] = RXingResultPoint::new(
|
||||||
|
height as f32 - points[i].getY() - 1.0,
|
||||||
|
points[i].getX(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.possibleLeftPairs.clear();
|
||||||
|
self.possibleRightPairs.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RSS14Reader {
|
||||||
|
const OUTSIDE_EVEN_TOTAL_SUBSET: [u32; 5] = [1, 10, 34, 70, 126];
|
||||||
|
const INSIDE_ODD_TOTAL_SUBSET: [u32; 4] = [4, 20, 48, 81];
|
||||||
|
const OUTSIDE_GSUM: [u32; 5] = [0, 161, 961, 2015, 2715];
|
||||||
|
const INSIDE_GSUM: [u32; 4] = [0, 336, 1036, 1516];
|
||||||
|
const OUTSIDE_ODD_WIDEST: [u32; 5] = [8, 6, 4, 3, 1];
|
||||||
|
const INSIDE_ODD_WIDEST: [u32; 4] = [2, 4, 6, 8];
|
||||||
|
|
||||||
|
const FINDER_PATTERNS: [[u32; 4]; 9] = [
|
||||||
|
[3, 8, 2, 1],
|
||||||
|
[3, 5, 5, 1],
|
||||||
|
[3, 3, 7, 1],
|
||||||
|
[3, 1, 9, 1],
|
||||||
|
[2, 7, 4, 1],
|
||||||
|
[2, 5, 6, 1],
|
||||||
|
[2, 3, 8, 1],
|
||||||
|
[1, 5, 7, 1],
|
||||||
|
[1, 3, 9, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
possibleLeftPairs: Vec::new(),
|
||||||
|
possibleRightPairs: Vec::new(),
|
||||||
|
decodeFinderCounters: [0u32; 4],
|
||||||
|
dataCharacterCounters: [0u32; 8],
|
||||||
|
oddRoundingErrors: [0.0; 4],
|
||||||
|
evenRoundingErrors: [0.0; 4],
|
||||||
|
oddCounts: [0u32; 4], //vec![0u32;4],
|
||||||
|
evenCounts: [0u32; 4], //vec![0u32;4],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addOrTally(possiblePairs: &mut Vec<Pair>, pair: Option<Pair>) {
|
||||||
|
let Some(pair) = pair else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
for other in possiblePairs.iter_mut() {
|
||||||
|
// for (Pair other : possiblePairs) {
|
||||||
|
if other.getValue() == pair.getValue() {
|
||||||
|
other.incrementCount();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
possiblePairs.push(pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructRXingResult(&self, leftPair: &Pair, rightPair: &Pair) -> RXingResult {
|
||||||
|
let symbolValue: u64 = 4537077 * leftPair.getValue() as u64 + rightPair.getValue() as u64;
|
||||||
|
let text = symbolValue.to_string();
|
||||||
|
|
||||||
|
let mut buffer = String::with_capacity(14);
|
||||||
|
let mut i = 13 - text.chars().count() as isize;
|
||||||
|
while i > 0 {
|
||||||
|
// for (int i = 13 - text.length(); i > 0; i--) {
|
||||||
|
buffer.push('0');
|
||||||
|
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
buffer.push_str(&text);
|
||||||
|
|
||||||
|
let mut checkDigit = 0;
|
||||||
|
for i in 0..13 {
|
||||||
|
// for (int i = 0; i < 13; i++) {
|
||||||
|
let digit = buffer.chars().nth(i).unwrap() as u32 - '0' as u32;
|
||||||
|
checkDigit += if (i & 0x01) == 0 { 3 * digit } else { digit };
|
||||||
|
}
|
||||||
|
checkDigit = 10 - (checkDigit % 10);
|
||||||
|
if checkDigit == 10 {
|
||||||
|
checkDigit = 0;
|
||||||
|
}
|
||||||
|
buffer.push_str(&checkDigit.to_string());
|
||||||
|
|
||||||
|
let leftPoints = leftPair.getFinderPattern().getRXingResultPoints();
|
||||||
|
let rightPoints = rightPair.getFinderPattern().getRXingResultPoints();
|
||||||
|
let mut result = RXingResult::new(
|
||||||
|
&buffer,
|
||||||
|
Vec::new(),
|
||||||
|
vec![leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1]],
|
||||||
|
BarcodeFormat::RSS_14,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.putMetadata(
|
||||||
|
RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
|
||||||
|
RXingResultMetadataValue::SymbologyIdentifier("]e0".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checkChecksum(&self, leftPair: &Pair, rightPair: &Pair) -> bool {
|
||||||
|
let checkValue = (leftPair.getChecksumPortion() + 16 * rightPair.getChecksumPortion()) % 79;
|
||||||
|
let mut targetCheckValue =
|
||||||
|
9 * leftPair.getFinderPattern().getValue() + rightPair.getFinderPattern().getValue();
|
||||||
|
if targetCheckValue > 72 {
|
||||||
|
targetCheckValue -= 1;
|
||||||
|
}
|
||||||
|
if targetCheckValue > 8 {
|
||||||
|
targetCheckValue -= 1;
|
||||||
|
}
|
||||||
|
checkValue == targetCheckValue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodePair(
|
||||||
|
&mut self,
|
||||||
|
row: &BitArray,
|
||||||
|
right: bool,
|
||||||
|
rowNumber: u32,
|
||||||
|
hints: &DecodingHintDictionary,
|
||||||
|
) -> Option<Pair> {
|
||||||
|
let pos_pair = || -> Result<Pair, Exceptions> {
|
||||||
|
let startEnd = self.findFinderPattern(row, right)?;
|
||||||
|
let pattern = self.parseFoundFinderPattern(row, rowNumber, right, &startEnd)?;
|
||||||
|
|
||||||
|
// RXingResultPointCallback resultPointCallback = hints == null ? null :
|
||||||
|
// (RXingResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
|
||||||
|
|
||||||
|
// if (resultPointCallback != null) {
|
||||||
|
// startEnd = pattern.getStartEnd();
|
||||||
|
// float center = (startEnd[0] + startEnd[1] - 1) / 2.0f;
|
||||||
|
// if (right) {
|
||||||
|
// // row is actually reversed
|
||||||
|
// center = row.getSize() - 1 - center;
|
||||||
|
// }
|
||||||
|
// resultPointCallback.foundPossibleRXingResultPoint(new RXingResultPoint(center, rowNumber));
|
||||||
|
// }
|
||||||
|
|
||||||
|
let outside = self.decodeDataCharacter(row, &pattern, true)?;
|
||||||
|
let inside = self.decodeDataCharacter(row, &pattern, false)?;
|
||||||
|
|
||||||
|
// todo!("must add callback");
|
||||||
|
|
||||||
|
Ok(Pair::new(
|
||||||
|
1597 * outside.getValue() + inside.getValue(),
|
||||||
|
outside.getChecksumPortion() + 4 * inside.getChecksumPortion(),
|
||||||
|
pattern,
|
||||||
|
))
|
||||||
|
}();
|
||||||
|
if pos_pair.is_err() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(pos_pair.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodeDataCharacter(
|
||||||
|
&mut self,
|
||||||
|
row: &BitArray,
|
||||||
|
pattern: &FinderPattern,
|
||||||
|
outsideChar: bool,
|
||||||
|
) -> Result<DataCharacter, Exceptions> {
|
||||||
|
let mut counters = [0_u32; 8]; //self.getDataCharacterCounters();
|
||||||
|
//Arrays.fill(counters, 0);
|
||||||
|
// counters.fill(0);
|
||||||
|
|
||||||
|
if outsideChar {
|
||||||
|
self.recordPatternInReverse(row, pattern.getStartEnd()[0], &mut counters)?;
|
||||||
|
} else {
|
||||||
|
self.recordPattern(row, pattern.getStartEnd()[1], &mut counters)?;
|
||||||
|
// reverse it
|
||||||
|
let mut i = 0;
|
||||||
|
let mut j = counters.len();
|
||||||
|
while i < j {
|
||||||
|
// for (int i = 0, j = counters.length - 1; i < j; i++, j--) {
|
||||||
|
let temp = counters[i];
|
||||||
|
counters[i] = counters[j];
|
||||||
|
counters[j] = temp;
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let numModules = if outsideChar { 16 } else { 15 };
|
||||||
|
|
||||||
|
let elementWidth: f32 = counters.iter().sum::<u32>() as f32 / numModules as f32;
|
||||||
|
|
||||||
|
let mut oddCounts = [0u32; 4]; //self.getOddCounts();
|
||||||
|
let mut evenCounts = [0u32; 4]; // self.getEvenCounts();
|
||||||
|
let mut oddRoundingErrors = [0f32; 4]; // self.getOddRoundingErrors();
|
||||||
|
let mut evenRoundingErrors = [0f32; 4]; // self.getEvenRoundingErrors();
|
||||||
|
|
||||||
|
for i in 0..counters.len() {
|
||||||
|
// for (int i = 0; i < counters.length; i++) {
|
||||||
|
let value: f32 = counters[i] as f32 / elementWidth;
|
||||||
|
let mut count = (value + 0.5) as u32; // Round
|
||||||
|
if count < 1 {
|
||||||
|
count = 1;
|
||||||
|
} else if count > 8 {
|
||||||
|
count = 8;
|
||||||
|
}
|
||||||
|
let offset = i / 2;
|
||||||
|
if (i & 0x01) == 0 {
|
||||||
|
oddCounts[offset] = count;
|
||||||
|
oddRoundingErrors[offset] = value - count as f32;
|
||||||
|
} else {
|
||||||
|
evenCounts[offset] = count;
|
||||||
|
evenRoundingErrors[offset] = value - count as f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.adjustOddEvenCounts(outsideChar, numModules)?;
|
||||||
|
|
||||||
|
let mut oddSum = 0;
|
||||||
|
let mut oddChecksumPortion = 0;
|
||||||
|
for i in (0..oddCounts.len()).rev() {
|
||||||
|
// for (int i = oddCounts.length - 1; i >= 0; i--) {
|
||||||
|
oddChecksumPortion *= 9;
|
||||||
|
oddChecksumPortion += oddCounts[i];
|
||||||
|
oddSum += oddCounts[i];
|
||||||
|
}
|
||||||
|
let mut evenChecksumPortion = 0;
|
||||||
|
let mut evenSum = 0;
|
||||||
|
for i in (0..evenCounts.len()).rev() {
|
||||||
|
// for (int i = evenCounts.length - 1; i >= 0; i--) {
|
||||||
|
evenChecksumPortion *= 9;
|
||||||
|
evenChecksumPortion += evenCounts[i];
|
||||||
|
evenSum += evenCounts[i];
|
||||||
|
}
|
||||||
|
let checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion;
|
||||||
|
|
||||||
|
self.oddCounts = oddCounts;
|
||||||
|
self.evenCounts = evenCounts;
|
||||||
|
self.oddRoundingErrors = oddRoundingErrors;
|
||||||
|
self.evenRoundingErrors = evenRoundingErrors;
|
||||||
|
|
||||||
|
if outsideChar {
|
||||||
|
if (oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4 {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
let group = ((12 - oddSum) / 2) as usize;
|
||||||
|
let oddWidest = Self::OUTSIDE_ODD_WIDEST[group];
|
||||||
|
let evenWidest = 9 - oddWidest;
|
||||||
|
let vOdd = rss_utils::getRSSvalue(&oddCounts, oddWidest, false);
|
||||||
|
let vEven = rss_utils::getRSSvalue(&evenCounts, evenWidest, true);
|
||||||
|
let tEven = Self::OUTSIDE_EVEN_TOTAL_SUBSET[group];
|
||||||
|
let gSum = Self::OUTSIDE_GSUM[group];
|
||||||
|
return Ok(DataCharacter::new(
|
||||||
|
vOdd * tEven + vEven + gSum,
|
||||||
|
checksumPortion,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
if (evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4 {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
let group = ((10 - evenSum) / 2) as usize;
|
||||||
|
let oddWidest = Self::INSIDE_ODD_WIDEST[group];
|
||||||
|
let evenWidest = 9 - oddWidest;
|
||||||
|
let vOdd = rss_utils::getRSSvalue(&oddCounts, oddWidest, true);
|
||||||
|
let vEven = rss_utils::getRSSvalue(&evenCounts, evenWidest, false);
|
||||||
|
let tOdd = Self::INSIDE_ODD_TOTAL_SUBSET[group];
|
||||||
|
let gSum = Self::INSIDE_GSUM[group];
|
||||||
|
return Ok(DataCharacter::new(
|
||||||
|
vEven * tOdd + vOdd + gSum,
|
||||||
|
checksumPortion,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findFinderPattern(
|
||||||
|
&mut self,
|
||||||
|
row: &BitArray,
|
||||||
|
rightFinderPattern: bool,
|
||||||
|
) -> Result<[usize; 2], Exceptions> {
|
||||||
|
// let counters = self.getDecodeFinderCounters();
|
||||||
|
// counters[0] = 0;
|
||||||
|
// counters[1] = 0;
|
||||||
|
// counters[2] = 0;
|
||||||
|
// counters[3] = 0;
|
||||||
|
let mut counters = [0u32; 4];
|
||||||
|
|
||||||
|
let width = row.getSize();
|
||||||
|
let mut isWhite = false;
|
||||||
|
let mut rowOffset = 0;
|
||||||
|
while rowOffset < width {
|
||||||
|
isWhite = !row.get(rowOffset);
|
||||||
|
if rightFinderPattern == isWhite {
|
||||||
|
// Will encounter white first when searching for right finder pattern
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rowOffset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut counterPosition = 0;
|
||||||
|
let mut patternStart = rowOffset;
|
||||||
|
for x in rowOffset..width {
|
||||||
|
// for (int x = rowOffset; x < width; x++) {
|
||||||
|
if row.get(x) != isWhite {
|
||||||
|
counters[counterPosition] += 1;
|
||||||
|
} else {
|
||||||
|
if counterPosition == 3 {
|
||||||
|
if self.isFinderPattern(&counters) {
|
||||||
|
return Ok([patternStart, x]);
|
||||||
|
}
|
||||||
|
patternStart += (counters[0] + counters[1]) as usize;
|
||||||
|
counters[0] = counters[2];
|
||||||
|
counters[1] = counters[3];
|
||||||
|
counters[2] = 0;
|
||||||
|
counters[3] = 0;
|
||||||
|
counterPosition -= 1;
|
||||||
|
} else {
|
||||||
|
counterPosition += 1;
|
||||||
|
}
|
||||||
|
counters[counterPosition] = 1;
|
||||||
|
isWhite = !isWhite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseFoundFinderPattern(
|
||||||
|
&mut self,
|
||||||
|
row: &BitArray,
|
||||||
|
rowNumber: u32,
|
||||||
|
right: bool,
|
||||||
|
startEnd: &[usize],
|
||||||
|
) -> Result<FinderPattern, Exceptions> {
|
||||||
|
// Actually we found elements 2-5
|
||||||
|
let firstIsBlack = row.get(startEnd[0]);
|
||||||
|
let mut firstElementStart = startEnd[0] as isize - 1;
|
||||||
|
// Locate element 1
|
||||||
|
while firstElementStart >= 0 && firstIsBlack != row.get(firstElementStart as usize) {
|
||||||
|
firstElementStart -= 1;
|
||||||
|
}
|
||||||
|
firstElementStart += 1;
|
||||||
|
let firstCounter = startEnd[0] - firstElementStart as usize;
|
||||||
|
// Make 'counters' hold 1-4
|
||||||
|
// let counters = self.getDecodeFinderCounters();
|
||||||
|
// System.arraycopy(counters, 0, counters, 1, counters.length - 1);
|
||||||
|
// counters.fill(0);
|
||||||
|
let mut counters = [0u32; 4];
|
||||||
|
counters[0] = firstCounter as u32;
|
||||||
|
let value = self.parseFinderValue(&counters, &Self::FINDER_PATTERNS)?;
|
||||||
|
let mut start = firstElementStart as usize;
|
||||||
|
let mut end = startEnd[1];
|
||||||
|
if right {
|
||||||
|
// row is actually reversed
|
||||||
|
start = row.getSize() - 1 - start;
|
||||||
|
end = row.getSize() - 1 - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(FinderPattern::new(
|
||||||
|
value,
|
||||||
|
[firstElementStart as usize, startEnd[1]],
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
rowNumber,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjustOddEvenCounts(
|
||||||
|
&mut self,
|
||||||
|
outsideChar: bool,
|
||||||
|
numModules: u32,
|
||||||
|
) -> Result<(), Exceptions> {
|
||||||
|
let oddSum = self.getOddCounts().iter().sum::<u32>(); //MathUtils.sum(getOddCounts());
|
||||||
|
let evenSum = self.getEvenCounts().iter().sum::<u32>(); //MathUtils.sum(getEvenCounts());
|
||||||
|
|
||||||
|
let mut incrementOdd = false;
|
||||||
|
let mut decrementOdd = false;
|
||||||
|
let mut incrementEven = false;
|
||||||
|
let mut decrementEven = false;
|
||||||
|
|
||||||
|
if outsideChar {
|
||||||
|
if oddSum > 12 {
|
||||||
|
decrementOdd = true;
|
||||||
|
} else if oddSum < 4 {
|
||||||
|
incrementOdd = true;
|
||||||
|
}
|
||||||
|
if evenSum > 12 {
|
||||||
|
decrementEven = true;
|
||||||
|
} else if evenSum < 4 {
|
||||||
|
incrementEven = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if oddSum > 11 {
|
||||||
|
decrementOdd = true;
|
||||||
|
} else if oddSum < 5 {
|
||||||
|
incrementOdd = true;
|
||||||
|
}
|
||||||
|
if evenSum > 10 {
|
||||||
|
decrementEven = true;
|
||||||
|
} else if evenSum < 4 {
|
||||||
|
incrementEven = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mismatch = oddSum as i32 + evenSum as i32 - numModules as i32;
|
||||||
|
let oddParityBad = (oddSum & 0x01) == (if outsideChar { 1 } else { 0 });
|
||||||
|
let evenParityBad = (evenSum & 0x01) == 1;
|
||||||
|
/*if (mismatch == 2) {
|
||||||
|
if (!(oddParityBad && evenParityBad)) {
|
||||||
|
throw ReaderException.getInstance();
|
||||||
|
}
|
||||||
|
decrementOdd = true;
|
||||||
|
decrementEven = true;
|
||||||
|
} else if (mismatch == -2) {
|
||||||
|
if (!(oddParityBad && evenParityBad)) {
|
||||||
|
throw ReaderException.getInstance();
|
||||||
|
}
|
||||||
|
incrementOdd = true;
|
||||||
|
incrementEven = true;
|
||||||
|
} else */
|
||||||
|
match mismatch {
|
||||||
|
1 => {
|
||||||
|
if oddParityBad {
|
||||||
|
if evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
decrementOdd = true;
|
||||||
|
} else {
|
||||||
|
if !evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
decrementEven = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-1 => {
|
||||||
|
if oddParityBad {
|
||||||
|
if evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
incrementOdd = true;
|
||||||
|
} else {
|
||||||
|
if !evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
incrementEven = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0 => {
|
||||||
|
if oddParityBad {
|
||||||
|
if !evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
// Both bad
|
||||||
|
if oddSum < evenSum {
|
||||||
|
incrementOdd = true;
|
||||||
|
decrementEven = true;
|
||||||
|
} else {
|
||||||
|
decrementOdd = true;
|
||||||
|
incrementEven = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if evenParityBad {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
// Nothing to do!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(Exceptions::NotFoundException("".to_owned())),
|
||||||
|
}
|
||||||
|
|
||||||
|
if incrementOdd {
|
||||||
|
if decrementOdd {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
Self::increment(&mut self.oddCounts, &self.oddRoundingErrors);
|
||||||
|
}
|
||||||
|
if decrementOdd {
|
||||||
|
Self::decrement(&mut self.oddCounts, &self.oddRoundingErrors);
|
||||||
|
}
|
||||||
|
if incrementEven {
|
||||||
|
if decrementEven {
|
||||||
|
return Err(Exceptions::NotFoundException("".to_owned()));
|
||||||
|
}
|
||||||
|
Self::increment(&mut self.evenCounts, &self.evenRoundingErrors);
|
||||||
|
}
|
||||||
|
if decrementEven {
|
||||||
|
Self::decrement(&mut self.evenCounts, &self.evenRoundingErrors);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
99
src/oned/rss/rss_utils.rs
Normal file
99
src/oned/rss/rss_utils.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. */
|
||||||
|
|
||||||
|
pub fn getRSSvalue(widths: &[u32], maxWidth: u32, noNarrow: bool) -> u32 {
|
||||||
|
let mut n = 0;
|
||||||
|
// for width in widths {
|
||||||
|
// // for (int width : widths) {
|
||||||
|
// n += width;
|
||||||
|
// }
|
||||||
|
n += widths.iter().sum::<u32>();
|
||||||
|
|
||||||
|
let mut val = 0;
|
||||||
|
let mut narrowMask = 0;
|
||||||
|
let elements = widths.len() as u32;
|
||||||
|
for bar in 0..(elements - 1) {
|
||||||
|
// for (int bar = 0; bar < elements - 1; bar++) {
|
||||||
|
// let elmWidth;
|
||||||
|
let mut elmWidth = 1;
|
||||||
|
narrowMask |= 1 << bar;
|
||||||
|
while elmWidth < widths[bar as usize] {
|
||||||
|
// for (elmWidth = 1, narrowMask |= 1 << bar;
|
||||||
|
// elmWidth < widths[bar];
|
||||||
|
// elmWidth++, narrowMask &= ~(1 << bar)) {
|
||||||
|
let mut subVal = combins(n - elmWidth - 1, elements - bar - 2);
|
||||||
|
if noNarrow
|
||||||
|
&& (narrowMask == 0)
|
||||||
|
&& (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)
|
||||||
|
{
|
||||||
|
subVal -= combins(n - elmWidth - (elements - bar), elements - bar - 2);
|
||||||
|
}
|
||||||
|
if elements - bar - 1 > 1 {
|
||||||
|
let mut lessVal = 0;
|
||||||
|
let mut mxwElement = n - elmWidth - (elements - bar - 2);
|
||||||
|
while mxwElement > maxWidth {
|
||||||
|
// for (int mxwElement = n - elmWidth - (elements - bar - 2);
|
||||||
|
// mxwElement > maxWidth; mxwElement--) {
|
||||||
|
lessVal += combins(n - elmWidth - mxwElement - 1, elements - bar - 3);
|
||||||
|
|
||||||
|
mxwElement -= 1;
|
||||||
|
}
|
||||||
|
subVal -= lessVal * (elements - 1 - bar);
|
||||||
|
} else if n - elmWidth > maxWidth {
|
||||||
|
subVal -= 1;
|
||||||
|
}
|
||||||
|
val += subVal;
|
||||||
|
|
||||||
|
elmWidth += 1;
|
||||||
|
narrowMask &= !(1 << bar)
|
||||||
|
}
|
||||||
|
n -= elmWidth;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combins(n: u32, r: u32) -> u32 {
|
||||||
|
let maxDenom;
|
||||||
|
let minDenom;
|
||||||
|
if n - r > r {
|
||||||
|
minDenom = r;
|
||||||
|
maxDenom = n - r;
|
||||||
|
} else {
|
||||||
|
minDenom = n - r;
|
||||||
|
maxDenom = r;
|
||||||
|
}
|
||||||
|
let mut val = 1;
|
||||||
|
let mut j = 1;
|
||||||
|
let mut i = n;
|
||||||
|
while i > maxDenom {
|
||||||
|
// for (int i = n; i > maxDenom; i--) {
|
||||||
|
val *= i;
|
||||||
|
if j <= minDenom {
|
||||||
|
val /= j;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
while j <= minDenom {
|
||||||
|
val /= j;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.common.AbstractBlackBoxTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class RSS14BlackBox1TestCase extends AbstractBlackBoxTestCase {
|
|
||||||
|
|
||||||
public RSS14BlackBox1TestCase() {
|
|
||||||
super("src/test/resources/blackbox/rss14-1", new MultiFormatReader(), BarcodeFormat.RSS_14);
|
|
||||||
addTest(6, 6, 0.0f);
|
|
||||||
addTest(6, 6, 180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.zxing.oned.rss;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.MultiFormatReader;
|
|
||||||
import com.google.zxing.common.AbstractBlackBoxTestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public final class RSS14BlackBox2TestCase extends AbstractBlackBoxTestCase {
|
|
||||||
|
|
||||||
public RSS14BlackBox2TestCase() {
|
|
||||||
super("src/test/resources/blackbox/rss14-2", new MultiFormatReader(), BarcodeFormat.RSS_14);
|
|
||||||
addTest(4, 8, 1, 1, 0.0f);
|
|
||||||
addTest(3, 8, 0, 1, 180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
60
tests/rss_14_blackbox.rs
Normal file
60
tests/rss_14_blackbox.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2008 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use rxing::{maxicode::MaxiCodeReader, BarcodeFormat, DecodeHintType, MultiFormatReader};
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn rss14_black_box1_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/rss14-1",
|
||||||
|
MultiFormatReader::default(),
|
||||||
|
BarcodeFormat::RSS_14,
|
||||||
|
);
|
||||||
|
|
||||||
|
// super("src/test/resources/blackbox/rss14-1", new MultiFormatReader(), BarcodeFormat.RSS_14);
|
||||||
|
tester.add_test(6, 6, 0.0);
|
||||||
|
tester.add_test(6, 6, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
#[test]
|
||||||
|
fn rss14_black_box2_test_case() {
|
||||||
|
let mut tester = common::AbstractBlackBoxTestCase::new(
|
||||||
|
"test_resources/blackbox/rss14-2",
|
||||||
|
MultiFormatReader::default(),
|
||||||
|
BarcodeFormat::RSS_14,
|
||||||
|
);
|
||||||
|
|
||||||
|
// super("src/test/resources/blackbox/rss14-2", new MultiFormatReader(), BarcodeFormat.RSS_14);
|
||||||
|
tester.add_test_complex(4, 8, 1, 1, 0.0);
|
||||||
|
tester.add_test_complex(3, 8, 0, 1, 180.0);
|
||||||
|
|
||||||
|
tester.test_black_box()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user