From 2c32e68a88318ef83dbdfb186fbed4b8a3a8b955 Mon Sep 17 00:00:00 2001 From: Ralf Eichinger Date: Thu, 9 Jun 2022 22:44:48 +0200 Subject: [PATCH] Add ConfiguredCamera handling (untested) --- README.md | 3 +- eazy-bookscanner-swing/README.md | 8 ++ eazy-bookscanner-swing/pom.xml | 33 +++++- .../com/datazuul/eazy/bookscanner/App.java | 25 ++++- .../bookscanner/devices/CameraFactory.java | 50 +++++++-- .../devices/CamerasProperties.java | 25 +++++ .../bookscanner/devices/ConfiguredCamera.java | 99 ++++++++++++++++++ .../bookscanner/devices/FocusModeChange.java | 30 ++++++ .../eazy/bookscanner/devices/Product.java | 48 +++++++++ .../eazy/bookscanner/devices/Vendor.java | 39 +++++++ .../eazy/bookscanner/devices/Zoom.java | 21 ++++ .../gui/ThumbnailsAndScanPanel.form | 5 + .../gui/ThumbnailsAndScanPanel.java | 2 +- .../src/main/resources/application.yml | 24 +++++ .../images/logo-datazuul-bookscan-16x16.png | Bin 0 -> 756 bytes .../images/logo-datazuul-bookscan-32x32.png | Bin 0 -> 1545 bytes .../images/logo-datazuul-bookscan-48x48.png | Bin 0 -> 2365 bytes .../images/splash-screen-bookscan-638x320.png | Bin 0 -> 20863 bytes 18 files changed, 394 insertions(+), 18 deletions(-) create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CamerasProperties.java create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/ConfiguredCamera.java create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/FocusModeChange.java create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Product.java create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Vendor.java create mode 100644 eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Zoom.java create mode 100644 eazy-bookscanner-swing/src/main/resources/application.yml create mode 100644 eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-16x16.png create mode 100644 eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-32x32.png create mode 100644 eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-48x48.png create mode 100644 eazy-bookscanner-swing/src/main/resources/images/splash-screen-bookscan-638x320.png diff --git a/README.md b/README.md index 679cde4..f7354cf 100644 --- a/README.md +++ b/README.md @@ -61,4 +61,5 @@ This app makes usage of * NetBeans Platform: * CHDK-PTP-Java Library: -* usb4java-javax: \ No newline at end of file +* usb4java-javax: +* USB IDs: \ No newline at end of file diff --git a/eazy-bookscanner-swing/README.md b/eazy-bookscanner-swing/README.md index bf14154..37135f3 100644 --- a/eazy-bookscanner-swing/README.md +++ b/eazy-bookscanner-swing/README.md @@ -1,3 +1,11 @@ +# Eazy BookScanner + +OpenSource Book Scanner application for digitizing books with two cameras. +Usage for two digital cameras like described at . + +![Screenshot GUI Eazy BookScanner](./screenshot-20201221.jpg) + +## References * Swing: https://zetcode.com/javaswing/ * Icons: https://www.javacodegeeks.com/2020/03/javafx-tip-32-need-icons-use-ikonli.html \ No newline at end of file diff --git a/eazy-bookscanner-swing/pom.xml b/eazy-bookscanner-swing/pom.xml index c71f7af..5459d26 100644 --- a/eazy-bookscanner-swing/pom.xml +++ b/eazy-bookscanner-swing/pom.xml @@ -3,16 +3,21 @@ 4.0.0 - com.datazuul - eazy-bookscanner-parent - 0.2.1-SNAPSHOT + org.springframework.boot + spring-boot-starter-parent + 2.6.7 + Eazy BookScanner (Swing) com.datazuul.eazy.bookscanner eazy-bookscanner-swing - 1.0-SNAPSHOT + 1.0.0-SNAPSHOT + jar + 1.8 + 1.8 + 1.8 UTF-8 com.datazuul.eazy.bookscanner.App @@ -23,6 +28,11 @@ CHDK-PTP-Java 0.7.1-SNAPSHOT + + commons-cli + commons-cli + 1.5.0 + org.imgscalr imgscalr-lib @@ -38,5 +48,20 @@ ikonli-swing 12.3.1 + + org.springframework.boot + spring-boot-starter + + + + eazy-bookscanner-${project.version} + + + + org.springframework.boot + spring-boot-maven-plugin + + + \ No newline at end of file diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/App.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/App.java index 7a8d097..52db74c 100644 --- a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/App.java +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/App.java @@ -1,5 +1,6 @@ package com.datazuul.eazy.bookscanner; +import com.datazuul.eazy.bookscanner.devices.CamerasProperties; import com.datazuul.eazy.bookscanner.gui.ThumbnailsAndScanPanel; import java.awt.Color; import java.awt.EventQueue; @@ -11,10 +12,22 @@ import static javax.swing.WindowConstants.EXIT_ON_CLOSE; import org.kordamp.ikonli.material2.Material2AL; import org.kordamp.ikonli.swing.FontIcon; - +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Implementing ApplicationRunner interface tells Spring Boot to automatically + * call the run method AFTER the application context has been loaded. + */ +@SpringBootApplication +@EnableConfigurationProperties(CamerasProperties.class) public class App extends JFrame { public static final int ICON_SIZE = 20; + + public static ConfigurableApplicationContext CONTEXT; public App() { initUI(); @@ -71,9 +84,17 @@ private void initUI() { } public static void main(String[] args) { + CONTEXT = new SpringApplicationBuilder(App.class).headless(false).run(args); EventQueue.invokeLater(() -> { - App ex = new App(); + App ex = CONTEXT.getBean(App.class); ex.setVisible(true); }); + + logConfig(); + } + + private static void logConfig() { + CamerasProperties props = CONTEXT.getBean(CamerasProperties.class); + System.out.println(props); } } diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CameraFactory.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CameraFactory.java index c2591d7..7dee982 100644 --- a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CameraFactory.java +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CameraFactory.java @@ -1,21 +1,51 @@ package com.datazuul.eazy.bookscanner.devices; import chdk.ptp.java.ICamera; -import chdk.ptp.java.SupportedCamera; import chdk.ptp.java.connection.CameraUsbDevice; -import javax.usb.UsbDevice; +import com.datazuul.eazy.bookscanner.App; +import java.util.List; +import java.util.Objects; +import org.springframework.stereotype.Component; +@Component public class CameraFactory { public static ICamera getCamera(CameraUsbDevice cameraUsbDevice) { - SupportedCamera sc = SupportedCamera.getCamera(cameraUsbDevice.getIdVendor(), cameraUsbDevice.getIdProduct()); - if (sc != null) { - // known camera - create specified class - try { - UsbDevice usbDevice = cameraUsbDevice.getDevice(); - return sc.getClazz().getConstructor(UsbDevice.class).newInstance(usbDevice); - } catch (Exception ex) { - return null; + CamerasProperties props = App.CONTEXT.getBean(CamerasProperties.class); + + Short idVendor = cameraUsbDevice.getIdVendor(); + Short idProduct = cameraUsbDevice.getIdProduct(); + + ConfiguredCamera camera = getCamera(props, idVendor, idProduct, cameraUsbDevice); + return camera; + +// SupportedCamera sc = SupportedCamera.getCamera(idVendor, idProduct); +// if (sc != null) { +// // known camera - create specified class +// try { +// UsbDevice usbDevice = cameraUsbDevice.getDevice(); +// return sc.getClazz().getConstructor(UsbDevice.class).newInstance(usbDevice); +// } catch (Exception ex) { +// return null; +// } +// } +// return null; + } + + private static ConfiguredCamera getCamera(CamerasProperties props, Short idVendor, Short idProduct, CameraUsbDevice cameraUsbDevice) { + List vendors = props.getVendors(); + if (vendors != null) { + Vendor vendor = vendors.stream().filter(v -> Objects.equals(idVendor, v.getId())).findAny().orElse(null); + if (vendor != null) { + System.out.println("found vendor: " + vendor); + List products = vendor.getProducts(); + if (products != null) { + Product product = products.stream().filter(p -> Objects.equals(idProduct, p.getId())).findAny().orElse(null); + if (product != null) { + System.out.println("found product: " + product); + return new ConfiguredCamera(cameraUsbDevice.getDevice(), product); + } + } } } return null; diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CamerasProperties.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CamerasProperties.java new file mode 100644 index 0000000..03204d6 --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/CamerasProperties.java @@ -0,0 +1,25 @@ +package com.datazuul.eazy.bookscanner.devices; + +import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; + +@ConfigurationProperties(prefix = "cameras") +@ConfigurationPropertiesScan +public class CamerasProperties { + + private List vendors; + + public List getVendors() { + return vendors; + } + + public void setVendors(List vendors) { + this.vendors = vendors; + } + + @Override + public String toString() { + return "CamerasProperties{" + "vendors=" + vendors + '}'; + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/ConfiguredCamera.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/ConfiguredCamera.java new file mode 100644 index 0000000..17b7a3b --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/ConfiguredCamera.java @@ -0,0 +1,99 @@ +package com.datazuul.eazy.bookscanner.devices; + +import chdk.ptp.java.camera.FailSafeCamera; +import chdk.ptp.java.exception.GenericCameraException; +import chdk.ptp.java.exception.PTPTimeoutException; +import chdk.ptp.java.model.FocusMode; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.usb.UsbDevice; + +public class ConfiguredCamera extends FailSafeCamera { + + private Logger log = Logger.getLogger(ConfiguredCamera.class.getName()); + + private final Product product; + + public ConfiguredCamera(UsbDevice device, Product product) { + super(device); + this.product = product; + } + + @Override + public void setFocusMode(FocusMode mode) throws GenericCameraException, PTPTimeoutException { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + throw new GenericCameraException(e.getLocalizedMessage()); + } + + // currently only supporting autofocus mode + if (FocusMode.AUTO.equals(mode)) { + List autofocus = product.getAutofocus(); + int currentFocusMode = getFocusMode().getValue(); + for (FocusModeChange focusModeChange : autofocus) { + if (currentFocusMode == focusModeChange.getCurrentMode()) { + List commands = focusModeChange.getExecute(); + if (commands != null) { + for (String command : commands) { + switch (command) { + case "LEFT": + this.executeLuaCommand("click('left');"); + break; + case "RIGHT": + this.executeLuaCommand("click('right');"); + break; + case "SET": + this.executeLuaCommand("click('set');"); + break; + default: + break; + } + if (command.startsWith("sleep")) { + long milliseconds = Long.valueOf(command.substring(5)); + try { + Thread.sleep(milliseconds); + } catch (InterruptedException ex) { + log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); + throw new GenericCameraException(ex.getLocalizedMessage()); + } + } + } + } + // activate auto focus and focus + try { + this.executeLuaCommand("set_aflock(0);"); + this.executeLuaCommand("press('shoot_half');"); + Thread.sleep(800); + this.executeLuaCommand("release('shoot_half');"); + this.executeLuaCommand("set_aflock(1);"); + Thread.sleep(1000); + } catch (InterruptedException ex) { + log.log(Level.SEVERE, ex.getLocalizedMessage(), ex); + throw new GenericCameraException(ex.getLocalizedMessage()); + } + } + } + } + } + + @Override + public void setZoom(int zoomPosition) throws PTPTimeoutException, GenericCameraException { + Zoom zoom = product.getZoom(); + if (zoom != null) { + List preExecute = zoom.getPreExecute(); + for (String command : preExecute) { + switch (command) { + case "SET_AUTOFOCUS": + setFocusMode(FocusMode.AUTO); + break; + default: + break; + } + } + } + super.setZoom(zoomPosition); + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/FocusModeChange.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/FocusModeChange.java new file mode 100644 index 0000000..0673461 --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/FocusModeChange.java @@ -0,0 +1,30 @@ +package com.datazuul.eazy.bookscanner.devices; + +import java.util.List; + +public class FocusModeChange { + + private int currentMode; + private List execute; + + public int getCurrentMode() { + return currentMode; + } + + public List getExecute() { + return execute; + } + + public void setCurrentMode(int currentMode) { + this.currentMode = currentMode; + } + + public void setExecute(List execute) { + this.execute = execute; + } + + @Override + public String toString() { + return "FocusModeChange{" + "currentMode=" + currentMode + ", execute=" + execute + '}'; + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Product.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Product.java new file mode 100644 index 0000000..cd62353 --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Product.java @@ -0,0 +1,48 @@ +package com.datazuul.eazy.bookscanner.devices; + +import java.util.List; + +public class Product { + + private List autofocus; + private Short id; + private String name; + private Zoom zoom; + + public List getAutofocus() { + return autofocus; + } + + public Short getId() { + return id; + } + + public String getName() { + return name; + } + + public Zoom getZoom() { + return zoom; + } + + public void setAutofocus(List autofocus) { + this.autofocus = autofocus; + } + + public void setId(Short id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setZoom(Zoom zoom) { + this.zoom = zoom; + } + + @Override + public String toString() { + return "Product{" + "autofocus=" + autofocus + ", id=" + id + ", name=" + name + ", zoom=" + zoom + '}'; + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Vendor.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Vendor.java new file mode 100644 index 0000000..c5dedbf --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Vendor.java @@ -0,0 +1,39 @@ +package com.datazuul.eazy.bookscanner.devices; + +import java.util.List; + +public class Vendor { + + private Short id; + private String name; + private List products; + + public Short getId() { + return id; + } + + public String getName() { + return name; + } + + public List getProducts() { + return products; + } + + public void setId(Short id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setProducts(List products) { + this.products = products; + } + + @Override + public String toString() { + return "Vendor{" + "id=" + id + ", name=" + name + ", products=" + products + '}'; + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Zoom.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Zoom.java new file mode 100644 index 0000000..c8ffc8a --- /dev/null +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/devices/Zoom.java @@ -0,0 +1,21 @@ +package com.datazuul.eazy.bookscanner.devices; + +import java.util.List; + +public class Zoom { + + private List preExecute; + + public List getPreExecute() { + return preExecute; + } + + public void setPreExecute(List preExecute) { + this.preExecute = preExecute; + } + + @Override + public String toString() { + return "Zoom{" + "preExecute=" + preExecute + '}'; + } +} diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.form b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.form index edaf5a4..2b64b94 100644 --- a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.form +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.form @@ -179,6 +179,11 @@ + + + + + diff --git a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.java b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.java index de00c9b..49d52cd 100644 --- a/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.java +++ b/eazy-bookscanner-swing/src/main/java/com/datazuul/eazy/bookscanner/gui/ThumbnailsAndScanPanel.java @@ -232,7 +232,6 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { scanPanels.setLayout(new javax.swing.BoxLayout(scanPanels, javax.swing.BoxLayout.X_AXIS)); - leftScanPanel.setAlignmentX(0.5F); leftScanPanel.setPreferredSize(new java.awt.Dimension(511, 800)); scanPanels.add(leftScanPanel); @@ -253,6 +252,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { add(scanPanels, java.awt.BorderLayout.CENTER); + bottomPanel.setPreferredSize(new java.awt.Dimension(59, 70)); bottomPanel.setLayout(new java.awt.BorderLayout()); shootButton.setBackground(new java.awt.Color(204, 255, 204)); diff --git a/eazy-bookscanner-swing/src/main/resources/application.yml b/eazy-bookscanner-swing/src/main/resources/application.yml new file mode 100644 index 0000000..d83c34c --- /dev/null +++ b/eazy-bookscanner-swing/src/main/resources/application.yml @@ -0,0 +1,24 @@ +cameras: + vendors: + - id: 0x04a9 + name: 'Canon, Inc.' + products: + - id: 0x322a + name: 'PowerShot A2200' + # The A2200 only has three focus modes (in this order on display): + # currentFocusMode in: "Macro" = 4 - "Normal" = 0 - "Infinity" = 3 + # FocusMode.MACRO (4), "Normal" = FocusMode.AUTO (0), "Infinity" = FocusMode.INF (3) + autofocus: + # set to "Normal" (there is no AUTO mode) and handle auto focus later during shoot + # see https://chdk.fandom.com/wiki/Script_commands#set_aflock + # macro + - current-mode: 4 + execute: [LEFT, sleep1000, RIGHT, sleep500, SET, sleep1000] + # normal + - current-mode: 0 + execute: [] + # infinity + - current-mode: 3 + execute: [LEFT, sleep1000, LEFT, sleep500, SET, sleep1000] + zoom: + pre-execute: [SET_AUTOFOCUS] diff --git a/eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-16x16.png b/eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..ce310fd7d5cea7cfaecdf2c99ca3ddedc3a50625 GIT binary patch literal 756 zcmVl0%S_DBP1sh}R!s-f^BpMAb z-~;#!hNXL-!JTm<8;yp5q^O{lmeSiafl_EmLkBN+7$ybz9#K6IWTL0KmJoH5itKSTwpo%bNE3x}SB^M0$T8bMZL#YBijkp0+VU2qaBgqD4iC{Z|b@ z)^!B?`rx8zjD$jHNKzLrs%o6J9EZEkAnfpB3yAq29n!{>Hmz9U2cI5SOHwhfA+a5E4vDMCmNz>MQK$X6=ZE|s7g#&t)5 zXIaFeQA|f7@bdg`%CfAtE|=?7=Z2rfB8tbyT|$;&aDQwJGozzmT&|1p8|qJ~v|t#< z@`H&9ioFC-uGg`e%fYlPj1LSTIXw*zcNv#qSr#1U{J&4>boPBJMH-SsI_s}2lVY_> zdTXy%BkQ}ns{lX)K$K;ZJj*seZf@e>CGsbb_kEW(huaE%Xdp^JTb$k0)wb|Swgvf*t msU^#Wm27rnLlB9nxEU+shoiANU2+zghn*9 zq_n6)0u-|_uR?aZ_7K6dr)z&t3NWkd)ym~1ZT#2!)vQl!1Sd44u z&Xx52Had#Uc>K_Ntx_33B9}Mp*2LaQ6Y2ELO2{vFcEY4q3yQnk*}3=3@jQNf^a$Bp z4$)*%t&qun0ni8R)PQGcsXGt~bqRq=C6bEBOXV3=&q``N5;=cseB1%->_9LY{jS

HWGn>tt>2x+LuU0^>GS0_lg z-=fJRejOd%s}-?G1hdhI<8^gw6d`07fNOsO%W-(TxCsB+TKOG$K{KjUIN8vEV?AIbr&gu{3=GlOI% z^FqYOYHQ&%o1uMvOJ1S~AxBt_+f+!UigI9lK98}vIXqciEm=_e&7e}@Olzyq#T5lm zPXWMPk7wGX(X_QUHy=9HiY*w6;r`SVSdKg7lQRrXSuC*B*O$fEv9BqL`h)_2L7(rE ze`V#SR;fgf%?4dfP1#JA<8W_s^1#5+WH6w|W`m4j1euq&wm6EAmzzu`|K4&3CMNz` z4uv{JG!2*43R`1iS&%}Z0Qc-H{OjvDWwD^GN%%zHW?8srX90?Oc+u&671%eDJ@EUD z8^PdmB9oB|eK(9r>vyz1)$$xH?hrl+wHi$TgT1+!k?+uh#&aMypR;)Z;_YYQ72 z*RwmnT{4D2pWR;7D7F*|;epo+K9>U{krXT@(>t%&Y&Z7Dlq~r{pRa!{6#8lRbBIME z^tQL7*=VeYm=J=og$4Zm^eF&9DU)TI^!hi>+H8Lm$3C~`MtwfR7R%mQi$t7+5YQBb z*X(vQ8w_R1`CJb7rlznO4uhg7H0X503X!P4$8L|7iWeNk{`C3!!->QCqA^WCo2R$i@8)C14} vAOK<+o?mwRd=vpjNIw6?d8c!=65M|PN48+qv~Zn@00000NkvXXu0mjfTSL*r literal 0 HcmV?d00001 diff --git a/eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-48x48.png b/eazy-bookscanner-swing/src/main/resources/images/logo-datazuul-bookscan-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..c35695411b161b15e9c8494a31f68ff2855d43f2 GIT binary patch literal 2365 zcmV-D3BvY?P)@~8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H12)ao`K~!jgy;*x~Q`Z^)-RtYO6X)Sa-p)HA;5ekFg+c^{q*ZAV zL#s-+b5%W+Jc=V?$B7@AJV8HQ8HWInl6I;W6IuYu?Pde~x_+3DPr*nxNK_PQ|3p7Dpn zulvH`0x>plOI9xE}a^1RS zv%Q~9H{%Ih9UlJpvCH*cLP-AD2>?w|s52V>a%9h*_qNm7b^-qx8Tq@z>HJPUh^Xaq zNEv36oDhOwG>Sx)4XQI5|8&%B{_$3QTQ1*?E ze38gmv8e$~WgixdMln1)i$Ej-8N;BVtPHhT+)F}lzNWZ%oQm@NSpY8qYYP~dn5efc zEOd$?p9^|zHaMJ4002c%AcSDn?S@(|$BBLWppwf4*>n2+hp!9|8@tWsB?bUOEc+3k zNaUY6{zqP;P@u3%p{gzHZ+!(0|5HQ#CD#}$fZm<8239W)9Brk9rRaAsru?hS=-@&0`Pz`@p5QTA6^ zwv=Jx@y&T|9`U->iqHD{@nCuyqx179RH+c-I0PaQ0Kop{=8XT5OyGE4M(?Vs;uR?g zSiYf>%kj;wE;LtEfB;xtSwT1!gTAm3Uwi&}v{hG&wjJkrnj(a(@`;3ea&Zy1xw+)d z2tl!0jZ^zKWx6|t!|6n?&9-enP1A${5R%ZeytT3tEfp15@OUsXH-|-^FXxG(9G6{5 z1k%&#bd(kpL@7eZ1b|JstS1=6gX!sbmIQ>G{UQ^c_o_) zwOo$fH8p6dtb{akp>&iYgctxgA>f&j<9Q6O#r14YB0^B4R>N#Ep}}Ybojtvd0Vt*b zfDm#UfZ#aj4TaD*HU{^~ig30mP%9MZtglC7S(%W$=nIOXPSOA{<91(-i3o)y8Vz2v zTJc;%LoPeE35-MnYeNIxIB)<><>f+?x^uvq+uWa;YMfeH8n-qy(Dhps(z(DJ3ZZvo z1io-MC;eK30WUN)L9I}Tna%~EmZGR=a>wN%^=D!Cjl zwzi^1rxQc`={$+V2U3aT43P3Fp;0J)B%$eB^UKR{`h2i9Hey#*l_10GrJ}K@2)D<_ zkzQx-^s-xJSq#q1L4^^uFFC|GK1 z(NR|?y8IK01R)rio5KT#0|`PPl}L!GwDic~_V(+kdRwx&VYB^VVsY`O>GE2G0f%?* z7W9TA2L5muy*67i8>J`;CWGNO$IRwmr|WLJotFj&FD!UGC)4Eytrp!D3!YUGG&(3Qy#Ypl*)*IwX+kY0-i?(CMT1hm1v5BzOZmuDV4r+ ztfS+u5I&-VdhghnnPb^Ao=~Ve6pbnsG8ta$?1WaG`JI?gB+zTK;jzmFjZzsYQmHQU zg#6-oXXmIG9(lQyE=L%rYLIfi!ChyDZ|tNFaXd1NB{@}a1lbL2d1W&U?lRG j<+x9d@7ve6)4Bf(;0}`0w&`@o00000NkvXXu0mjfDL{X| literal 0 HcmV?d00001 diff --git a/eazy-bookscanner-swing/src/main/resources/images/splash-screen-bookscan-638x320.png b/eazy-bookscanner-swing/src/main/resources/images/splash-screen-bookscan-638x320.png new file mode 100644 index 0000000000000000000000000000000000000000..ba253e2b7f7a9e68b1649dc3014c678acfdefe7e GIT binary patch literal 20863 zcmd3O1zVO~&@D>0bc0BDN=UtQN_QjO-6bszlG2^hEnU(j-QC>{XY+mM{D0l zW?vlW9i>Q;u5L)(nqOS9DVZJZt%|$*IkHfk*i6PbA4UJ`6Gd1~kF0;XK6I!o1luj_ zSJ4h62?#>=i)Y^Gm+=qD_t_&YmvpB?%4%xS+MdUCx*vq#NCRV>59?-i;|9uGZ!}NI zqInewPyhb!6MOD!ey}hU=QdEJf#8u)WP~U1`VT@JaQ~nDMWcnFa;1_Gws{D8@$pqV zJY4#fm)OmVpWdSt0)k|yYxh!+Gzk&{H`q^zGC+zk9<58+@ktGm zx$1tzZ2jlAiqExVBf~(iKV#CJHWI9nimY0QLD(1SL*Jwv<`fC@Fg2C$tI2?*$zY^d zyw~^X{PU^ZnvrSYYJKp=MjqVL5hG5;@$~&Y<{jFE4lZHf{I~N()z~Ch`8DzWFzPeJ zfa(37y(9WzY(((eicxJi>iGPgxwZ29eo)ZRA~{lkOd0n4{(k>Z|9=^}sNB&0Z<_?~ z|Gpi|jxYp196CTr2{-*$XG=HQDdoKZH;NJ>VzQ=sNAJ3U1UdRvUSaM>HVlgS`SFtJ zbDK|Z`-%<+?eiX7>tWagEI?ONBkt)=V1%(o#Mp>|mko-kho^yrw6KOOij<>6mICeO zGVfdb^x#4JoH{Zx=D2zhE*l!c&(`1+Z)dNwwYF0C4~sba@FTFYnP0Gh3sehQ-*wo| zScpEJF+Yr$RMHci?ubD5+2dwp{5`v3SB#gM!p6)h$bvwa4}QIa2cd~<+^u`xXJTr< zV$^lFq}`H=t_1dL#M_(8mNk3OOvKxs1sRemfciHk75MmbtHzEotEx3C-`8NoyZ7#1 z{Mv-XVtsqmw3ip->Y8Dg2oP@{>TKN&aG0&Q0s!*g5_wCQxuy z8?3}P^;ti?+d16PtE-M@pI_|NUqTimT^V(RcKhK_tQG=_upEm-K-x6?Ke z7SpQqAODy+lvXLuLU8luPwY+WI1HoIkwU1Tjh@}z%uiD6-Bgz-U{J~5 zScdq+mob!2l~jy{Fi`?Gug%z=>J)6y^?|yLpJ%pq4fVc`l=SJ@agB3u{pc*FY2?co$0rK* z{`|RUU~HG@vZ;V_BD(IUmdi;XX_m+;h=&y`+uOzZvfoHr($b>bJE1o&GEix30xo+W zm_FDL5cULh3btF%TF?6n1qjBw@H#%Q^YX85zZRA#H#)xhDBOI7(+Kg?>+6Rby}If0 z>RY~HtTlMX6qwvc`aUyj-x zOY6M3aG1iu>TTwR&-b)KqT=D1#rzO-F+5G|_@|j5DL918M!0AL3%jl*)1P_)o%0Bh zk2zeq=w15wX3jhcNUUhHf8d_}?(W#-wDJ`XmQoOq4C(4(d8_CU*=Ed&v0K+|D67q; zcy`V_JgtO=CPR7u=jHJfTu|^0{p#KM@q~6k`~dpSZ2}yr+NWB-m}~NV$aao6c!uX^ zc>AsuI588Gv!!2bjeoM={nE5iMO7(kv!- zvaE4c-`A8ITBEMfs6k%U^m%xL5D(R}GW&eYB2c;vnVr;VT;6T-P#`0b{qa~oN0876xD zPaomAx|!$nlmcjTSxk=iQj^!Nora8A374ylr}d@jHS6#nSM`!v4C^l5w-ctHT ~ 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 literal 0 HcmV?d00001