/* * 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.RXingResult; import com.google.zxing.RXingResultMetadataType; import com.google.zxing.common.AbstractBlackBoxTestCase; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.common.TestRXingResult; 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 testRXingResults = new ArrayList<>(); public PDF417BlackBox4TestCase() { super("src/test/resources/blackbox/pdf417-4", null, BarcodeFormat.PDF_417); testRXingResults.add(new TestRXingResult(3, 3, 0, 0, 0.0f)); } @Test @Override public void testBlackBox() throws IOException { assertFalse(testRXingResults.isEmpty()); Map> imageFiles = getImageFileLists(); int testCount = testRXingResults.size(); int[] passedCounts = new int[testCount]; int[] tryHarderCounts = new int[testCount]; Path testBase = getTestBase(); for (Entry> 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 results = new ArrayList<>(); for (Path imageFile : testImageGroup.getValue()) { BufferedImage image = ImageIO.read(imageFile.toFile()); float rotation = testRXingResults.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((RXingResult r) -> getMeta(r).getSegmentIndex())); StringBuilder resultText = new StringBuilder(); String fileId = null; for (RXingResult result : results) { PDF417RXingResultMetadata 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 < testRXingResults.size(); x++) { TestRXingResult testRXingResult = testRXingResults.get(x); log.info(String.format("Rotation %d degrees:", (int) testRXingResult.getRotation())); log.info(String.format(" %d of %d images passed (%d required)", passedCounts[x], numberOfTests, testRXingResult.getMustPassCount())); log.info(String.format(" %d of %d images passed with try harder (%d required)", tryHarderCounts[x], numberOfTests, testRXingResult.getTryHarderCount())); totalFound += passedCounts[x] + tryHarderCounts[x]; totalMustPass += testRXingResult.getMustPassCount() + testRXingResult.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++) { TestRXingResult testRXingResult = testRXingResults.get(x); String label = "Rotation " + testRXingResult.getRotation() + " degrees: Too many images failed"; assertTrue(label, passedCounts[x] >= testRXingResult.getMustPassCount()); assertTrue("Try harder, " + label, tryHarderCounts[x] >= testRXingResult.getTryHarderCount()); } } private static PDF417RXingResultMetadata getMeta(RXingResult result) { return result.getRXingResultMetadata() == null ? null : (PDF417RXingResultMetadata) result.getRXingResultMetadata().get( RXingResultMetadataType.PDF417_EXTRA_METADATA); } private RXingResult[] decode(BinaryBitmap source, boolean tryHarder) throws ReaderException { Map hints = new EnumMap<>(DecodeHintType.class); if (tryHarder) { hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); } return barcodeReader.decodeMultiple(source, hints); } private Map> getImageFileLists() throws IOException { Map> result = new HashMap<>(); for (Path file : getImageFiles()) { String testImageFileName = file.getFileName().toString(); String fileBaseName = testImageFileName.substring(0, testImageFileName.indexOf('-')); List files = result.computeIfAbsent(fileBaseName, k -> new ArrayList<>()); files.add(file); } return result; } }