PDF417BlackBox4TestCase.java
/*
* 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.
*/
package com.google.zxing.pdf417;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.BufferedImageLuminanceSource;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultMetadataType;
import com.google.zxing.common.AbstractBlackBoxTestCase;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.common.TestResult;
import com.google.zxing.multi.MultipleBarcodeReader;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
/**
* This class tests Macro PDF417 barcode specific functionality. It ensures that information, which is split into
* several barcodes can be properly combined again to yield the original data content.
*
* @author Guenther Grau
*/
public final class PDF417BlackBox4TestCase extends AbstractBlackBoxTestCase {
private static final Logger log = Logger.getLogger(AbstractBlackBoxTestCase.class.getSimpleName());
private final MultipleBarcodeReader barcodeReader = new PDF417Reader();
private final List<TestResult> testResults = new ArrayList<>();
public PDF417BlackBox4TestCase() {
super("src/test/resources/blackbox/pdf417-4", null, BarcodeFormat.PDF_417);
testResults.add(new TestResult(3, 3, 0, 0, 0.0f));
}
@Test
@Override
public void testBlackBox() throws IOException {
assertFalse(testResults.isEmpty());
Map<String,List<Path>> imageFiles = getImageFileLists();
int testCount = testResults.size();
int[] passedCounts = new int[testCount];
int[] tryHarderCounts = new int[testCount];
Path testBase = getTestBase();
for (Entry<String,List<Path>> testImageGroup : imageFiles.entrySet()) {
log.fine(String.format("Starting Image Group %s", testImageGroup.getKey()));
String fileBaseName = testImageGroup.getKey();
String expectedText;
Path expectedTextFile = testBase.resolve(fileBaseName + ".txt");
if (Files.exists(expectedTextFile)) {
expectedText = readFileAsString(expectedTextFile, StandardCharsets.UTF_8);
} else {
expectedTextFile = testBase.resolve(fileBaseName + ".bin");
assertTrue(Files.exists(expectedTextFile));
expectedText = readFileAsString(expectedTextFile, StandardCharsets.ISO_8859_1);
}
for (int x = 0; x < testCount; x++) {
List<Result> results = new ArrayList<>();
for (Path imageFile : testImageGroup.getValue()) {
BufferedImage image = ImageIO.read(imageFile.toFile());
float rotation = testResults.get(x).getRotation();
BufferedImage rotatedImage = rotateImage(image, rotation);
LuminanceSource source = new BufferedImageLuminanceSource(rotatedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
results.addAll(Arrays.asList(decode(bitmap, false)));
} catch (ReaderException ignored) {
// ignore
}
}
results.sort(Comparator.comparingInt((Result r) -> getMeta(r).getSegmentIndex()));
StringBuilder resultText = new StringBuilder();
String fileId = null;
for (Result result : results) {
PDF417ResultMetadata resultMetadata = getMeta(result);
assertNotNull("resultMetadata", resultMetadata);
if (fileId == null) {
fileId = resultMetadata.getFileId();
}
assertEquals("FileId", fileId, resultMetadata.getFileId());
resultText.append(result.getText());
}
assertEquals("ExpectedText", expectedText, resultText.toString());
passedCounts[x]++;
tryHarderCounts[x]++;
}
}
// Print the results of all tests first
int totalFound = 0;
int totalMustPass = 0;
int numberOfTests = imageFiles.keySet().size();
for (int x = 0; x < testResults.size(); x++) {
TestResult testResult = testResults.get(x);
log.info(String.format("Rotation %d degrees:", (int) testResult.getRotation()));
log.info(String.format(" %d of %d images passed (%d required)", passedCounts[x], numberOfTests,
testResult.getMustPassCount()));
log.info(String.format(" %d of %d images passed with try harder (%d required)", tryHarderCounts[x],
numberOfTests, testResult.getTryHarderCount()));
totalFound += passedCounts[x] + tryHarderCounts[x];
totalMustPass += testResult.getMustPassCount() + testResult.getTryHarderCount();
}
int totalTests = numberOfTests * testCount * 2;
log.info(String.format("Decoded %d images out of %d (%d%%, %d required)", totalFound, totalTests, totalFound *
100 /
totalTests, totalMustPass));
if (totalFound > totalMustPass) {
log.warning(String.format("+++ Test too lax by %d images", totalFound - totalMustPass));
} else if (totalFound < totalMustPass) {
log.warning(String.format("--- Test failed by %d images", totalMustPass - totalFound));
}
// Then run through again and assert if any failed
for (int x = 0; x < testCount; x++) {
TestResult testResult = testResults.get(x);
String label = "Rotation " + testResult.getRotation() + " degrees: Too many images failed";
assertTrue(label, passedCounts[x] >= testResult.getMustPassCount());
assertTrue("Try harder, " + label, tryHarderCounts[x] >= testResult.getTryHarderCount());
}
}
private static PDF417ResultMetadata getMeta(Result result) {
return result.getResultMetadata() == null ? null : (PDF417ResultMetadata) result.getResultMetadata().get(
ResultMetadataType.PDF417_EXTRA_METADATA);
}
private Result[] decode(BinaryBitmap source, boolean tryHarder) throws ReaderException {
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
if (tryHarder) {
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
}
return barcodeReader.decodeMultiple(source, hints);
}
private Map<String,List<Path>> getImageFileLists() throws IOException {
Map<String,List<Path>> result = new HashMap<>();
for (Path file : getImageFiles()) {
String testImageFileName = file.getFileName().toString();
String fileBaseName = testImageFileName.substring(0, testImageFileName.indexOf('-'));
List<Path> files = result.computeIfAbsent(fileBaseName, k -> new ArrayList<>());
files.add(file);
}
return result;
}
}