Browse Source

implemented handling of jpeg files

main
Stephan Richter 2 years ago
parent
commit
bb584ea7a6
  1. 2
      pom.xml
  2. 2
      resources/translations/Application.de.translation
  3. 6
      src/main/java/de/srsoftware/belegscanner/Constants.java
  4. 44
      src/main/java/de/srsoftware/belegscanner/gui/DocTable.java
  5. 85
      src/main/java/de/srsoftware/belegscanner/gui/MainFrame.java
  6. 42
      src/main/java/de/srsoftware/belegscanner/gui/Toolbar.java

2
pom.xml

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>BelegScanner</groupId>
<artifactId>BelegScanner</artifactId>
<version>1.0.7</version>
<version>1.0.8</version>
<name>BelegScanner</name>
<packaging>jar</packaging>

2
resources/translations/Application.de.translation

@ -8,6 +8,7 @@ current resolution : aktuelle Auflösung @@ -8,6 +8,7 @@ current resolution : aktuelle Auflösung
DAY : TAG
Directory : Ordner
display preview : Vorschau anzeigen
drop file : Datei löschen
done : fertig
Error code\: {} for {} : Fehlercode: {} für {}
Finished text recognition. : Texterkennung beendet.
@ -25,6 +26,7 @@ Scan failed. : Scannen fehlgeschlagen. @@ -25,6 +26,7 @@ Scan failed. : Scannen fehlgeschlagen.
Scanning… : Scanne…
scan! : scannen!
State : Status
Target type : Zieltyp
{} terminated\: : {} abgebrochen:
Text recognition… : Texterkennung…
This application requires the following helper commands to be installed\: : Diese Anwendung erfordert es, dass auch die folgenden Hilfsprogramme installiert sind:

6
src/main/java/de/srsoftware/belegscanner/Constants.java

@ -3,8 +3,12 @@ package de.srsoftware.belegscanner; @@ -3,8 +3,12 @@ package de.srsoftware.belegscanner;
public class Constants {
public static final String APPLICATION_NAME = "BelegScanner";
public static final String FILE_BROWSER = "thunar";
public static final String CONFIG_TARGET = "app.main.target";
public static final String DEFAULT_WIDTH = "209";
public static final String DEFAULT_HEIGHT = "297";
public static final String FILE_BROWSER = "thunar";
public static final String JPG = "jpeg";
public static final String OCR = "pdf+ocr";
public static final String PDF = "pdf";
}

44
src/main/java/de/srsoftware/belegscanner/gui/DocTable.java

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
package de.srsoftware.belegscanner.gui;
import static de.srsoftware.belegscanner.Application.t;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
@ -29,7 +31,6 @@ import org.slf4j.Logger; @@ -29,7 +31,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.srsoftware.belegscanner.Constants;
import static de.srsoftware.belegscanner.Application.*;
/**
*
@ -40,13 +41,12 @@ import static de.srsoftware.belegscanner.Application.*; @@ -40,13 +41,12 @@ import static de.srsoftware.belegscanner.Application.*;
public class DocTable extends JPanel{
private static final Logger LOG = LoggerFactory.getLogger(DocTable.class);
private static FilenameFilter PAGES = (dir,name) -> name.toLowerCase().endsWith("pdf") && name.toLowerCase().startsWith("page");
private static FilenameFilter PDFS = (dir,name) -> name.toLowerCase().endsWith("pdf");
private static FilenameFilter PAGES = (dir,name) -> name.toLowerCase().endsWith("pdf") && name.toLowerCase().contains("page");
private static int rowCounter = 0;
private static Font btnFont = new Font("Arial", Font.PLAIN, 28);
public interface PreviewListener{
public void show(String filename);
public void show(Path filename);
}
/**
@ -78,13 +78,12 @@ public class DocTable extends JPanel{ @@ -78,13 +78,12 @@ public class DocTable extends JPanel{
buttons.add(joinButton = button("⎗",t("join PDFs"),ev -> joinDocs(path)));
buttons.add(button("🖻",t("display preview"),ev -> preview(path)));
buttons.add(button("✓",t("done"),ev -> drop(this)));
buttons.add(button("❌",t("drop file"),ev -> dropFile(path)));
constraints.gridx = 2;
add(buttons,constraints);
}
/**
* drop the selected document from the table
* @param row
@ -181,6 +180,18 @@ public class DocTable extends JPanel{ @@ -181,6 +180,18 @@ public class DocTable extends JPanel{
return btn;
}
private static int compareFiles(String file1, String file2) {
return timestampFrom(file1) < timestampFrom(file2) ? 1 : -1;
}
private void dropFile(String path) {
Path latest = latestFile(path);
if (latest != null) {
latest.toFile().delete();
preview(path); // show lates of remaining files
}
}
/**
* join documents in given path
* @param path
@ -217,6 +228,14 @@ public class DocTable extends JPanel{ @@ -217,6 +228,14 @@ public class DocTable extends JPanel{
setState(path,t("PDFs joined."));
preview(path);
}
private Path latestFile(String path) {
File folder = new File(path);
if (!folder.exists()) return null;
List<String> files = Arrays.asList(folder.list());
String latest = files.stream().sorted(DocTable::compareFiles).findFirst().orElse(null);
return latest == null ? null : Path.of(path,latest);
}
/**
* open given path in external file browser
@ -245,11 +264,7 @@ public class DocTable extends JPanel{ @@ -245,11 +264,7 @@ public class DocTable extends JPanel{
*/
public void preview(String path) {
LOG.debug("preview({})",path);
File folder = new File(path);
if (!folder.exists()) return;
List<String> pdfs = Arrays.asList(folder.list(PDFS));
LOG.debug("PDFs: {}",pdfs);
if (!pdfs.isEmpty()) previewListeners.forEach(l -> l.show(Path.of(path,pdfs.get(0)).toString()));
previewListeners.forEach(l -> l.show(latestFile(path)));
}
/**
@ -260,5 +275,12 @@ public class DocTable extends JPanel{ @@ -260,5 +275,12 @@ public class DocTable extends JPanel{
public void setState(String path, String state) {
Row row = rows.get(path);
if (row != null) row.status(state);
}
private static long timestampFrom(String filename) {
try {
return Long.parseLong(filename.split("\\.",2)[0]);
} catch (Exception e) {}
return 0;
}
}

85
src/main/java/de/srsoftware/belegscanner/gui/MainFrame.java

@ -1,20 +1,35 @@ @@ -1,20 +1,35 @@
package de.srsoftware.belegscanner.gui;
import static de.srsoftware.belegscanner.Application.t;
import static de.srsoftware.belegscanner.Constants.CONFIG_TARGET;
import static de.srsoftware.belegscanner.Constants.FILE_BROWSER;
import static de.srsoftware.belegscanner.Constants.JPG;
import static de.srsoftware.belegscanner.Constants.PDF;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
@ -29,10 +44,7 @@ import org.json.JSONArray; @@ -29,10 +44,7 @@ import org.json.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static de.srsoftware.belegscanner.Application.*;
import de.srsoftware.belegscanner.Configuration;
import de.srsoftware.belegscanner.Constants;
/**
* The "guts" of the application:
@ -46,7 +58,7 @@ public class MainFrame extends JFrame { @@ -46,7 +58,7 @@ public class MainFrame extends JFrame {
private static final long serialVersionUID = 210283601541223645L;
private static final String HOME = System.getProperty("user.home");
private static final Pattern MARKEN = Pattern.compile("\\$([a-zA-Z]+)");
private static final Pattern MARKEN = Pattern.compile("\\$([a-zäöüA-ZÄÖÜ]+)");
private static final String APP_WIDTH = "app.main.dimension.w";
@ -83,6 +95,10 @@ public class MainFrame extends JFrame { @@ -83,6 +95,10 @@ public class MainFrame extends JFrame {
private boolean isScanning = false;
private JComponent previewComponent = null;
private JPanel pdfPreview;
/**
* Create application main frame.
* @param config
@ -103,7 +119,9 @@ public class MainFrame extends JFrame { @@ -103,7 +119,9 @@ public class MainFrame extends JFrame {
add(toolbar,BorderLayout.EAST);
add(statusBar,BorderLayout.SOUTH);
add(docTable,BorderLayout.NORTH);
add(preview(),BorderLayout.CENTER);
pdfPreview = preview();
add(previewComponent = pdfPreview,BorderLayout.CENTER);
toolbar.addCategoryListener(this::setCategory)
.addDateListener(this::setDate)
.addDimensionListener(this::setDimension)
@ -138,7 +156,7 @@ public class MainFrame extends JFrame { @@ -138,7 +156,7 @@ public class MainFrame extends JFrame {
};
public void checkDependencies() {
List<String> missing = List.of("convert --version", "killall --version", "pdfsandwich -version", "pdftk --version", "scanimage --version",Constants.FILE_BROWSER+" --version").stream().map(this::appMissing).filter(app -> app != null).collect(Collectors.toList());
List<String> missing = List.of("convert --version", "killall --version", "pdfsandwich -version", "pdftk --version", "scanimage --version",FILE_BROWSER+" --version").stream().map(this::appMissing).filter(app -> app != null).collect(Collectors.toList());
if (!missing.isEmpty()) notifyAppsMissing(missing);
}
@ -185,6 +203,9 @@ public class MainFrame extends JFrame { @@ -185,6 +203,9 @@ public class MainFrame extends JFrame {
*/
private void performScan(String path, Dimension dimension) {
LOG.debug("performScan({})",path);
/* We need to all required config values before starting to scan, because the might be changed during scanning */
String target = config.getOrCreate(CONFIG_TARGET, "pdf");
setScanning(true);
File folder = new File(path);
@ -230,8 +251,13 @@ public class MainFrame extends JFrame { @@ -230,8 +251,13 @@ public class MainFrame extends JFrame {
LOG.error(t("{} terminated: "),builder,e);
}
setScanning(false);
if (JPG.equals(target)) {
docTable.setState(path, t("Image scanned"));
docTable.preview(path);
return;
};
String pdf = "page."+timestamp+".pdf";
String pdf = timestamp+".page.pdf";
cmd = new Vector<>();
cmd.add("convert");
cmd.add(raw);
@ -253,8 +279,13 @@ public class MainFrame extends JFrame { @@ -253,8 +279,13 @@ public class MainFrame extends JFrame {
}
Path.of(path, raw).toFile().delete();
String ocr = "page."+timestamp+".ocr.pdf";
if (PDF.equals(target)) {
docTable.setState(path, t("PDF created"));
docTable.preview(path);
return;
}
String ocr = timestamp+".page.ocr.pdf";
cmd = new Vector<>();
cmd.add("pdfsandwich");
@ -319,9 +350,37 @@ public class MainFrame extends JFrame { @@ -319,9 +350,37 @@ public class MainFrame extends JFrame {
* open file in preview panel
* @param file
*/
private void preview(String file) {
pdfViewer.openDocument(file);
pdfViewer.setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false);
private void preview(Path filePath) {
if (filePath == null) return;
String file = filePath.toString();
if (file.toLowerCase().endsWith("pdf")) {
if (previewComponent != pdfPreview) {
remove(previewComponent);
previewComponent = pdfPreview;
add(previewComponent,BorderLayout.CENTER);
pack();
}
pdfViewer.openDocument(file);
pdfViewer.setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false);
}
if (file.toLowerCase().endsWith("jpg")) {
try {
Image img = ImageIO.read(new File(file));
Dimension dim = previewComponent.getSize();
double w = img.getWidth(null);
double h = img.getHeight(null);
double factor = Math.min(dim.width/w, dim.height/h);
if (factor != 1.0) img = img.getScaledInstance((int)(w*factor), (int)(h*factor), Image.SCALE_DEFAULT);
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
this.remove(previewComponent);
previewComponent = label;
this.add(previewComponent, BorderLayout.CENTER);
pack();
} catch (IOException e) {
LOG.error("Was not able to preview {}:",file,e);
}
}
fileName.setText(file);
}

42
src/main/java/de/srsoftware/belegscanner/gui/Toolbar.java

@ -37,6 +37,7 @@ import de.srsoftware.tools.gui.DateChooser; @@ -37,6 +37,7 @@ import de.srsoftware.tools.gui.DateChooser;
import de.srsoftware.tools.gui.SelectComboBox;
import static de.srsoftware.belegscanner.Application.*;
import static de.srsoftware.belegscanner.Constants.*;
/**
* create the application's toolbar
@ -95,7 +96,7 @@ public class Toolbar extends JPanel { @@ -95,7 +96,7 @@ public class Toolbar extends JPanel {
private JTextField height;
private SelectComboBox catPicker;
private int resolution = 150;
/**
* create toolbar
* @param config
@ -108,6 +109,7 @@ public class Toolbar extends JPanel { @@ -108,6 +109,7 @@ public class Toolbar extends JPanel {
add(input(t("Path"),pathPicker = pathPicker()));
addFormatSelector();
add(resolutionSelector());
add(typeSelector());
add(scanButton());
add(Box.createGlue());
Arrays.stream(getComponents()).filter(c -> c instanceof JPanel).map(JPanel.class::cast).forEach(p -> p.setBorder(BORDER));
@ -372,7 +374,7 @@ public class Toolbar extends JPanel { @@ -372,7 +374,7 @@ public class Toolbar extends JPanel {
}
/**
* create a small for to select the resolution for scanning
* create a radio group to select the resolution for scanning
* @return
*/
private JPanel resolutionSelector() {
@ -405,6 +407,42 @@ public class Toolbar extends JPanel { @@ -405,6 +407,42 @@ public class Toolbar extends JPanel {
scanListeners.forEach(l->l.actionPerformed(evt));
}
/**
* create one radio button for the typeSelector
* @param group
* @param label
* @param i
* @return
*/
private JRadioButton typeButton(ButtonGroup group, String label,String selection) {
JRadioButton btn = new JRadioButton(label);
group.add(btn);
btn.addActionListener(ev -> config.set(CONFIG_TARGET, label));
if (label.equals(selection)) btn.setSelected(true);
return btn;
}
/**
* create a radio group to select the target type for scanning
* @param jsonObject
* @return
*/
private JPanel typeSelector() {
ButtonGroup group = new ButtonGroup();
JPanel typeSelector = new JPanel(new BorderLayout());
JLabel label = new JLabel(t("Target type"));
String target = config.getOrCreate(CONFIG_TARGET, PDF);
typeSelector.add(label, BorderLayout.NORTH);
typeSelector.add(typeButton(group,t(JPG),target),BorderLayout.WEST);
typeSelector.add(typeButton(group,t(PDF),target),BorderLayout.CENTER);
typeSelector.add(typeButton(group,t(OCR),target),BorderLayout.EAST);
typeSelector.setMaximumSize(new Dimension(600,200));
return typeSelector;
}
/**
* category updated: notify listeners and update dependent fields
* @param newCat

Loading…
Cancel
Save