CommandLineRunner can now handle URIs again; refactored some duplicated code
diff --git a/javase/src/main/java/com/google/zxing/client/j2se/CommandLineRunner.java b/javase/src/main/java/com/google/zxing/client/j2se/CommandLineRunner.java
index 75e555d..d2fa2f0 100644
--- a/javase/src/main/java/com/google/zxing/client/j2se/CommandLineRunner.java
+++ b/javase/src/main/java/com/google/zxing/client/j2se/CommandLineRunner.java
@@ -20,6 +20,7 @@
import com.google.zxing.DecodeHintType;
import java.io.IOException;
+import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -27,7 +28,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
-import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -43,6 +43,7 @@
* directories, summary statistics are also displayed.
*
* @author dswitkin@google.com (Daniel Switkin)
+ * @author Sean Owen
*/
public final class CommandLineRunner {
@@ -58,7 +59,7 @@
}
Config config = new Config();
- Queue<Path> inputs = new ConcurrentLinkedQueue<>();
+ Queue<URI> inputs = new ConcurrentLinkedQueue<>();
for (String arg : args) {
String[] argValue = arg.split("=");
@@ -104,13 +105,25 @@
printUsage();
return;
}
- addArgumentToInputs(Paths.get(arg), config, inputs);
+ URI argURI = URI.create(arg);
+ if (argURI.getScheme() == null) {
+ argURI = new URI("file", argURI.getSchemeSpecificPart(), argURI.getFragment());
+ }
+ addArgumentToInputs(argURI, config, inputs);
break;
}
}
+
+ int numInputs = inputs.size();
+ if (numInputs == 0) {
+ System.err.println("No inputs specified");
+ printUsage();
+ return;
+ }
+
config.setHints(buildHints(config));
- int numThreads = Math.min(inputs.size(), Runtime.getRuntime().availableProcessors());
+ int numThreads = Math.min(numInputs, Runtime.getRuntime().availableProcessors());
int successful = 0;
if (numThreads > 1) {
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
@@ -126,44 +139,38 @@
successful += new DecodeWorker(config, inputs).call();
}
- int total = inputs.size();
- if (total > 1) {
- System.out.println("\nDecoded " + successful + " files out of " + total +
- " successfully (" + (successful * 100 / total) + "%)\n");
+ if (numInputs > 1) {
+ System.out.println("\nDecoded " + successful + " files out of " + numInputs +
+ " successfully (" + (successful * 100 / numInputs) + "%)\n");
}
}
- // Build all the inputs up front into a single flat list, so the threads can atomically pull
- // paths/URLs off the queue.
- private static void addArgumentToInputs(Path inputFile, Config config, Queue<Path> inputs) throws IOException {
- if (Files.isDirectory(inputFile)) {
- try (DirectoryStream<Path> paths = Files.newDirectoryStream(inputFile)) {
- for (Path singleFile : paths) {
- String filename = singleFile.getFileName().toString().toLowerCase(Locale.ENGLISH);
+ /**
+ * Build all the inputs up front into a single flat list, so the threads can atomically pull
+ * paths/URLs off the queue.
+ */
+ private static void addArgumentToInputs(URI input, Config config, Queue<URI> inputs) throws IOException {
+ // Special case: a local directory
+ if ("file".equals(input.getScheme()) && Files.isDirectory(Paths.get(input))) {
+ try (DirectoryStream<Path> childPaths = Files.newDirectoryStream(Paths.get(input))) {
+ for (Path childPath : childPaths) {
+ Path realChildPath = childPath.toRealPath();
// Skip hidden files and directories (e.g. svn stuff).
- if (filename.startsWith(".")) {
- continue;
- }
- // Recur on nested directories if requested, otherwise skip them.
- if (Files.isDirectory(singleFile)) {
- if (config.isRecursive()) {
- addArgumentToInputs(singleFile, config, inputs);
+ if (!realChildPath.getFileName().toString().startsWith(".")) {
+ // Recur on nested directories if requested, otherwise skip them.
+ if (config.isRecursive() && Files.isDirectory(realChildPath)) {
+ addArgumentToInputs(realChildPath.toUri(), config, inputs);
+ } else {
+ inputs.add(realChildPath.toUri());
}
- continue;
}
- // Skip text files and the results of dumping the black point.
- if (filename.endsWith(".txt") || filename.contains(".mono.png")) {
- continue;
- }
- inputs.add(singleFile);
}
}
} else {
- inputs.add(inputFile);
+ inputs.add(input);
}
}
- // Manually turn on all formats, even those not yet considered production quality.
private static Map<DecodeHintType,?> buildHints(Config config) {
Collection<BarcodeFormat> possibleFormats = new ArrayList<>();
String[] possibleFormatsNames = config.getPossibleFormats();
diff --git a/javase/src/main/java/com/google/zxing/client/j2se/DecodeWorker.java b/javase/src/main/java/com/google/zxing/client/j2se/DecodeWorker.java
index 5275c8b..5146da6 100644
--- a/javase/src/main/java/com/google/zxing/client/j2se/DecodeWorker.java
+++ b/javase/src/main/java/com/google/zxing/client/j2se/DecodeWorker.java
@@ -42,7 +42,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Callable;
@@ -59,9 +58,9 @@
private static final int WHITE = 0xFFFFFFFF;
private final Config config;
- private final Queue<Path> inputs;
+ private final Queue<URI> inputs;
- DecodeWorker(Config config, Queue<Path> inputs) {
+ DecodeWorker(Config config, Queue<URI> inputs) {
this.config = config;
this.inputs = inputs;
}
@@ -69,139 +68,101 @@
@Override
public Integer call() throws IOException {
int successful = 0;
- Path input;
- while ((input = inputs.poll()) != null) {
- if (Files.exists(input)) {
- if (config.isMulti()) {
- Result[] results = decodeMulti(input.toUri(), config.getHints());
- if (results != null) {
- successful++;
- if (config.isDumpResults()) {
- dumpResultMulti(input, results);
- }
- }
- } else {
- Result result = decode(input.toUri(), config.getHints());
- if (result != null) {
- successful++;
- if (config.isDumpResults()) {
- dumpResult(input, result);
- }
- }
- }
- } else {
- if (decode(input.toUri(), config.getHints()) != null) {
- successful++;
+ for (URI input; (input = inputs.poll()) != null;) {
+ Result[] results = decode(input, config.getHints());
+ if (results != null) {
+ successful++;
+ if (config.isDumpResults()) {
+ dumpResult(input, results);
}
}
}
return successful;
}
- private static void dumpResult(Path input, Result result) throws IOException {
- String name = input.getFileName().toString();
- int pos = name.lastIndexOf('.');
- if (pos > 0) {
- name = name.substring(0, pos) + ".txt";
+ private static Path buildOutputPath(URI input, String suffix) throws IOException {
+ Path outDir;
+ String inputFileName;
+ if ("file".equals(input.getScheme())) {
+ Path inputPath = Paths.get(input);
+ outDir = inputPath.getParent();
+ inputFileName = inputPath.getFileName().toString();
+ } else {
+ outDir = Paths.get(".").toRealPath();
+ String[] pathElements = input.getPath().split("/");
+ inputFileName = pathElements[pathElements.length - 1];
}
- Path dumpFile = input.getParent().resolve(name);
- Files.write(dumpFile, Collections.singleton(result.getText()), StandardCharsets.UTF_8);
+
+ // Replace/add extension
+ int pos = inputFileName.lastIndexOf('.');
+ if (pos > 0) {
+ inputFileName = inputFileName.substring(0, pos) + suffix;
+ } else {
+ inputFileName += suffix;
+ }
+
+ return outDir.resolve(inputFileName);
}
- private static void dumpResultMulti(Path input, Result[] results) throws IOException {
- String name = input.getFileName().toString();
- int pos = name.lastIndexOf('.');
- if (pos > 0) {
- name = name.substring(0, pos) + ".txt";
- }
- Path dumpFile = input.getParent().resolve(name);
+ private static void dumpResult(URI input, Result... results) throws IOException {
Collection<String> resultTexts = new ArrayList<>();
for (Result result : results) {
resultTexts.add(result.getText());
}
- Files.write(dumpFile, resultTexts, StandardCharsets.UTF_8);
+ Files.write(buildOutputPath(input, ".txt"), resultTexts, StandardCharsets.UTF_8);
}
- private Result decode(URI uri, Map<DecodeHintType,?> hints) throws IOException {
+ private Result[] decode(URI uri, Map<DecodeHintType,?> hints) throws IOException {
BufferedImage image = ImageReader.readImage(uri);
- try {
- LuminanceSource source;
- if (config.getCrop() == null) {
- source = new BufferedImageLuminanceSource(image);
- } else {
- int[] crop = config.getCrop();
- source = new BufferedImageLuminanceSource(image, crop[0], crop[1], crop[2], crop[3]);
- }
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- if (config.isDumpBlackPoint()) {
- dumpBlackPoint(uri, image, bitmap);
- }
- Result result = new MultiFormatReader().decode(bitmap, hints);
- if (config.isBrief()) {
- System.out.println(uri + ": Success");
- } else {
- ParsedResult parsedResult = ResultParser.parseResult(result);
- System.out.println(uri + " (format: " + result.getBarcodeFormat() + ", type: " +
- parsedResult.getType() + "):\nRaw result:\n" + result.getText() + "\nParsed result:\n" +
- parsedResult.getDisplayResult());
+ LuminanceSource source;
+ if (config.getCrop() == null) {
+ source = new BufferedImageLuminanceSource(image);
+ } else {
+ int[] crop = config.getCrop();
+ source = new BufferedImageLuminanceSource(image, crop[0], crop[1], crop[2], crop[3]);
+ }
+
+ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+ if (config.isDumpBlackPoint()) {
+ dumpBlackPoint(uri, image, bitmap);
+ }
+
+ MultiFormatReader multiFormatReader = new MultiFormatReader();
+ Result[] results;
+ try {
+ if (config.isMulti()) {
+ MultipleBarcodeReader reader = new GenericMultipleBarcodeReader(multiFormatReader);
+ results = reader.decodeMultiple(bitmap, hints);
+ } else {
+ results = new Result[]{multiFormatReader.decode(bitmap, hints)};
+ }
+ } catch (NotFoundException ignored) {
+ System.out.println(uri + ": No barcode found");
+ return null;
+ }
+
+ if (config.isBrief()) {
+ System.out.println(uri + ": Success");
+ } else {
+ for (Result result : results) {
+ ParsedResult parsedResult = ResultParser.parseResult(result);
+ System.out.println(uri +
+ " (format: " + result.getBarcodeFormat() +
+ ", type: " + parsedResult.getType() + "):\n" +
+ "Raw result:\n" +
+ result.getText() + "\n" +
+ "Parsed result:\n" +
+ parsedResult.getDisplayResult());
System.out.println("Found " + result.getResultPoints().length + " result points.");
for (int i = 0; i < result.getResultPoints().length; i++) {
ResultPoint rp = result.getResultPoints()[i];
- if (rp != null) {
- System.out.println(" Point " + i + ": (" + rp.getX() + ',' + rp.getY() + ')');
- }
+ System.out.println(" Point " + i + ": (" + rp.getX() + ',' + rp.getY() + ')');
}
}
-
- return result;
- } catch (NotFoundException ignored) {
- System.out.println(uri + ": No barcode found");
- return null;
}
- }
- private Result[] decodeMulti(URI uri, Map<DecodeHintType,?> hints) throws IOException {
- BufferedImage image = ImageReader.readImage(uri);
- try {
- LuminanceSource source;
- if (config.getCrop() == null) {
- source = new BufferedImageLuminanceSource(image);
- } else {
- int[] crop = config.getCrop();
- source = new BufferedImageLuminanceSource(image, crop[0], crop[1], crop[2], crop[3]);
- }
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- if (config.isDumpBlackPoint()) {
- dumpBlackPoint(uri, image, bitmap);
- }
-
- MultiFormatReader multiFormatReader = new MultiFormatReader();
- MultipleBarcodeReader reader = new GenericMultipleBarcodeReader(multiFormatReader);
- Result[] results = reader.decodeMultiple(bitmap, hints);
-
- if (config.isBrief()) {
- System.out.println(uri + ": Success");
- } else {
- for (Result result : results) {
- ParsedResult parsedResult = ResultParser.parseResult(result);
- System.out.println(uri + " (format: "
- + result.getBarcodeFormat() + ", type: "
- + parsedResult.getType() + "):\nRaw result:\n"
- + result.getText() + "\nParsed result:\n"
- + parsedResult.getDisplayResult());
- System.out.println("Found " + result.getResultPoints().length + " result points.");
- for (int i = 0; i < result.getResultPoints().length; i++) {
- ResultPoint rp = result.getResultPoints()[i];
- System.out.println(" Point " + i + ": (" + rp.getX() + ',' + rp.getY() + ')');
- }
- }
- }
- return results;
- } catch (NotFoundException ignored) {
- System.out.println(uri + ": No barcode found");
- return null;
- }
+ return results;
}
/**
@@ -209,11 +170,7 @@
* to right: the original image, the row sampling monochrome version, and the 2D sampling
* monochrome version.
*/
- private static void dumpBlackPoint(URI uri, BufferedImage image, BinaryBitmap bitmap) {
- if (uri.getPath().contains(".mono.png")) {
- return;
- }
-
+ private static void dumpBlackPoint(URI uri, BufferedImage image, BinaryBitmap bitmap) throws IOException {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int stride = width * 3;
@@ -263,30 +220,17 @@
private static void writeResultImage(int stride,
int height,
int[] pixels,
- URI uri,
- String suffix) {
+ URI input,
+ String suffix) throws IOException {
BufferedImage result = new BufferedImage(stride, height, BufferedImage.TYPE_INT_ARGB);
result.setRGB(0, 0, stride, height, pixels, 0, stride);
-
- // Use the current working directory for URLs
- String resultName = uri.getPath();
- if ("http".equals(uri.getScheme())) {
- int pos = resultName.lastIndexOf('/');
- if (pos > 0) {
- resultName = '.' + resultName.substring(pos);
- }
- }
- int pos = resultName.lastIndexOf('.');
- if (pos > 0) {
- resultName = resultName.substring(0, pos);
- }
- resultName += suffix;
+ Path imagePath = buildOutputPath(input, suffix);
try {
- if (!ImageIO.write(result, "png", Paths.get(resultName).toFile())) {
- System.err.println("Could not encode an image to " + resultName);
+ if (!ImageIO.write(result, "png", imagePath.toFile())) {
+ System.err.println("Could not encode an image to " + imagePath);
}
} catch (IOException ignored) {
- System.err.println("Could not write to " + resultName);
+ System.err.println("Could not write to " + imagePath);
}
}
diff --git a/javase/src/main/java/com/google/zxing/client/j2se/ImageReader.java b/javase/src/main/java/com/google/zxing/client/j2se/ImageReader.java
index 3ee4dbf..45312ba 100644
--- a/javase/src/main/java/com/google/zxing/client/j2se/ImageReader.java
+++ b/javase/src/main/java/com/google/zxing/client/j2se/ImageReader.java
@@ -53,8 +53,8 @@
}
public static BufferedImage readDataURIImage(URI uri) throws IOException {
- String uriString = uri.toString();
- if (!uriString.startsWith("data:image/")) {
+ String uriString = uri.getSchemeSpecificPart();
+ if (!uriString.startsWith("image/")) {
throw new IOException("Unsupported data URI MIME type");
}
int base64Start = uriString.indexOf(BASE64TOKEN);