commit 9a63237f321bd1f5b11796dd4c28ace65ada7ce3 Author: 李建国 Date: Wed Feb 28 10:53:50 2024 +0800 1. init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a91c35d --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store +/.idea/ diff --git a/buildNumber.properties b/buildNumber.properties new file mode 100644 index 0000000..7f6d281 --- /dev/null +++ b/buildNumber.properties @@ -0,0 +1,3 @@ +#maven.buildNumber.plugin properties file +#Wed Feb 21 16:14:03 CST 2024 +buildNumber=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6e87b2b --- /dev/null +++ b/pom.xml @@ -0,0 +1,170 @@ + + + 4.0.0 + + org.aohe + twain-service + 0.1.1 + + + 8 + 8 + UTF-8 + + + + + org.java-websocket + Java-WebSocket + 1.5.3 + + + org.projectlombok + lombok + 1.18.30 + true + + + + cn.hutool + hutool-all + 5.8.25 + + + com.alibaba.fastjson2 + fastjson2 + 2.0.43 + + + + net.java.dev.jna + jna + 4.5.1 + + + net.java.dev.jna + jna-platform + 4.5.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4.1 + + + + jar-with-dependencies + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.0 + + UTF-8 + UTF-8 + UTF-8 + none + + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/aohe/Main.java b/src/main/java/org/aohe/Main.java new file mode 100644 index 0000000..4711236 --- /dev/null +++ b/src/main/java/org/aohe/Main.java @@ -0,0 +1,29 @@ +//package org.aohe; +// +//import lombok.extern.slf4j.Slf4j; +//import org.aohe.web.SocketServer; +// +//import java.io.BufferedReader; +//import java.io.IOException; +//import java.io.InputStreamReader; +// +//@Slf4j +//public class Main { +// public static void main(String[] args) throws IOException, InterruptedException { +// int port = 8997; // 843 flash policy port +// +// SocketServer s = new SocketServer(port); +// s.start(); +// System.out.println("ChatServer started on port: " + s.getPort()); +// +// BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in)); +// while (true) { +// String in = sysin.readLine(); +// s.broadcast(in); +// if (in.equals("exit")) { +// s.stop(1000); +// break; +// } +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/org/aohe/control/Operational.java b/src/main/java/org/aohe/control/Operational.java new file mode 100644 index 0000000..34a332e --- /dev/null +++ b/src/main/java/org/aohe/control/Operational.java @@ -0,0 +1,242 @@ +//package org.aohe.control; +// +//import cn.hutool.core.codec.Base64; +//import cn.hutool.core.lang.Console; +//import cn.hutool.log.Log; +//import cn.hutool.log.LogFactory; +//import cn.hutool.log.StaticLog; +//import com.alibaba.fastjson2.JSONObject; +//import org.aohe.core.twain.*; +//import org.aohe.exceptions.TwainException; +//import org.aohe.result.R; +//import org.aohe.scan.Source; +//import org.aohe.scan.SourceManager; +// +//import java.io.File; +//import java.util.*; +// +//public class Operational { +// +// private static final Log log = LogFactory.get(); +// +// private static TwainScanner scanner = null; +// +// public static String selectOperational(String path) { +// JSONObject json = JSONObject.parse(path); +// +// //操作符 +// String function = json.getString("function"); +// +// //参数符 +// JSONObject param = json.getJSONObject("params"); +// +// R r = R.ok(); +// try { +// if("001001".equals(function)){ +// //获取扫描仪列表 +// r = getDevices(); +// } else if ("001002".equals(function)) { +// //选择扫描仪 +// r = setScanner(param.getString("scannerId")); +// }else if ("001003".equals(function)){ +// //获取扫描仪操作符列表 +// r = getDeviceOperations(); +// }else if ("001004".equals(function)){ +// //r = setDeviceOperations(); +// }else if ("001007".equals(function)){ +// r = setDeviceOperations(param); +// }else if ("001008".equals(function)){ +// r = startScan(param.getString("scannerId")); +// }else if ("001012".equals(function)){ +// closeTwSource(); +// }else if ("001013".equals(function)){ +// closeTwSource(); +// }else if ("001015".equals(function)){ +// r = startScan(param.getString("scannerId"),true); +// }else if ("001016".equals(function)){ +// r = startScan(param.getString("scannerId"),true); +// } +// } catch (TwainException e) { +// StaticLog.error("获取驱动列表失败"); +// StaticLog.error(e); +// throw new RuntimeException(e); +// } catch (InterruptedException e) { +// StaticLog.error("选择驱动失败"); +// StaticLog.error(e); +// throw new RuntimeException(e); +// } +// +// return r.toJsonStr(); +// } +// +// /** +// * 001001 +// * 获取连接到当前终端的所有扫描仪并返回设备的SN号 +// * +// * @return R +// */ +// public static R getDevices () throws TwainException { +// return R.ok(TwainSource.getProductNamesToList()); +// } +// +// /** +// * 001002 +// * 选中某一获取到的扫描仪 +// * @return R -> success +// */ +// public static R setScanner(String name) throws TwainException, InterruptedException { +// if(name == null || name.isEmpty()){ +// return R.fail("扫描仪名字为空"); +// } +// +// TwainScanner.getScanner().select(name); +// Twain.getSourceManager().selectSource(name); +// +// return R.ok(); +// } +// +// public static void main(String[] args) throws TwainException { +// System.out.println(TwainScanner.getScanner().getDeviceNames()); +// } +// +// /** +// * 001003 +// * 获取当前选中扫描仪可配置的项 +// * @return +// */ +// public static R getDeviceOperations() throws TwainException { +// +// try{ +// TwainSource twainSource = openTwSource(); +// TwainCapability[] capabilities = twainSource.getCapabilities(); +// +// +// Map> map = new HashMap<>(); +// for (TwainCapability cap : capabilities){ +// List list = new ArrayList<>(); +// +// String key = Twain.getMapCapCodeToName().get(cap.cap); +// String formatKey = String.format("0x%04x", cap.cap); +// +// list.add(key); +// list.add(formatKey); +// +// map.put(key,list); +// } +// return R.ok(map); +// }finally { +// closeTwSource(); +// } +// +// +// +// +// +// } +// +// /** +// * 001004 +// * 设置或修改当前选中扫描仪某一配置项的能力值 +// * DPI --> double +// * 色彩模式 color 0,1,2 -> 黑白,灰度,彩色 +// * 进纸模式 paper true,false -> 自动,手动 +// * @param map 参数和值 +// * @return R +// */ +// public static R setDeviceOperations(JSONObject map){ +// try { +// TwainSource twainSource = Twain.getSourceManager().getSource(); +// // 先约定为三种参数 DPI,色彩模式,进纸模式 +// if(map.get("dpi") !=null){ +// twainSource.setResolution(map.getDouble("dpi")); +// } +// if(map.get("color") !=null){ +// twainSource.setCapability(Twain.ICAP_PIXELTYPE, map.getInteger("color")); +// } +// if(map.get("paper") !=null){ +// twainSource.setCapability(Twain.CAP_FEEDERENABLED, map.getBooleanValue("paper")); +// } +// } catch (TwainException e) { +// throw new RuntimeException(e); +// } +// return R.ok(); +// } +// +// /** +// * 001008 +// * 当前扫描仪启动扫描 +// * @param name 扫描仪名称 +// * @return R +// * @throws TwainException default error +// */ +// public static R startScan(String name) throws TwainException { +// return startScan(name, false); +// } +// +// /** +// * 001008 +// * 当前扫描仪启动扫描 +// * @param name 扫描仪名称 +// * @param systemUI 是否使用打印机自带UI +// * @return R +// * @throws TwainException default error +// */ +// public static R startScan(String name, boolean systemUI ) throws TwainException { +// Source source = new Source(); +// source.setName(name); +// source.setSystemUI(systemUI); +// List fileList = source.scan(); +// List base64Files = new ArrayList<>(); +// for (File file : fileList){ +// base64Files.add(Base64.encode(file)); +// } +// return R.ok(base64Files); +// } +// +//// public static void main(String[] args) throws TwainException, InterruptedException { +//// List list = (List) getDevices().getData(); +//// System.out.println(list.get(0)); +//// R r = setScanner(list.get(0)); +//// //System.out.println(getDeviceOperations()); +//// System.out.println(startScan(list.get(0), false)); +//// ; +//// } +// +// +// /** +// * 打开接口 +// * @return twSource +// * @throws TwainException 默认错误 +// */ +// public static TwainSource openTwSource() throws TwainException { +// TwainSource twainSource = Twain.getSourceManager().getSource(); +// +// if(twainSource.getState() != 4){ +// //打开接口 +// Twain.getSourceManager().openSource(); +// } +// return twainSource; +// } +// +// /** +// * 关闭接口 +// * @throws TwainException 默认错误 +// */ +// public static void closeTwSource() throws TwainException { +// TwainSource twainSource = Twain.getSourceManager().getSource(); +// twainSource.close(); +// } +// +// public void getSetting(Integer i) throws TwainException { +// +// try{ +// TwainSource twainSource = openTwSource(); +// TwainCapability tc = twainSource.getCapability(i); +// Console.log(tc.getItems()); +// } catch (TwainException e) { +// throw new RuntimeException(e); +// } finally { +// closeTwSource(); +// } +// } +//} diff --git a/src/main/java/org/aohe/core/twain/Twain.java b/src/main/java/org/aohe/core/twain/Twain.java new file mode 100644 index 0000000..bc81aeb --- /dev/null +++ b/src/main/java/org/aohe/core/twain/Twain.java @@ -0,0 +1,1392 @@ +package org.aohe.core.twain; + +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.*; +import org.aohe.exceptions.TwainException; +import org.aohe.libs.Win32Twain; +import org.aohe.libs.Win32Twain.TW_IDENTITY; +import org.aohe.libs.Kernel32; +import com.sun.jna.platform.win32.User32; +import org.aohe.transfer.TwainMemoryTransfer; +import org.aohe.variable.TwainContainer; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +/** + * + * @author lucifer + */ +public class Twain { + + // Based on http://www.twain.org/wp-content/uploads/2017/04/TWAIN.H.h + public static final String[] ImageFileFormatExts = { + ".tiff", ".pict", ".bmp", ".xbm", ".jpeg", ".fpx", ".tiff", ".png", ".spiff", ".exif" + }; + static public final int STATE_UNDEFINED = 0; + static public final int STATE_PRESESSION = 1; + static public final int STATE_SRCMNGLOADED = 2; + static public final int STATE_SRCMNGOPEN = 3; + static public final int STATE_SRCOPEN = 4; + static public final int STATE_SRCENABLED = 5; + static public final int STATE_TRANSFERREADY = 6; + static public final int STATE_TRANSFERRING = 7; + + public static final short MSG_NULL = 0; + public static final short MSG_GET = 0x0001; + public static final short MSG_GETCURRENT = 0x0002; + public static final short MSG_GETDEFAULT = 0x0003; + public static final short MSG_GETFIRST = 0x0004; + public static final short MSG_GETNEXT = 0x0005; + public static final short MSG_SET = 0x0006; + public static final short MSG_RESET = 0x0007; + public static final short MSG_QUERYSUPPORT = 0x0008; + public static final short MSG_XFERREADY = 0x0101; + public static final short MSG_CLOSEDSREQ = 0x0102; + public static final short MSG_CLOSEDSOK = 0x0103; + public static final short MSG_DEVICEEVENT = 0x0104; + public static final short MSG_OPENDSM = 0x0301; + public static final short MSG_CLOSEDSM = 0x0302; + public static final short MSG_OPENDS = 0x0401; + public static final short MSG_CLOSEDS = 0x0402; + public static final short MSG_USERSELECT = 0x0403; + public static final short MSG_DISABLEDS = 0x0501; + public static final short MSG_ENABLEDS = 0x0502; + public static final short MSG_ENABLEDSUIONLY = 0x0503; + public static final short MSG_PROCESSEVENT = 0x0601; + public static final short MSG_ENDXFER = 0x0701; + public static final short MSG_CHANGEDIRECTORY = 0x0801; + public static final short MSG_CREATEDIRECTORY = 0x0802; + public static final short MSG_DELETE = 0x0803; + public static final short MSG_FORMATMEDIA = 0x0804; + public static final short MSG_GETCLOSE = 0x0805; + public static final short MSG_GETFIRSTFILE = 0x0806; + public static final short MSG_GETINFO = 0x0807; + public static final short MSG_GETNEXTFILE = 0x0808; + public static final short MSG_RENAME = 0x0809; + public static final short MSG_COPY = 0x080A; + public static final short MSG_AUTOMATICCAPTUREDIRECTORY = 0x080B; + public static final short MSG_CUSTOMBASE = (short) 0x8000; + + public static final short DAT_NULL = 0x0000; + public static final short DAT_CAPABILITY = 0x0001; + public static final short DAT_EVENT = 0x0002; + public static final short DAT_IDENTITY = 0x0003; + public static final short DAT_PARENT = 0x0004; + public static final short DAT_PENDINGXFERS = 0x0005; + public static final short DAT_SETUPMEMXFER = 0x0006; + public static final short DAT_SETUPFILEXFER = 0x0007; + public static final short DAT_STATUS = 0x0008; + public static final short DAT_USERINTERFACE = 0x0009; + public static final short DAT_XFERGROUP = 0x000a; + public static final short DAT_TWUNKIDENTITY = 0x000b; + public static final short DAT_CUSTOMDSDATA = 0x000c; + public static final short DAT_DEVICEEVENT = 0x000d; + public static final short DAT_FILESYSTEM = 0x000e; + public static final short DAT_PASSTHRU = 0x000f; + public static final short DAT_IMAGEINFO = 0x0101; + public static final short DAT_IMAGELAYOUT = 0x0102; + public static final short DAT_IMAGEMEMXFER = 0x0103; + public static final short DAT_IMAGENATIVEXFER = 0x0104; + public static final short DAT_IMAGEFILEXFER = 0x0105; + public static final short DAT_CIECOLOR = 0x0106; + public static final short DAT_GRAYRESPONSE = 0x0107; + public static final short DAT_RGBRESPONSE = 0x0108; + public static final short DAT_JPEGCOMPRESSION = 0x0109; + public static final short DAT_PALETTE8 = 0x010a; + public static final short DAT_EXTIMAGEINFO = 0x010b; + + public static final short TWCP_NONE = 0; + public static final short TWCP_PACKBITS = 1; + public static final short TWCP_GROUP31D = 2; + public static final short TWCP_GROUP31DEOL = 3; + public static final short TWCP_GROUP32D = 4; + public static final short TWCP_GROUP4 = 5; + public static final short TWCP_JPEG = 6; + public static final short TWCP_LZW = 7; + public static final short TWCP_JBIG = 8; + public static final short TWCP_PNG = 9; + public static final short TWCP_RLE4 = 10; + public static final short TWCP_RLE8 = 11; + public static final short TWCP_BITFIELDS = 12; + + public static final short DG_CONTROL = 1; + public static final short DG_IMAGE = 2; + public static final short DG_AUDIO = 4; + + public static final short TWRC_SUCCESS = 0; + public static final short TWRC_FAILURE = 1; + public static final short TWRC_CHECKSTATUS = 2; + public static final short TWRC_CANCEL = 3; + public static final short TWRC_DSEVENT = 4; + public static final short TWRC_NOTDSEVENT = 5; + public static final short TWRC_XFERDONE = 6; + public static final short TWRC_ENDOFLIST = 7; + public static final short TWRC_INFONOTSUPPORTED = 8; + public static final short TWRC_DATANOTAVAILABLE = 9; + + public static final short TWMF_APPOWNS = 0x0001; + public static final short TWMF_DSMOWNS = 0x0002; + public static final short TWMF_DSOWNS = 0x0004; + public static final short TWMF_POINTER = 0x0008; + public static final short TWMF_HANDLE = 0x0010; + + public static final int TWON_ARRAY = 3; + public static final int TWON_ENUMERATION = 4; + public static final int TWON_ONEVALUE = 5; + public static final int TWON_RANGE = 6; + + public static final int TWTY_INT8 = 0x0000; + public static final int TWTY_INT16 = 0x0001; + public static final int TWTY_INT32 = 0x0002; + + public static final int TWTY_UINT8 = 0x0003; + public static final int TWTY_UINT16 = 0x0004; + public static final int TWTY_UINT32 = 0x0005; + + public static final int TWTY_BOOL = 0x0006; + + public static final int TWTY_FIX32 = 0x0007; + + public static final int TWTY_FRAME = 0x0008; + + public static final int TWTY_STR32 = 0x0009; + public static final int TWTY_STR64 = 0x000a; + public static final int TWTY_STR128 = 0x000b; + public static final int TWTY_STR255 = 0x000c; + public static final int TWTY_STR1024 = 0x000d; + public static final int TWTY_UNI512 = 0x000e; + + public static final int CAP_CUSTOMBASE = 0x8000; + + public static final int CAP_XFERCOUNT = 0x0001; + + public static final int ICAP_COMPRESSION = 0x0100; + + /** 色彩模式 */ + public static final int ICAP_PIXELTYPE = 0x0101; + public static final int ICAP_UNITS = 0x0102; + public static final int ICAP_XFERMECH = 0x0103; + + public static final int CAP_AUTHOR = 0x01000; + public static final int CAP_CAPTION = 0x01001; + + /** 自动禁止模式 */ + public static final int CAP_FEEDERENABLED = 0x01002; + public static final int CAP_FEEDERLOADED = 0x01003; + public static final int CAP_TIMEDATE = 0x01004; + public static final int CAP_SUPPORTEDCAPS = 0x01005; + public static final int CAP_EXTENDEDCAPS = 0x01006; + public static final int CAP_AUTOFEED = 0x01007; + public static final int CAP_CLEARPAGE = 0x01008; + public static final int CAP_FEEDPAGE = 0x01009; + public static final int CAP_REWINDPAGE = 0x0100a; + public static final int CAP_INDICATORS = 0x0100b; + public static final int CAP_SUPPORTEDCAPSEXT = 0x0100c; + public static final int CAP_PAPERDETECTABLE = 0x0100d; + public static final int CAP_UICONTROLLABLE = 0x0100e; + public static final int CAP_DEVICEONLINE = 0x0100f; + public static final int CAP_AUTOSCAN = 0x01010; + public static final int CAP_THUMBNAILSENABLED = 0x01011; + public static final int CAP_DUPLEX = 0x01012; + public static final int CAP_DUPLEXENABLED = 0x01013; + public static final int CAP_ENABLEDSUIONLY = 0x01014; + public static final int CAP_CUSTOMDSDATA = 0x01015; + public static final int CAP_ENDORSER = 0x01016; + public static final int CAP_JOBCONTROL = 0x01017; + public static final int CAP_ALARMS = 0x01018; + public static final int CAP_ALARMVOLUME = 0x01019; + public static final int CAP_AUTOMATICCAPTURE = 0x0101a; + public static final int CAP_TIMEBEFOREFIRSTCAPTURE = 0x0101b; + public static final int CAP_TIMEBETWEENCAPTURES = 0x0101c; + public static final int CAP_CLEARBUFFERS = 0x0101d; + public static final int CAP_MAXBATCHBUFFERS = 0x0101e; + public static final int CAP_DEVICETIMEDATE = 0x0101f; + public static final int CAP_POWERSUPPLY = 0x01020; + public static final int CAP_CAMERAPREVIEWUI = 0x01021; + public static final int CAP_DEVICEEVENT = 0x01022; + public static final int CAP_PAGEMULTIPLEACQUIRE = 0x01023; + public static final int CAP_SERIALNUMBER = 0x01024; + public static final int CAP_FILESYSTEM = 0x01025; + public static final int CAP_PRINTER = 0x01026; + public static final int CAP_PRINTERENABLED = 0x01027; + public static final int CAP_PRINTERINDEX = 0x01028; + public static final int CAP_PRINTERMODE = 0x01029; + public static final int CAP_PRINTERSTRING = 0x0102a; + public static final int CAP_PRINTERSUFFIX = 0x0102b; + public static final int CAP_LANGUAGE = 0x0102c; + public static final int CAP_FEEDERALIGNMENT = 0x0102d; + public static final int CAP_FEEDERORDER = 0x0102e; + public static final int CAP_PAPERBINDING = 0x0102f; + public static final int CAP_REACQUIREALLOWED = 0x01030; + public static final int CAP_PASSTHRU = 0x01031; + public static final int CAP_BATTERYMINUTES = 0x01032; + public static final int CAP_BATTERYPERCENTAGE = 0x01033; + public static final int CAP_POWERDOWNTIME = 0x01034; + + public static final int ICAP_AUTOBRIGHT = 0x01100; + public static final int ICAP_BRIGHTNESS = 0x01101; + public static final int ICAP_CONTRAST = 0x01103; + public static final int ICAP_CUSTHALFTONE = 0x01104; + public static final int ICAP_EXPOSURETIME = 0x01105; + public static final int ICAP_FILTER = 0x01106; + public static final int ICAP_FLASHUSED = 0x01107; + public static final int ICAP_GAMMA = 0x01108; + public static final int ICAP_HALFTONES = 0x01109; + public static final int ICAP_HIGHLIGHT = 0x0110a; + public static final int ICAP_IMAGEFILEFORMAT = 0x0110c; + public static final int ICAP_LAMPSTATE = 0x0110d; + public static final int ICAP_LIGHTSOURCE = 0x0110e; + public static final int ICAP_ORIENTATION = 0x01110; + public static final int ICAP_PHYSICALWIDTH = 0x01111; + public static final int ICAP_PHYSICALHEIGHT = 0x01112; + public static final int ICAP_SHADOW = 0x01113; + public static final int ICAP_FRAMES = 0x01114; + public static final int ICAP_XNATIVERESOLUTION = 0x01116; + public static final int ICAP_YNATIVERESOLUTION = 0x01117; + + /** DPI */ + public static final int ICAP_XRESOLUTION = 0x01118; + public static final int ICAP_YRESOLUTION = 0x01119; + public static final int ICAP_MAXFRAMES = 0x0111a; + public static final int ICAP_TILES = 0x0111b; + public static final int ICAP_BITORDER = 0x0111c; + public static final int ICAP_CCITTKFACTOR = 0x0111d; + public static final int ICAP_LIGHTPATH = 0x0111e; + public static final int ICAP_PIXELFLAVOR = 0x0111f; + public static final int ICAP_PLANARCHUNKY = 0x01120; + public static final int ICAP_ROTATION = 0x01121; + public static final int ICAP_SUPPORTEDSIZES = 0x01122; + public static final int ICAP_THRESHOLD = 0x01123; + public static final int ICAP_XSCALING = 0x01124; + public static final int ICAP_YSCALING = 0x01125; + public static final int ICAP_BITORDERCODES = 0x01126; + public static final int ICAP_PIXELFLAVORCODES = 0x01127; + public static final int ICAP_JPEGPIXELTYPE = 0x01128; + public static final int ICAP_TIMEFILL = 0x0112a; + public static final int ICAP_BITDEPTH = 0x0112b; + public static final int ICAP_BITDEPTHREDUCTION = 0x0112c; + public static final int ICAP_UNDEFINEDIMAGESIZE = 0x0112d; + public static final int ICAP_IMAGEDATASET = 0x0112e; + public static final int ICAP_EXTIMAGEINFO = 0x0112f; + public static final int ICAP_MINIMUMHEIGHT = 0x01130; + public static final int ICAP_MINIMUMWIDTH = 0x01131; + public static final int ICAP_AUTODISCARDBLANKPAGES = 0x01134; + public static final int ICAP_FLIPROTATION = 0x01136; + public static final int ICAP_BARCODEDETECTIONENABLED = 0x01137; + public static final int ICAP_SUPPORTEDBARCODETYPES = 0x01138; + public static final int ICAP_BARCODEMAXSEARCHPRIORITIES = 0x01139; + public static final int ICAP_BARCODESEARCHPRIORITIES = 0x0113a; + public static final int ICAP_BARCODESEARCHMODE = 0x0113b; + public static final int ICAP_BARCODEMAXRETRIES = 0x0113c; + public static final int ICAP_BARCODETIMEOUT = 0x0113d; + public static final int ICAP_ZOOMFACTOR = 0x0113e; + public static final int ICAP_PATCHCODEDETECTIONENABLED = 0x0113f; + public static final int ICAP_SUPPORTEDPATCHCODETYPES = 0x01140; + public static final int ICAP_PATCHCODEMAXSEARCHPRIORITIES = 0x01141; + public static final int ICAP_PATCHCODESEARCHPRIORITIES = 0x01142; + public static final int ICAP_PATCHCODESEARCHMODE = 0x01143; + public static final int ICAP_PATCHCODEMAXRETRIES = 0x01144; + public static final int ICAP_PATCHCODETIMEOUT = 0x01145; + public static final int ICAP_FLASHUSED2 = 0x01146; + public static final int ICAP_IMAGEFILTER = 0x01147; + public static final int ICAP_NOISEFILTER = 0x01148; + public static final int ICAP_OVERSCAN = 0x01149; + public static final int ICAP_AUTOMATICBORDERDETECTION = 0x01150; + public static final int ICAP_AUTOMATICDESKEW = 0x01151; + public static final int ICAP_AUTOMATICROTATE = 0x01152; + + public static final int TWBO_LSBFIRST = 0; + public static final int TWBO_MSBFIRST = 1; + + public static final int TWFF_TIFF = 0; + public static final int TWFF_PICT = 1; + public static final int TWFF_BMP = 2; + public static final int TWFF_XBM = 3; + public static final int TWFF_JFIF = 4; + public static final int TWFF_FPX = 5; + public static final int TWFF_TIFFMULTI = 6; + public static final int TWFF_PNG = 7; + public static final int TWFF_SPIFF = 8; + public static final int TWFF_EXIF = 9; + + public static final int TWUN_INCHES = 0; + public static final int TWUN_CENTIMETERS = 1; + public static final int TWUN_PICAS = 2; + public static final int TWUN_POINTS = 3; + public static final int TWUN_TWIPS = 4; + public static final int TWUN_PIXELS = 5; + + public static final int TWSX_NATIVE = 0; + public static final int TWSX_FILE = 1; + public static final int TWSX_MEMORY = 2; + public static final int TWSX_FILE2 = 3; + + public static final int HWND_DESKTOP = 0x10014; + public static final int WS_POPUPWINDOW = 0x80000000 | 0x00800000 | 0x00080000; + public static final int CW_USEDEFAULT = 0x80000000; + public static final int HWND_TOPMOST = -1; + public static final int SWP_NOSIZE = 1; + + protected static Kernel32 kernel32; +// protected static User32 user32; + protected static Win32Twain twain; + protected static String libraryName; + + static TW_IDENTITY g_AppID; + private static TW_IDENTITY c_AppID; + static WinDef.HWND hwnd; + private static WeakReference scanner; + static TwainSourceManager sourceManager; + private static Map mapCapCodeToName; + private static Map mapCapNameToCode; + + public static Map getMapCapNameToCode() { + if (mapCapNameToCode != null) { + return mapCapNameToCode; + } + + Map map = new HashMap<>(); + map.put("CAP_CUSTOMBASE", 0x8000); + /* Base of custom capabilities */ + + /* all data sources are REQUIRED to support these caps */ + map.put("CAP_XFERCOUNT", 0x0001); + + /* image data sources are REQUIRED to support these caps */ + map.put("ICAP_COMPRESSION", 0x0100); + map.put("ICAP_PIXELTYPE", 0x0101); + map.put("ICAP_UNITS", 0x0102); + map.put("ICAP_XFERMECH", 0x0103); + + /* all data sources MAY support these caps */ + map.put("CAP_AUTHOR", 0x1000); + map.put("CAP_CAPTION", 0x1001); + map.put("CAP_FEEDERENABLED", 0x1002); + map.put("CAP_FEEDERLOADED", 0x1003); + map.put("CAP_TIMEDATE", 0x1004); + map.put("CAP_SUPPORTEDCAPS", 0x1005); + map.put("CAP_EXTENDEDCAPS", 0x1006); + map.put("CAP_AUTOFEED", 0x1007); + map.put("CAP_CLEARPAGE", 0x1008); + map.put("CAP_FEEDPAGE", 0x1009); + map.put("CAP_REWINDPAGE", 0x100a); + map.put("CAP_INDICATORS", 0x100b); + map.put("CAP_PAPERDETECTABLE", 0x100d); + map.put("CAP_UICONTROLLABLE", 0x100e); + map.put("CAP_DEVICEONLINE", 0x100f); + map.put("CAP_AUTOSCAN", 0x1010); + map.put("CAP_THUMBNAILSENABLED", 0x1011); + map.put("CAP_DUPLEX", 0x1012); + map.put("CAP_DUPLEXENABLED", 0x1013); + map.put("CAP_ENABLEDSUIONLY", 0x1014); + map.put("CAP_CUSTOMDSDATA", 0x1015); + map.put("CAP_ENDORSER", 0x1016); + map.put("CAP_JOBCONTROL", 0x1017); + map.put("CAP_ALARMS", 0x1018); + map.put("CAP_ALARMVOLUME", 0x1019); + map.put("CAP_AUTOMATICCAPTURE", 0x101a); + map.put("CAP_TIMEBEFOREFIRSTCAPTURE", 0x101b); + map.put("CAP_TIMEBETWEENCAPTURES", 0x101c); + map.put("CAP_CLEARBUFFERS", 0x101d); + map.put("CAP_MAXBATCHBUFFERS", 0x101e); + map.put("CAP_DEVICETIMEDATE", 0x101f); + map.put("CAP_POWERSUPPLY", 0x1020); + map.put("CAP_CAMERAPREVIEWUI", 0x1021); + map.put("CAP_DEVICEEVENT", 0x1022); + map.put("CAP_SERIALNUMBER", 0x1024); + map.put("CAP_PRINTER", 0x1026); + map.put("CAP_PRINTERENABLED", 0x1027); + map.put("CAP_PRINTERINDEX", 0x1028); + map.put("CAP_PRINTERMODE", 0x1029); + map.put("CAP_PRINTERSTRING", 0x102a); + map.put("CAP_PRINTERSUFFIX", 0x102b); + map.put("CAP_LANGUAGE", 0x102c); + map.put("CAP_FEEDERALIGNMENT", 0x102d); + map.put("CAP_FEEDERORDER", 0x102e); + map.put("CAP_REACQUIREALLOWED", 0x1030); + map.put("CAP_BATTERYMINUTES", 0x1032); + map.put("CAP_BATTERYPERCENTAGE", 0x1033); + map.put("CAP_CAMERASIDE", 0x1034); + map.put("CAP_SEGMENTED", 0x1035); + map.put("CAP_CAMERAENABLED", 0x1036); + map.put("CAP_CAMERAORDER", 0x1037); + map.put("CAP_MICRENABLED", 0x1038); + map.put("CAP_FEEDERPREP", 0x1039); + map.put("CAP_FEEDERPOCKET", 0x103a); + map.put("CAP_AUTOMATICSENSEMEDIUM", 0x103b); + map.put("CAP_CUSTOMINTERFACEGUID", 0x103c); + map.put("CAP_SUPPORTEDCAPSSEGMENTUNIQUE", 0x103d); + map.put("CAP_SUPPORTEDDATS", 0x103e); + map.put("CAP_DOUBLEFEEDDETECTION", 0x103f); + map.put("CAP_DOUBLEFEEDDETECTIONLENGTH", 0x1040); + map.put("CAP_DOUBLEFEEDDETECTIONSENSITIVITY", 0x1041); + map.put("CAP_DOUBLEFEEDDETECTIONRESPONSE", 0x1042); + map.put("CAP_PAPERHANDLING", 0x1043); + map.put("CAP_INDICATORSMODE", 0x1044); + map.put("CAP_PRINTERVERTICALOFFSET", 0x1045); + map.put("CAP_POWERSAVETIME", 0x1046); + map.put("CAP_PRINTERCHARROTATION", 0x1047); + map.put("CAP_PRINTERFONTSTYLE", 0x1048); + map.put("CAP_PRINTERINDEXLEADCHAR", 0x1049); + map.put("CAP_PRINTERINDEXMAXVALUE", 0x104A); + map.put("CAP_PRINTERINDEXNUMDIGITS", 0x104B); + map.put("CAP_PRINTERINDEXSTEP", 0x104C); + map.put("CAP_PRINTERINDEXTRIGGER", 0x104D); + map.put("CAP_PRINTERSTRINGPREVIEW", 0x104E); + + /* image data sources MAY support these caps */ + map.put("ICAP_AUTOBRIGHT", 0x1100); + map.put("ICAP_BRIGHTNESS", 0x1101); + map.put("ICAP_CONTRAST", 0x1103); + map.put("ICAP_CUSTHALFTONE", 0x1104); + map.put("ICAP_EXPOSURETIME", 0x1105); + map.put("ICAP_FILTER", 0x1106); + map.put("ICAP_FLASHUSED", 0x1107); + map.put("ICAP_GAMMA", 0x1108); + map.put("ICAP_HALFTONES", 0x1109); + map.put("ICAP_HIGHLIGHT", 0x110a); + map.put("ICAP_IMAGEFILEFORMAT", 0x110c); + map.put("ICAP_LAMPSTATE", 0x110d); + map.put("ICAP_LIGHTSOURCE", 0x110e); + map.put("ICAP_ORIENTATION", 0x1110); + map.put("ICAP_PHYSICALWIDTH", 0x1111); + map.put("ICAP_PHYSICALHEIGHT", 0x1112); + map.put("ICAP_SHADOW", 0x1113); + map.put("ICAP_FRAMES", 0x1114); + map.put("ICAP_XNATIVERESOLUTION", 0x1116); + map.put("ICAP_YNATIVERESOLUTION", 0x1117); + map.put("ICAP_XRESOLUTION", 0x1118); + map.put("ICAP_YRESOLUTION", 0x1119); + map.put("ICAP_MAXFRAMES", 0x111a); + map.put("ICAP_TILES", 0x111b); + map.put("ICAP_BITORDER", 0x111c); + map.put("ICAP_CCITTKFACTOR", 0x111d); + map.put("ICAP_LIGHTPATH", 0x111e); + map.put("ICAP_PIXELFLAVOR", 0x111f); + map.put("ICAP_PLANARCHUNKY", 0x1120); + map.put("ICAP_ROTATION", 0x1121); + map.put("ICAP_SUPPORTEDSIZES", 0x1122); + map.put("ICAP_THRESHOLD", 0x1123); + map.put("ICAP_XSCALING", 0x1124); + map.put("ICAP_YSCALING", 0x1125); + map.put("ICAP_BITORDERCODES", 0x1126); + map.put("ICAP_PIXELFLAVORCODES", 0x1127); + map.put("ICAP_JPEGPIXELTYPE", 0x1128); + map.put("ICAP_TIMEFILL", 0x112a); + map.put("ICAP_BITDEPTH", 0x112b); + map.put("ICAP_BITDEPTHREDUCTION", 0x112c); + map.put("ICAP_UNDEFINEDIMAGESIZE", 0x112d); + map.put("ICAP_IMAGEDATASET", 0x112e); + map.put("ICAP_EXTIMAGEINFO", 0x112f); + map.put("ICAP_MINIMUMHEIGHT", 0x1130); + map.put("ICAP_MINIMUMWIDTH", 0x1131); + map.put("ICAP_AUTODISCARDBLANKPAGES", 0x1134); + map.put("ICAP_FLIPROTATION", 0x1136); + map.put("ICAP_BARCODEDETECTIONENABLED", 0x1137); + map.put("ICAP_SUPPORTEDBARCODETYPES", 0x1138); + map.put("ICAP_BARCODEMAXSEARCHPRIORITIES", 0x1139); + map.put("ICAP_BARCODESEARCHPRIORITIES", 0x113a); + map.put("ICAP_BARCODESEARCHMODE", 0x113b); + map.put("ICAP_BARCODEMAXRETRIES", 0x113c); + map.put("ICAP_BARCODETIMEOUT", 0x113d); + map.put("ICAP_ZOOMFACTOR", 0x113e); + map.put("ICAP_PATCHCODEDETECTIONENABLED", 0x113f); + map.put("ICAP_SUPPORTEDPATCHCODETYPES", 0x1140); + map.put("ICAP_PATCHCODEMAXSEARCHPRIORITIES", 0x1141); + map.put("ICAP_PATCHCODESEARCHPRIORITIES", 0x1142); + map.put("ICAP_PATCHCODESEARCHMODE", 0x1143); + map.put("ICAP_PATCHCODEMAXRETRIES", 0x1144); + map.put("ICAP_PATCHCODETIMEOUT", 0x1145); + map.put("ICAP_FLASHUSED2", 0x1146); + map.put("ICAP_IMAGEFILTER", 0x1147); + map.put("ICAP_NOISEFILTER", 0x1148); + map.put("ICAP_OVERSCAN", 0x1149); + map.put("ICAP_AUTOMATICBORDERDETECTION", 0x1150); + map.put("ICAP_AUTOMATICDESKEW", 0x1151); + map.put("ICAP_AUTOMATICROTATE", 0x1152); + map.put("ICAP_JPEGQUALITY", 0x1153); + map.put("ICAP_FEEDERTYPE", 0x1154); + map.put("ICAP_ICCPROFILE", 0x1155); + map.put("ICAP_AUTOSIZE", 0x1156); + map.put("ICAP_AUTOMATICCROPUSESFRAME", 0x1157); + map.put("ICAP_AUTOMATICLENGTHDETECTION", 0x1158); + map.put("ICAP_AUTOMATICCOLORENABLED", 0x1159); + map.put("ICAP_AUTOMATICCOLORNONCOLORPIXELTYPE", 0x115a); + map.put("ICAP_COLORMANAGEMENTENABLED", 0x115b); + map.put("ICAP_IMAGEMERGE", 0x115c); + map.put("ICAP_IMAGEMERGEHEIGHTTHRESHOLD", 0x115d); + map.put("ICAP_SUPPORTEDEXTIMAGEINFO", 0x115e); + map.put("ICAP_FILMTYPE", 0x115f); + map.put("ICAP_MIRROR", 0x1160); + map.put("ICAP_JPEGSUBSAMPLING", 0x1161); + + map.put("CAP_SUPPORTEDCAPSEXT", 0x100c); + map.put("CAP_PAGEMULTIPLEACQUIRE", 0x1023); + map.put("CAP_PAPERBINDING", 0x102f); + map.put("CAP_PASSTHRU", 0x1031); + map.put("CAP_POWERDOWNTIME", 0x1034); + + mapCapNameToCode = map; + return mapCapNameToCode; + } + + public static Map getMapCapCodeToName() { + if (mapCapCodeToName != null) { + return mapCapCodeToName; + } + + Map map = new HashMap<>(); + map.put(0x8000, "CAP_CUSTOMBASE"); + /* Base of custom capabilities */ + + /* all data sources are REQUIRED to support these caps */ + map.put(0x0001, "CAP_XFERCOUNT"); + + /* image data sources are REQUIRED to support these caps */ + map.put(0x0100, "ICAP_COMPRESSION"); + map.put(0x0101, "ICAP_PIXELTYPE"); + map.put(0x0102, "ICAP_UNITS"); + map.put(0x0103, "ICAP_XFERMECH"); + + /* all data sources MAY support these caps */ + map.put(0x1000, "CAP_AUTHOR"); + map.put(0x1001, "CAP_CAPTION"); + map.put(0x1002, "CAP_FEEDERENABLED"); + map.put(0x1003, "CAP_FEEDERLOADED"); + map.put(0x1004, "CAP_TIMEDATE"); + map.put(0x1005, "CAP_SUPPORTEDCAPS"); + map.put(0x1006, "CAP_EXTENDEDCAPS"); + map.put(0x1007, "CAP_AUTOFEED"); + map.put(0x1008, "CAP_CLEARPAGE"); + map.put(0x1009, "CAP_FEEDPAGE"); + map.put(0x100a, "CAP_REWINDPAGE"); + map.put(0x100b, "CAP_INDICATORS"); + map.put(0x100d, "CAP_PAPERDETECTABLE"); + map.put(0x100e, "CAP_UICONTROLLABLE"); + map.put(0x100f, "CAP_DEVICEONLINE"); + map.put(0x1010, "CAP_AUTOSCAN"); + map.put(0x1011, "CAP_THUMBNAILSENABLED"); + map.put(0x1012, "CAP_DUPLEX"); + map.put(0x1013, "CAP_DUPLEXENABLED"); + map.put(0x1014, "CAP_ENABLEDSUIONLY"); + map.put(0x1015, "CAP_CUSTOMDSDATA"); + map.put(0x1016, "CAP_ENDORSER"); + map.put(0x1017, "CAP_JOBCONTROL"); + map.put(0x1018, "CAP_ALARMS"); + map.put(0x1019, "CAP_ALARMVOLUME"); + map.put(0x101a, "CAP_AUTOMATICCAPTURE"); + map.put(0x101b, "CAP_TIMEBEFOREFIRSTCAPTURE"); + map.put(0x101c, "CAP_TIMEBETWEENCAPTURES"); + map.put(0x101d, "CAP_CLEARBUFFERS"); + map.put(0x101e, "CAP_MAXBATCHBUFFERS"); + map.put(0x101f, "CAP_DEVICETIMEDATE"); + map.put(0x1020, "CAP_POWERSUPPLY"); + map.put(0x1021, "CAP_CAMERAPREVIEWUI"); + map.put(0x1022, "CAP_DEVICEEVENT"); + map.put(0x1024, "CAP_SERIALNUMBER"); + map.put(0x1026, "CAP_PRINTER"); + map.put(0x1027, "CAP_PRINTERENABLED"); + map.put(0x1028, "CAP_PRINTERINDEX"); + map.put(0x1029, "CAP_PRINTERMODE"); + map.put(0x102a, "CAP_PRINTERSTRING"); + map.put(0x102b, "CAP_PRINTERSUFFIX"); + map.put(0x102c, "CAP_LANGUAGE"); + map.put(0x102d, "CAP_FEEDERALIGNMENT"); + map.put(0x102e, "CAP_FEEDERORDER"); + map.put(0x1030, "CAP_REACQUIREALLOWED"); + map.put(0x1032, "CAP_BATTERYMINUTES"); + map.put(0x1033, "CAP_BATTERYPERCENTAGE"); + map.put(0x1034, "CAP_CAMERASIDE"); + map.put(0x1035, "CAP_SEGMENTED"); + map.put(0x1036, "CAP_CAMERAENABLED"); + map.put(0x1037, "CAP_CAMERAORDER"); + map.put(0x1038, "CAP_MICRENABLED"); + map.put(0x1039, "CAP_FEEDERPREP"); + map.put(0x103a, "CAP_FEEDERPOCKET"); + map.put(0x103b, "CAP_AUTOMATICSENSEMEDIUM"); + map.put(0x103c, "CAP_CUSTOMINTERFACEGUID"); + map.put(0x103d, "CAP_SUPPORTEDCAPSSEGMENTUNIQUE"); + map.put(0x103e, "CAP_SUPPORTEDDATS"); + map.put(0x103f, "CAP_DOUBLEFEEDDETECTION"); + map.put(0x1040, "CAP_DOUBLEFEEDDETECTIONLENGTH"); + map.put(0x1041, "CAP_DOUBLEFEEDDETECTIONSENSITIVITY"); + map.put(0x1042, "CAP_DOUBLEFEEDDETECTIONRESPONSE"); + map.put(0x1043, "CAP_PAPERHANDLING"); + map.put(0x1044, "CAP_INDICATORSMODE"); + map.put(0x1045, "CAP_PRINTERVERTICALOFFSET"); + map.put(0x1046, "CAP_POWERSAVETIME"); + map.put(0x1047, "CAP_PRINTERCHARROTATION"); + map.put(0x1048, "CAP_PRINTERFONTSTYLE"); + map.put(0x1049, "CAP_PRINTERINDEXLEADCHAR"); + map.put(0x104A, "CAP_PRINTERINDEXMAXVALUE"); + map.put(0x104B, "CAP_PRINTERINDEXNUMDIGITS"); + map.put(0x104C, "CAP_PRINTERINDEXSTEP"); + map.put(0x104D, "CAP_PRINTERINDEXTRIGGER"); + map.put(0x104E, "CAP_PRINTERSTRINGPREVIEW"); + + /* image data sources MAY support these caps */ + map.put(0x1100, "ICAP_AUTOBRIGHT"); + map.put(0x1101, "ICAP_BRIGHTNESS"); + map.put(0x1103, "ICAP_CONTRAST"); + map.put(0x1104, "ICAP_CUSTHALFTONE"); + map.put(0x1105, "ICAP_EXPOSURETIME"); + map.put(0x1106, "ICAP_FILTER"); + map.put(0x1107, "ICAP_FLASHUSED"); + map.put(0x1108, "ICAP_GAMMA"); + map.put(0x1109, "ICAP_HALFTONES"); + map.put(0x110a, "ICAP_HIGHLIGHT"); + map.put(0x110c, "ICAP_IMAGEFILEFORMAT"); + map.put(0x110d, "ICAP_LAMPSTATE"); + map.put(0x110e, "ICAP_LIGHTSOURCE"); + map.put(0x1110, "ICAP_ORIENTATION"); + map.put(0x1111, "ICAP_PHYSICALWIDTH"); + map.put(0x1112, "ICAP_PHYSICALHEIGHT"); + map.put(0x1113, "ICAP_SHADOW"); + map.put(0x1114, "ICAP_FRAMES"); + map.put(0x1116, "ICAP_XNATIVERESOLUTION"); + map.put(0x1117, "ICAP_YNATIVERESOLUTION"); + map.put(0x1118, "ICAP_XRESOLUTION"); + map.put(0x1119, "ICAP_YRESOLUTION"); + map.put(0x111a, "ICAP_MAXFRAMES"); + map.put(0x111b, "ICAP_TILES"); + map.put(0x111c, "ICAP_BITORDER"); + map.put(0x111d, "ICAP_CCITTKFACTOR"); + map.put(0x111e, "ICAP_LIGHTPATH"); + map.put(0x111f, "ICAP_PIXELFLAVOR"); + map.put(0x1120, "ICAP_PLANARCHUNKY"); + map.put(0x1121, "ICAP_ROTATION"); + map.put(0x1122, "ICAP_SUPPORTEDSIZES"); + map.put(0x1123, "ICAP_THRESHOLD"); + map.put(0x1124, "ICAP_XSCALING"); + map.put(0x1125, "ICAP_YSCALING"); + map.put(0x1126, "ICAP_BITORDERCODES"); + map.put(0x1127, "ICAP_PIXELFLAVORCODES"); + map.put(0x1128, "ICAP_JPEGPIXELTYPE"); + map.put(0x112a, "ICAP_TIMEFILL"); + map.put(0x112b, "ICAP_BITDEPTH"); + map.put(0x112c, "ICAP_BITDEPTHREDUCTION"); + map.put(0x112d, "ICAP_UNDEFINEDIMAGESIZE"); + map.put(0x112e, "ICAP_IMAGEDATASET"); + map.put(0x112f, "ICAP_EXTIMAGEINFO"); + map.put(0x1130, "ICAP_MINIMUMHEIGHT"); + map.put(0x1131, "ICAP_MINIMUMWIDTH"); + map.put(0x1134, "ICAP_AUTODISCARDBLANKPAGES"); + map.put(0x1136, "ICAP_FLIPROTATION"); + map.put(0x1137, "ICAP_BARCODEDETECTIONENABLED"); + map.put(0x1138, "ICAP_SUPPORTEDBARCODETYPES"); + map.put(0x1139, "ICAP_BARCODEMAXSEARCHPRIORITIES"); + map.put(0x113a, "ICAP_BARCODESEARCHPRIORITIES"); + map.put(0x113b, "ICAP_BARCODESEARCHMODE"); + map.put(0x113c, "ICAP_BARCODEMAXRETRIES"); + map.put(0x113d, "ICAP_BARCODETIMEOUT"); + map.put(0x113e, "ICAP_ZOOMFACTOR"); + map.put(0x113f, "ICAP_PATCHCODEDETECTIONENABLED"); + map.put(0x1140, "ICAP_SUPPORTEDPATCHCODETYPES"); + map.put(0x1141, "ICAP_PATCHCODEMAXSEARCHPRIORITIES"); + map.put(0x1142, "ICAP_PATCHCODESEARCHPRIORITIES"); + map.put(0x1143, "ICAP_PATCHCODESEARCHMODE"); + map.put(0x1144, "ICAP_PATCHCODEMAXRETRIES"); + map.put(0x1145, "ICAP_PATCHCODETIMEOUT"); + map.put(0x1146, "ICAP_FLASHUSED2"); + map.put(0x1147, "ICAP_IMAGEFILTER"); + map.put(0x1148, "ICAP_NOISEFILTER"); + map.put(0x1149, "ICAP_OVERSCAN"); + map.put(0x1150, "ICAP_AUTOMATICBORDERDETECTION"); + map.put(0x1151, "ICAP_AUTOMATICDESKEW"); + map.put(0x1152, "ICAP_AUTOMATICROTATE"); + map.put(0x1153, "ICAP_JPEGQUALITY"); + map.put(0x1154, "ICAP_FEEDERTYPE"); + map.put(0x1155, "ICAP_ICCPROFILE"); + map.put(0x1156, "ICAP_AUTOSIZE"); + map.put(0x1157, "ICAP_AUTOMATICCROPUSESFRAME"); + map.put(0x1158, "ICAP_AUTOMATICLENGTHDETECTION"); + map.put(0x1159, "ICAP_AUTOMATICCOLORENABLED"); + map.put(0x115a, "ICAP_AUTOMATICCOLORNONCOLORPIXELTYPE"); + map.put(0x115b, "ICAP_COLORMANAGEMENTENABLED"); + map.put(0x115c, "ICAP_IMAGEMERGE"); + map.put(0x115d, "ICAP_IMAGEMERGEHEIGHTTHRESHOLD"); + map.put(0x115e, "ICAP_SUPPORTEDEXTIMAGEINFO"); + map.put(0x115f, "ICAP_FILMTYPE"); + map.put(0x1160, "ICAP_MIRROR"); + map.put(0x1161, "ICAP_JPEGSUBSAMPLING"); + + map.put(0x100c, "CAP_SUPPORTEDCAPSEXT"); + map.put(0x1023, "CAP_PAGEMULTIPLEACQUIRE"); + map.put(0x102f, "CAP_PAPERBINDING"); + map.put(0x1031, "CAP_PASSTHRU"); + map.put(0x1034, "CAP_POWERDOWNTIME"); + + mapCapCodeToName = map; + return mapCapCodeToName; + } + + public static short DSM_Entry(TW_IDENTITY origin, TW_IDENTITY destination, int dg, short dat, short msg, Object p) { + return twain.DSM_Entry(origin, destination, dg, dat, msg, p); + } + + public static Pointer DSM_Alloc(int len) { + try { + return twain.DSM_Alloc(len); + } catch (UnsatisfiedLinkError e) { + return kernel32.GlobalAlloc(0, len); + } + } + + public static void DSM_Free(Pointer handle) { + try { + twain.DSM_Free(handle); + } catch (UnsatisfiedLinkError e) { + kernel32.GlobalFree(handle); + } + } + + public static Pointer DSM_Lock(Pointer handle) { + try { + return twain.DSM_Lock(handle); + } catch (UnsatisfiedLinkError e) { + return kernel32.GlobalLock(handle); + } + } + + public static boolean DSM_Unlock(Pointer handle) { + try { + return twain.DSM_Unlock(handle); + } catch (UnsatisfiedLinkError e) { + return kernel32.GlobalUnlock(handle); + } + } + + public static boolean isWindows() { + return System.getProperty("os.name").toLowerCase().startsWith("windows"); + } + + public static String getArch() { + return System.getProperty("os.name").contains("amd64") ? "64" : "32"; + } + + public static void init() throws TwainException { + + if (!isWindows()) { + throw new TwainException("Library works only on Windows OS"); + } + kernel32 = Native.loadLibrary("kernel32", Kernel32.class); + +// user32 = (User32) Native.loadLibrary("user32", User32.class); + try { + twain = Native.loadLibrary("twaindsm", Win32Twain.class); + libraryName = "twaindsm"; + } catch (UnsatisfiedLinkError e) { + try { + twain = Native.loadLibrary("twain_" + getArch(), Win32Twain.class); + libraryName = "twain_32"; + } catch (UnsatisfiedLinkError ex) { + throw new TwainException("Cannot load TWAIN_" + getArch() + ".DLL or TWAINDSM.DLL"); + } + } + + if (!openDataSourceManager()) { + throw new TwainException("Cannot open datasource manager."); + } + } + + public static void done() { + User32.INSTANCE.PostMessage(hwnd, WinUser.WM_QUIT, null, null); + } + + private static void setupAppId(TW_IDENTITY appID) { + appID.Id = 0; + appID.ProtocolMajor = 1; + appID.ProtocolMinor = 9; +// appID.ProtocolMajor = 2; +// appID.ProtocolMinor = 4; + appID.SupportedGroups = (DG_CONTROL | DG_IMAGE | 0x20000000); + appID.setManufacturer("Smart-Consulting"); + appID.setProductFamily("JTwain agent"); + appID.setProductName("TWAIN-AGENT"); +// appID.Version.MajorNum = 2; +// appID.Version.MinorNum = 4; + appID.Version.MajorNum = 1; + appID.Version.MinorNum = 9; + appID.Version.Language = 17; + appID.Version.Country = 1; + appID.Version.setInfo("2017-01-17"); + } +// + + private static int OpenDSM(TW_IDENTITY application, WinDef.HWND winHdl) { + int stat = twain.DSM_Entry(application, null, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, new WinNT.HANDLEByReference(winHdl)); + return stat; + } + + static boolean started = false; + + public static boolean openDataSourceManager() throws TwainException { + if (g_AppID != null) { + return true; + } + + g_AppID = new TW_IDENTITY(); + + final Object o = new Object(); + + new Thread(new Runnable() { + + private WinDef.HWND owner; + + @Override + public void run() { + try { + String wNClass = "TWAIN" + System.currentTimeMillis(); + + WinDef.HMODULE hInst = null;//com.sun.jna.platform.win32.Kernel32.INSTANCE.GetModuleHandle(""); + WinUser.WNDCLASSEX wClass = new WinUser.WNDCLASSEX(); + wClass.hInstance = hInst; + wClass.lpszClassName = wNClass; + wClass.lpfnWndProc = new TwainWndProc(); + User32.INSTANCE.RegisterClassEx(wClass); + + owner = hwnd = User32.INSTANCE.CreateWindowEx(0, wNClass, wNClass, User32.WS_MAXIMIZE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, new WinDef.HWND(new Pointer(HWND_DESKTOP)), null, hInst, null); + + if (hwnd == null) { + throw new TwainException("Unable to create private window"); + } + boolean ok = User32.INSTANCE.SetWindowPos(hwnd, new WinDef.HWND(Pointer.createConstant(-1)), 0, 0, 0, 0, (short) SWP_NOSIZE); + if (!ok) { + User32.INSTANCE.DestroyWindow(hwnd); + hwnd = null; + g_AppID = null; + throw new TwainException("Unable to position private window"); + } + + setupAppId(g_AppID); + int stat = OpenDSM(g_AppID, hwnd); + + if (stat != TWRC_SUCCESS) { + User32.INSTANCE.DestroyWindow(hwnd); + hwnd = null; + g_AppID = null; + + throw new TwainException("Unable to open DSM"); + } + + WinUser.MSG lpMsg = new WinUser.MSG(); + started = true; + synchronized (o) { + o.notifyAll(); + } + + while (0 != User32.INSTANCE.GetMessage(lpMsg, null, 0, 0)) { + int rc = 0; + if (sourceManager != null) { + rc = handleMessage(lpMsg.getPointer()); + } + if (rc != TWRC_DSEVENT) { + User32.INSTANCE.TranslateMessage(lpMsg); + User32.INSTANCE.DispatchMessage(lpMsg); + } + } + + } catch (Throwable e) { + started = false; + e.printStackTrace(); + } + } + + } + ).start(); + + synchronized (o) { + try { + o.wait(TimeUnit.SECONDS.toMillis(10)); + } catch (InterruptedException ex) { + throw new TwainException(ex); + } + } + + return started; + } + + public static TwainSourceManager getSourceManager() throws TwainException { + if (sourceManager != null) { + return sourceManager; + } + init(); + return sourceManager = new TwainSourceManager(hwnd); + } + + static int callSourceManager(int dg, int id, int msg, Object obj) { + int rc = DSM_Entry(g_AppID, null, dg, (short) id, (short) msg, obj); + + if (dg == DG_CONTROL && id == DAT_IDENTITY && msg == MSG_USERSELECT) { + // Set foreground window + } + + return rc; + } + + static int callSource(TW_IDENTITY identity, int dg, int id, int msg, Object obj) { +// int rc = DSM_Entry(g_AppID, identity, dg, (short) id, (short) msg, obj); + int rc = DSM_Entry(g_AppID, identity, dg, (short) id, (short) msg, obj); + + if (dg == DG_CONTROL && id == DAT_IDENTITY && msg == MSG_USERSELECT) { + // Set foreground window + } + + return rc; + } + + static byte[] getContainer(int containerType, Pointer containerPtr) { + if (containerPtr == Pointer.NULL) { + return null; + } + switch (containerType) { + case TWON_ARRAY: { + Pointer p = DSM_Lock(containerPtr); + byte[] ret = null; + int size = 0; + int type = 0; + if (p != Pointer.NULL) { + type = p.getShort(0); + size = p.getInt(2); + + if (type <= TWTY_UNI512) { + size = 6 + size * TwainContainer.TYPE_SIZES[type]; + } else { + size = 6; + p.setInt(2, 0); + } + ret = p.getByteArray(0, size); + } + DSM_Unlock(containerPtr); + return ret; + } + case TWON_ENUMERATION: { + Pointer p = DSM_Lock(containerPtr); + byte[] ret = null; + int size = 0; + short type = 0; + if (p != Pointer.NULL) { + type = p.getShort(0); + size = p.getInt(2); + + if (type <= TWTY_UNI512) { + size = 14 + size * TwainContainer.TYPE_SIZES[type]; + } else { + size = 14; + p.setInt(2, 0); + } + ret = p.getByteArray(0, size); + } + DSM_Unlock(containerPtr); + return ret; + } + case TWON_ONEVALUE: { + Pointer p = DSM_Lock(containerPtr); + byte[] ret = null; + if (p != Pointer.NULL) { + ret = p.getByteArray(0, 6); + } + DSM_Unlock(containerPtr); + return ret; + } + + case TWON_RANGE: { + Pointer p = DSM_Lock(containerPtr); + byte[] ret = p.getByteArray(0, 22); + DSM_Unlock(containerPtr); + return ret; + + } + default: + return null; + } + } + + static Pointer setContainer(int containerType, byte[] containerBytes) { + Pointer p = DSM_Alloc(containerBytes.length); + + Pointer buf = DSM_Lock(p); + + if (buf == Pointer.NULL) { + DSM_Unlock(p); + DSM_Free(p); + + return Pointer.NULL; + } + + buf.write(0, containerBytes, 0, containerBytes.length); + + DSM_Unlock(p); + + return p; + } + + static void free(Pointer containerHandle) { + DSM_Free(containerHandle); + } + + static void signalException(String string) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.signalException(string); + } + } + + static void signalStateChange(TwainSource aThis) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.setState(aThis); + } + } + + static void negotiateCapabilities(TwainSource aThis) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.negotiateCapabilities(aThis); + } + } + + static public void setScanner(TwainScanner s) { + scanner = new WeakReference<>(s); + } + + static TwainScanner getScanner() { + return (TwainScanner) scanner.get(); + } + + static void select(TwainScanner sc) throws TwainException { + setScanner(sc); + TwainSourceManager sm = getSourceManager(); + sm.getSource().checkState(3); + trigger(sc, 1); + } + + static void getIdentities(TwainScanner sc, List list) throws TwainException { + setScanner(sc); + TwainSourceManager sm = getSourceManager(); + sm.getSource().checkState(3); + Semaphore s = new Semaphore(0, true); + list.add(s); + trigger(list, 2); + try { + s.tryAcquire(500, TimeUnit.MILLISECONDS); + } catch (InterruptedException ie) { + throw new TwainException(Twain.class.getName() + ".getIdentities\n\tCould not retrieve device names. Request timed out."); + } + } + + static void select(TwainScanner sc, String name) throws TwainException { + setScanner(sc); + TwainSourceManager sm = getSourceManager(); + sm.getSource().checkState(3); + trigger(name, 3); + } + + /** + * 使用当前打开的接口 + * @throws TwainException default错误 + */ + static void selectNow() throws TwainException { + //setScanner(sc); + TwainSourceManager sm = getSourceManager(); + sm.getSource().checkState(3); + trigger(scanner.get(), 1); + } + + static void acquire(TwainScanner scanner) throws TwainException { + setScanner(scanner); + TwainSourceManager sm = getSourceManager(); + sm.getSource().checkState(3); + trigger(scanner, 4); + } + + static void setCancel(TwainScanner aThis, boolean c) throws TwainException { + getSourceManager().getSource().setCancel(c); + } + + public static void nnew(byte[] imx, int preferredSize) { + Pointer p = kernel32.GlobalAlloc(0, preferredSize); + Win32Twain.TW_IMAGEMEMXFER im = new Win32Twain.TW_IMAGEMEMXFER(); + im.getPointer().write(0, imx, 0, im.size()); + im.read(); + + im.Memory.Flags = TWMF_APPOWNS | TWMF_HANDLE; + im.Memory.Length = preferredSize; + im.Memory.TheMem = p; + + im.write(); + im.getPointer().read(0, imx, 0, im.size()); + + im.Memory.TheMem = null; + } + + public static int ncopy(byte[] buffer, byte[] imx, int bytesWritten) { + Win32Twain.TW_IMAGEMEMXFER ix = new Win32Twain.TW_IMAGEMEMXFER(); + ix.getPointer().write(0, imx, 0, ix.size()); + ix.read(); + + Pointer p = kernel32.GlobalLock(ix.Memory.TheMem); + + p.read(0, buffer, 0, bytesWritten); + + kernel32.GlobalUnlock(p); + + ix.Memory.TheMem = null; + + return bytesWritten; + } + + public static void transferMemoryBuffer(TwainMemoryTransfer.Info info) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.setImageBuffer(info); + } + } + + public static void ndelete(byte[] imx) { + + Win32Twain.TW_IMAGEMEMXFER im = new Win32Twain.TW_IMAGEMEMXFER(); + im.getPointer().write(0, imx, 0, im.size()); + im.read(); + + if (im.Memory.TheMem != Pointer.NULL) { + kernel32.GlobalFree(im.Memory.TheMem); + im.Memory.TheMem = Pointer.NULL; + } + + im.write(); + im.getPointer().read(0, imx, 0, im.size()); + } + + public static void transferNativeImage(int handle) { + + BufferedImage image = (BufferedImage) ntransferImage(handle); + if (image != null) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.setImage(image); + } + } + } + + public static void transferFileImage(File file) { + if (file != null) { + TwainScanner scanner = getScanner(); + if (scanner != null) { + scanner.setImage(file); + } + } + } + + private static void trigger(Object caller, int cmd) { + ntrigger(caller, cmd); + } + + protected static void execute(Object obj, int cmd) { + TwainSource source; + try { + switch (cmd) { + case 0: { + if (!(obj instanceof TwainScanner)) { + throw new TwainException(obj.getClass().getName() + " not a instance of TwainScanner class"); + } + TwainScanner ti = (TwainScanner) obj; + source = sourceManager.getSource(); + ti.setState(source); + break; + } + case 1: + sourceManager.selectSource(); + break; + case 2: + List list = (List) obj; + Semaphore s = (Semaphore) list.get(0); + list.remove(0); + sourceManager.getIdentities(list); + s.release(); + break; + case 3: + String name = (String) obj; + sourceManager.selectSource(name); + break; + case 4: + final TwainSource src = sourceManager.openSource(); + + try { + src.enable(); + } finally { + src.close(); + } + break; + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private static int handleMessage(Pointer lpMsg) { + try { + return sourceManager.getSource().handleGetMessage(lpMsg); + } catch (Throwable ex) { + signalException(ex.getMessage()); + ex.printStackTrace(); + return TWRC_NOTDSEVENT; + } + } + protected static Map callMapper = new ConcurrentHashMap<>(); + + private static void ntrigger(Object caller, int cmd) { + int id = (int) System.nanoTime(); + callMapper.put(id, caller); +// User32.INSTANCE.PostMessage(hwnd, WinUser.WM_USER, new WinDef.WPARAM(cmd), new WinDef.LPARAM(id)); + User32.INSTANCE.PostMessage(hwnd, WinUser.WM_USER, new WinDef.WPARAM(cmd), new WinDef.LPARAM(id)); + } + + private static BufferedImage ntransferImage(int handle) { + + if (handle == 0) { + return null; + } + + Pointer HANDLE = new Pointer(handle); + Pointer p = DSM_Lock(HANDLE); + if (p == null) { + return null; + } + WinGDI.BITMAPINFOHEADER bih = (WinGDI.BITMAPINFOHEADER) WinGDI.BITMAPINFOHEADER.newInstance(WinGDI.BITMAPINFOHEADER.class, p); + bih.read(); + + if (bih.biCompression != WinGDI.BI_RGB && bih.biCompression != WinGDI.BI_BITFIELDS) { + signalException("Cannot deal with DIB header"); + DSM_Unlock(HANDLE); + DSM_Free(HANDLE); + return null; + } + BufferedImage image = null; + switch (bih.biBitCount) { + case 1: + image = transfer01BitImage(bih); + break; + case 4: + image = transfer04BitImage(bih); + break; + case 8: + image = transfer08BitImage(bih); + break; + case 24: + image = transfer24BitImage(bih); + break; + default: + signalException("Unsupported bit size"); + break; + } + + DSM_Unlock(HANDLE); + DSM_Free(HANDLE); + return image; + } + + private static BufferedImage transfer01BitImage(WinGDI.BITMAPINFOHEADER bih) { + BufferedImage img = new BufferedImage(bih.biWidth, bih.biHeight, BufferedImage.TYPE_BYTE_BINARY, readBitIndexModel(bih)); + DataBufferByte dbi = (DataBufferByte) img.getRaster().getDataBuffer(); + int size = (bih.biWidth + 7) >> 3; + + int offset = bih.size() + getColorsInPallete(bih) * 4; + int coffest = dbi.getData().length - size; + int bpl = ((bih.biWidth * bih.biBitCount + 31) >> 5) << 2; + for (int i = 0; i < bih.biHeight; i++) { + bih.getPointer().read(offset, dbi.getData(), coffest, size); + offset += bpl; + coffest -= size; + + } + return img; + } + + private static BufferedImage transfer04BitImage(WinGDI.BITMAPINFOHEADER bih) { + BufferedImage img = new BufferedImage(bih.biWidth, bih.biHeight, BufferedImage.TYPE_BYTE_INDEXED, readBitIndexModel(bih)); + DataBufferByte dbi = (DataBufferByte) img.getRaster().getDataBuffer(); + int size = (bih.biWidth + 1) >> 1; + + int offset = bih.size() + getColorsInPallete(bih) * 4; + int coffest = dbi.getData().length - size; + int bpl = ((bih.biWidth * bih.biBitCount + 31) >> 5) << 2; + for (int i = 0; i < bih.biHeight; i++) { + bih.getPointer().read(offset, dbi.getData(), coffest, size); + offset += bpl; + coffest -= size; + + } + + return img; + } + + private static BufferedImage transfer08BitImage(WinGDI.BITMAPINFOHEADER bih) { + BufferedImage img = new BufferedImage(bih.biWidth, bih.biHeight, BufferedImage.TYPE_BYTE_INDEXED, readBitIndexModel(bih)); + DataBufferByte dbi = (DataBufferByte) img.getRaster().getDataBuffer(); + int size = bih.biWidth; + + int offset = bih.size() + getColorsInPallete(bih) * 4; + int coffest = dbi.getData().length - size; + int bpl = ((bih.biWidth * bih.biBitCount + 31) >> 5) << 2; + for (int i = 0; i < bih.biHeight; i++) { + bih.getPointer().read(offset, dbi.getData(), coffest, size); + offset += bpl; + coffest -= size; + } + + return img; + } + + private static BufferedImage transfer24BitImage(WinGDI.BITMAPINFOHEADER bih) { + BufferedImage img = new BufferedImage(bih.biWidth, bih.biHeight, BufferedImage.TYPE_3BYTE_BGR); + DataBufferByte dbi = (DataBufferByte) img.getRaster().getDataBuffer(); + int size = bih.biWidth * 3; + + int offset = bih.size(); + int coffest = dbi.getData().length - size; + int bpl = ((bih.biWidth * bih.biBitCount + 31) >> 5) << 2; + for (int i = 0; i < bih.biHeight; i++) { + bih.getPointer().read(offset, dbi.getData(), coffest, size); + offset += bpl; + coffest -= size; + } + return img; + } + + private static IndexColorModel readBitIndexModel(WinGDI.BITMAPINFOHEADER bih) { + WinGDI.BITMAPINFO bi = (WinGDI.BITMAPINFO) WinGDI.BITMAPINFO.newInstance(WinGDI.BITMAPINFO.class, new Pointer(Pointer.nativeValue(bih.getPointer()))); + + int size = getColorsInPallete(bih); + + bi.bmiColors = new WinGDI.RGBQUAD[size]; + bi.read(); + + byte[] r = new byte[size]; + byte[] g = new byte[size]; + byte[] b = new byte[size]; + for (int i = 0; i < size; i++) { + r[i] = bi.bmiColors[i].rgbRed; + g[i] = bi.bmiColors[i].rgbGreen; + b[i] = bi.bmiColors[i].rgbBlue; + } + IndexColorModel icm = new IndexColorModel(bih.biBitCount, size, r, g, b); + + return icm; + } + + private static int getColorsInPallete(WinGDI.BITMAPINFOHEADER bih) { + return bih.biClrUsed != 0 ? bih.biClrUsed : 1 << bih.biBitCount; + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainCallback.java b/src/main/java/org/aohe/core/twain/TwainCallback.java new file mode 100644 index 0000000..5de02e6 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainCallback.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 lucifer. + * + * 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 org.aohe.core.twain; + +import com.sun.jna.Pointer; +import com.sun.jna.win32.StdCallLibrary; +import org.aohe.libs.Win32Twain; + +public class TwainCallback implements StdCallLibrary.StdCallCallback { + + public int callback(Win32Twain.TW_IDENTITY orign, Win32Twain.TW_IDENTITY dest, int dg, short dat, short msg, Pointer data) { +// System.out.println("MSG!!!!!!!!!!!!!!!!!!!!!!!!!!!" + msg); + try { + TwainIdentity orig = new TwainIdentity(Twain.sourceManager, orign); + TwainSource source = Twain.sourceManager.getSource(); + + if (orig.getId() != source.getId()) { + return Twain.TWRC_FAILURE; + } + System.out.println(String.format("CALLBACK ----------------------> DG:%d, DAT:%d, MSG:%d", dg, dat, msg)); + return source.callback(dg, dat, msg, data); + } catch (Throwable e) { + Twain.signalException(e.getMessage()); + e.printStackTrace(); + return Twain.TWRC_FAILURE; + } + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainCapability.java b/src/main/java/org/aohe/core/twain/TwainCapability.java new file mode 100644 index 0000000..b699627 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainCapability.java @@ -0,0 +1,280 @@ +package org.aohe.core.twain; + +import com.sun.jna.Pointer; +import org.aohe.exceptions.TwainCheckStatusException; +import org.aohe.exceptions.TwainException; +import org.aohe.libs.Win32Twain; +import org.aohe.utils.TwainUtils; +import org.aohe.variable.*; + +import java.util.ArrayList; +import java.util.List; + +public class TwainCapability { + + protected TwainSource source; + public int cap; + protected byte[] capability = new byte[16]; + protected TwainContainer container; + + public TwainCapability(TwainSource source, int cap) throws TwainException { + this.source = source; + this.cap = cap; + this.container = get(); + } + + public TwainCapability(TwainSource source, int cap, int mode) throws TwainException { + this.source = source; + this.cap = cap; + switch (mode) { + case Twain.MSG_GETCURRENT: + container = getCurrent(); + break; + case Twain.MSG_GETDEFAULT: + container = getDefault(); + break; + case Twain.MSG_GET: + default: + container = get(); + break; + } + } + + /** + * 根据消息和容器类型获取TwainContainer对象 + * @param msg 消息类型 + * @param contype 容器类型 + * @return TwainContainer对象 + * @throws TwainException Twain异常 + */ + private TwainContainer get(int msg, int contype) throws TwainException { + Win32Twain.TW_CAPABILITY cp = new Win32Twain.TW_CAPABILITY(); + + cp.Cap = (short) cap; + cp.ConType = (short) contype; + cp.Container = 0l; + + TwainUtils.setINT16(capability, 0, cap); + TwainUtils.setINT16(capability, 2, contype); + TwainUtils.setINT64(capability, 4, 0); + + System.out.print("TWAIN GET: "); + dumpHex(capability); + System.out.print(","); + source.call(Twain.DG_CONTROL, Twain.DAT_CAPABILITY, (short) msg, capability); + + int containerType = TwainUtils.getINT16(capability, 2); + Pointer containerPtr = new Pointer(TwainUtils.getINT64(capability, 4)); + + dumpHex(capability); + System.out.print(","); + byte[] container = Twain.getContainer(containerType, containerPtr); + dumpHex(container); + System.out.println(); + + switch (containerType) { + case Twain.TWON_ARRAY: + return new TwainArray(cap, container); + case Twain.TWON_ENUMERATION: + return new TwainEnumeration(cap, container); + case Twain.TWON_ONEVALUE: + return new TwainOneValue(cap, container); + case Twain.TWON_RANGE: + return new TwainRange(cap, container); + default: + throw new TwainException("Unknown container type " + containerType); + } + } + + private TwainContainer get(int msg) throws TwainException { + return get(msg, -1); + } + + public TwainContainer get() throws TwainException { + return container = get(Twain.MSG_GET); + } + + public TwainContainer getCurrent() throws TwainException { + return get(Twain.MSG_GETCURRENT); + } + + public TwainContainer getDefault() throws TwainException { + return get(Twain.MSG_GETDEFAULT); + } + + public int querySupport() throws TwainException { + return get(Twain.MSG_QUERYSUPPORT, Twain.TWON_ONEVALUE).intValue(); + } + + public boolean querySupport(int flagMask) { + try { + int flags = querySupport(); + return (flags & flagMask) != 0; + } catch (TwainException e) { + return false; + } + } + + public TwainContainer reset() throws TwainException { + return container = get(Twain.MSG_RESET); + } + + public TwainContainer set() throws TwainException { + return container = set(container); + } + + public static void dumpHex(byte[] bytes) { + for (int i = 0; i < bytes.length; i++) { + System.out.print(String.format("%02x", bytes[i])); + } + } + + public TwainContainer set(TwainContainer container) throws TwainException { + int containerType = container.getType(); + byte[] containerBytes = container.getBytes(); + Pointer containerHandle = Twain.setContainer(containerType, containerBytes); + + try { + + TwainUtils.setINT16(capability, 0, cap); + TwainUtils.setINT16(capability, 2, containerType); + TwainUtils.setINT64(capability, 4, Pointer.nativeValue(containerHandle)); + System.out.print("TWAIN SET: "); + dumpHex(capability); + System.out.print(","); + dumpHex(containerBytes); + System.out.println(); + source.call(Twain.DG_CONTROL, Twain.DAT_CAPABILITY, Twain.MSG_SET, capability); + + } catch (TwainCheckStatusException e) { + e.printStackTrace(); + container = get(); + } finally { + Twain.free(containerHandle); + } + + return container; + } + + public T[] getItems() { + return container.getItems(); + } + + public boolean booleanValue() throws TwainException { + return getCurrent().booleanValue(); + } + + public int intValue() throws TwainException { + return getCurrent().intValue(); + } + + public double doubleValue() throws TwainException { + return getCurrent().doubleValue(); + } + + public void setCurrentValue(boolean v) throws TwainException { + setCurrentValue(new Boolean(v)); + } + + public void setCurrentValue(int v) throws TwainException { + setCurrentValue(new Integer(v)); + } + + public void setCurrentValue(double v) throws TwainException { + setCurrentValue(new Double(v)); + } + + public void setCurrentValue(Object val) throws TwainException { + container.setCurrentValue(val); + set(); + } + + public boolean booleanDefaultValue() throws TwainException { + return getDefault().booleanDefaultValue(); + } + + public int intDefaultValue() throws TwainException { + return getDefault().intDefaultValue(); + } + + public double doubleDefaultValue() throws TwainException { + return getDefault().doubleDefaultValue(); + } + + public void setDefaultValue(boolean v) throws TwainException { + setDefaultValue(new Boolean(v)); + } + + public void setDefaultValue(int v) throws TwainException { + setDefaultValue(new Integer(v)); + } + + public void setDefaultValue(double v) throws TwainException { + setDefaultValue(new Double(v)); + } + + public void setDefaultValue(Object val) throws TwainException { + container.setDefaultValue(val); + set(); + } + + public static TwainCapability[] getCapabilities(TwainSource source) throws TwainException { + TwainCapability tc = source.getCapability(Twain.CAP_SUPPORTEDCAPS); + Object[] items = tc.getItems(); + List caps = new ArrayList<>(); + + for (int i = 0; i < items.length; i++) { + int capid = ((Number) items[i]).intValue(); + try { + switch (capid) { + case Twain.ICAP_COMPRESSION: + caps.add(new Compression(source)); + break; + case Twain.ICAP_XFERMECH: + caps.add(new XferMech(source)); + break; + case Twain.ICAP_IMAGEFILEFORMAT: + caps.add(new ImageFileFormat(source)); + break; + default: + caps.add(new TwainCapability(source, capid)); + break; + } + } catch (TwainException e) { + } + } + return (TwainCapability[]) caps.toArray(new TwainCapability[0]); + } + + static public class ImageFileFormat extends TwainCapability { + + ImageFileFormat(TwainSource source) throws TwainException { + super(source, Twain.ICAP_IMAGEFILEFORMAT); + } + + } + + static public class Compression extends TwainCapability { + + Compression(TwainSource source) throws TwainException { + super(source, Twain.ICAP_COMPRESSION); + } + + } + + static public class XferMech extends TwainCapability { + + XferMech(TwainSource source) throws TwainException { + super(source, Twain.ICAP_XFERMECH); + } + + @Override + public int intValue() { + try { + return super.intValue(); + } catch (Exception e) { + return Twain.TWSX_NATIVE; + } + } + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainDefaultTransferFactory.java b/src/main/java/org/aohe/core/twain/TwainDefaultTransferFactory.java new file mode 100644 index 0000000..63937ba --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainDefaultTransferFactory.java @@ -0,0 +1,29 @@ +package org.aohe.core.twain; + + +import org.aohe.transfer.TwainFileTransfer; +import org.aohe.transfer.TwainMemoryTransfer; +import org.aohe.transfer.TwainNativeTransfer; +import org.aohe.transfer.TwainTransfer; + +public class TwainDefaultTransferFactory implements TwainTransferFactory { + + public TwainDefaultTransferFactory() { + } + + @Override + public TwainTransfer createMemoryTransfer(TwainSource source) { + return new TwainMemoryTransfer(source); + } + + @Override + public TwainTransfer createNativeTransfer(TwainSource source) { + return new TwainNativeTransfer(source); + } + + @Override + public TwainTransfer createFileTransfer(TwainSource source) { + return new TwainFileTransfer(source); + } + +} diff --git a/src/main/java/org/aohe/core/twain/TwainIOMetadata.java b/src/main/java/org/aohe/core/twain/TwainIOMetadata.java new file mode 100644 index 0000000..907fa51 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainIOMetadata.java @@ -0,0 +1,140 @@ +package org.aohe.core.twain; + +import org.aohe.transfer.TwainMemoryTransfer; + +import java.awt.image.BufferedImage; +import java.io.File; + +public class TwainIOMetadata { + + static public Type INFO = new Type("INFO"); + static public Type EXCEPTION = new Type("EXCEPTION"); + static public Type SELECTED = new Type("SELECTED"); + static public Type ACQUIRED = new Type("ACQUIRED"); + static public Type FILE = new Type("FILE"); + static public Type MEMORY = new Type("MEMORY"); + static public Type NEGOTIATE = new Type("NEGOTIATE"); + static public Type STATECHANGE = new Type("STATECHANGE"); + + private int laststate = 0, state = 0; + private boolean cancel = false; + private BufferedImage image = null; + private File file = null; + private String info = ""; + private Exception exception = null; + + public void setState(int s) { + laststate = state; + state = s; + } + + public int getLastState() { + return laststate; + } + + public int getState() { + return state; + } + + public boolean isState(int state) { + return this.state == state; + } + + public void setImage(BufferedImage image) { + this.image = image; + this.file = null; + } + + public BufferedImage getImage() { + return image; + } + + public void setFile(File file) { + this.image = null; + this.file = file; + } + + public File getFile() { + return file; + } + + public void setInfo(String info) { + this.info = info; + } + + public String getInfo() { + return info; + } + + public void setException(Exception ex) { + this.exception = ex; + } + + public Exception getException() { + return exception; + } + + public boolean getCancel() { + return cancel; + } + + public void setCancel(boolean cancel) { + this.cancel = cancel; + } + + static public final String[] TWAIN_STATE = { + "", + "Pre-Session", + "Source Manager Loaded", + "Source Manager Open", + "Source Open", + "Source Enabled", + "Transfer Ready", + "Transferring Data",}; + + public String getStateStr() { + return TWAIN_STATE[getState()]; + } + + private TwainSource source = null; + + void setSource(TwainSource source) { + this.source = source; + } + + public TwainSource getSource() { + return source; + } + + public TwainSource getDevice() { + return source; + } + private TwainMemoryTransfer.Info memory = null; + + public void setMemory(TwainMemoryTransfer.Info info) { + memory = info; + } + + public TwainMemoryTransfer.Info getMemory() { + return memory; + } + + public boolean isFinished() { + return (getState() == 3) && (getLastState() == 4); + } + + static public class Type { + + String type; + + public Type(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } + + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainIdentity.java b/src/main/java/org/aohe/core/twain/TwainIdentity.java new file mode 100644 index 0000000..4e3d355 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainIdentity.java @@ -0,0 +1,179 @@ +package org.aohe.core.twain; + +import org.aohe.exceptions.TwainException; +import org.aohe.libs.Win32Twain; + +import java.util.ArrayList; +import java.util.List; + +public class TwainIdentity { + + private TwainSourceManager manager; + protected Win32Twain.TW_IDENTITY identity; + + public TwainIdentity(TwainSourceManager manager) { + this.manager = manager; + this.identity = new Win32Twain.TW_IDENTITY(); + } + + TwainIdentity(TwainSourceManager sourceManager, Win32Twain.TW_IDENTITY orign) { + this.manager = manager; + this.identity = orign; + } + + protected void getDefault() { + try { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_GETDEFAULT, identity); + } catch (TwainException e) { + } + } + + void userSelect() throws TwainException { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_USERSELECT, identity); + } + + public void open() throws TwainException { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_OPENDS, identity); + } + + public void close() throws TwainException { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_CLOSEDS, identity); + } + + void getFirst() throws TwainException { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_GETFIRST, identity); + } + + void getNext() throws TwainException { + manager.call(Twain.DG_CONTROL, Twain.DAT_IDENTITY, Twain.MSG_GETNEXT, identity); + } + + public int getId() { + return identity.Id; + } + + public int getMajorNum() { + return identity.Version.MajorNum; + } + + public int getMinorNum() { + return identity.Version.MinorNum; + } + + public int getLanguage() { + return identity.Version.Language; + } + + public int getCountry() { + return identity.Version.Country; + } + + public int getProtocolMajor() { + return identity.ProtocolMajor; + } + + public int getProtocolMinor() { + return identity.ProtocolMinor; + } + + public int getSupportedGroups() { + return identity.SupportedGroups; + } + + public String getManufacturer() { + return identity.getManufacturer(); + } + + public String getProductFamily() { + return identity.getProductFamily(); + } + + public String getProductName() { + return identity.getProductName(); + } + + public static TwainIdentity[] getIdentities() throws TwainException { + TwainSourceManager manager = Twain.getSourceManager(); + List identities = new ArrayList<>(); + try { + TwainIdentity identity = new TwainIdentity(manager); + identity.getFirst(); + identities.add(identity); + while (true) { + identity = new TwainIdentity(manager); + identity.getNext(); + identities.add(identity); + } + } catch (TwainException e) { + } + + return identities.toArray(new TwainIdentity[0]); + } + + /** + * 获取产品名称数组 + * @return 产品名称数组 + * @throws TwainException 如果获取产品名称时发生错误 + */ + public static String[] getProductNames() throws TwainException { + TwainSourceManager manager = Twain.getSourceManager(); + List identities = new ArrayList<>(); + try { + TwainIdentity identity = new TwainIdentity(manager); + identity.getFirst(); + identities.add(identity.getProductName()); + while (true) { + identity = new TwainIdentity(manager); + identity.getNext(); + identities.add(identity.getProductName()); + } + } catch (TwainException e) { + // 处理TwainException + //查询完成,抛出错误 + } + + return identities.toArray(new String[0]); + } + + /** + * 获取产品名称List + * @return 产品名称数组 + * @throws TwainException 如果获取产品名称时发生错误 + */ + public static List getProductNamesToList() throws TwainException { + TwainSourceManager manager = Twain.getSourceManager(); + List identities = new ArrayList<>(); + try { + TwainIdentity identity = new TwainIdentity(manager); + identity.getFirst(); + identities.add(identity.getProductName()); + while (true) { + identity = new TwainIdentity(manager); + identity.getNext(); + identities.add(identity.getProductName()); + } + } catch (TwainException e) { + // 处理TwainException + //查询完成,抛出错误 + } + + return identities; + } + + public String toString() { + String s = "TwainIdentity\n"; + s += "\tid = 0x" + Integer.toHexString(getId()) + "\n"; + s += "\tmajorNum = 0x" + Integer.toHexString(getMajorNum()) + "\n"; + s += "\tminorNum = 0x" + Integer.toHexString(getMinorNum()) + "\n"; + s += "\tlanguage = 0x" + Integer.toHexString(getLanguage()) + "\n"; + s += "\tcountry = 0x" + Integer.toHexString(getCountry()) + "\n"; + s += "\tprotocol major = 0x" + Integer.toHexString(getProtocolMajor()) + "\n"; + s += "\tprotocol minor = 0x" + Integer.toHexString(getProtocolMinor()) + "\n"; + s += "\tsupported groups = 0x" + Integer.toHexString(getSupportedGroups()) + "\n"; + s += "\tmanufacturer = " + getManufacturer() + "\n"; + s += "\tproduct family = " + getProductFamily() + "\n"; + s += "\tproduct name = " + getProductName() + "\n"; + return s; + } + +} diff --git a/src/main/java/org/aohe/core/twain/TwainImageLayout.java b/src/main/java/org/aohe/core/twain/TwainImageLayout.java new file mode 100644 index 0000000..9dae8e6 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainImageLayout.java @@ -0,0 +1,90 @@ +package org.aohe.core.twain; + + +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +import static org.aohe.core.twain.Twain.*; + +public class TwainImageLayout { + + TwainSource source; + byte[] buf = new byte[28]; + + public TwainImageLayout(TwainSource source) { + this.source = source; + } + + public void get() throws TwainException { + source.call(DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, buf); + } + + public void getDefault() throws TwainException { + source.call(DG_IMAGE, DAT_IMAGELAYOUT, MSG_GETDEFAULT, buf); + } + + public void set() throws TwainException { + source.call(DG_IMAGE, DAT_IMAGELAYOUT, MSG_SET, buf); + } + + public void reset() throws TwainException { + source.call(DG_IMAGE, DAT_IMAGELAYOUT, MSG_RESET, buf); + } + + public double getLeft() { + return TwainUtils.getFIX32(buf, 0); + } + + public void setLeft(double v) { + TwainUtils.setFIX32(buf, 0, v); + } + + public double getTop() { + return TwainUtils.getFIX32(buf, 4); + } + + public void setTop(double v) { + TwainUtils.setFIX32(buf, 4, v); + } + + public double getRight() { + return TwainUtils.getFIX32(buf, 8); + } + + public void setRight(double v) { + TwainUtils.setFIX32(buf, 8, v); + } + + public double getBottom() { + return TwainUtils.getFIX32(buf, 12); + } + + public void setBottom(double v) { + TwainUtils.setFIX32(buf, 12, v); + } + + public int getDocumentNumber() { + return TwainUtils.getINT32(buf, 16); + } + + public void setDocumentNumber(int v) { + TwainUtils.setINT32(buf, 16, v); + } + + public int getPageNumber() { + return TwainUtils.getINT32(buf, 20); + } + + public void setPageNumber(int v) { + TwainUtils.setINT32(buf, 20, v); + } + + public int getFrameNumber() { + return TwainUtils.getINT32(buf, 24); + } + + public void setFrameNumber(int v) { + TwainUtils.setINT32(buf, 24, v); + } + +} diff --git a/src/main/java/org/aohe/core/twain/TwainListener.java b/src/main/java/org/aohe/core/twain/TwainListener.java new file mode 100644 index 0000000..65f3e46 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainListener.java @@ -0,0 +1,8 @@ +package org.aohe.core.twain; + + +public interface TwainListener { + + public void update(TwainIOMetadata.Type type, TwainIOMetadata metadata); + +} diff --git a/src/main/java/org/aohe/core/twain/TwainScanner.java b/src/main/java/org/aohe/core/twain/TwainScanner.java new file mode 100644 index 0000000..25a24ae --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainScanner.java @@ -0,0 +1,159 @@ +package org.aohe.core.twain; + + +import org.aohe.exceptions.TwainException; +import org.aohe.transfer.TwainMemoryTransfer; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TwainScanner { + + private TwainIOMetadata metadata; + private List listeners = new ArrayList<>(); + + public TwainScanner() { + metadata = new TwainIOMetadata(); + Twain.setScanner(this); + } + + public void select() throws TwainException { + Twain.select(this); + } + + public TwainIdentity[] getIdentities() { + List identities = new ArrayList<>(); + try { + Twain.getIdentities(this, identities); + } catch (Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + return (TwainIdentity[]) identities.toArray(new TwainIdentity[identities.size()]); + } + + public String[] getDeviceNames() throws TwainException { + List identities = new ArrayList<>(); + + Twain.getIdentities(this, identities); + + String[] names = new String[identities.size()]; + Iterator ids = identities.iterator(); + for (int i = 0; ids.hasNext(); i++) { + TwainIdentity id = (TwainIdentity) ids.next(); + names[i] = id.getProductName(); + } + return names; + } + + public void select(String name) throws TwainException { + Twain.select(this, name); + } + + public void selectNow() throws TwainException { + Twain.selectNow(); + } + + public void acquire() throws TwainException { + Twain.acquire(this); + } + + public void setCancel(boolean c) throws TwainException { + Twain.setCancel(this, c); + } + + void setImage(BufferedImage image) { + try { + metadata.setImage(image); + fireListenerUpdate(metadata.ACQUIRED); + } catch (Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + } + + void setImage(File file) { + try { + metadata.setFile(file); + fireListenerUpdate(metadata.FILE); + } catch (Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + } + + void setImageBuffer(TwainMemoryTransfer.Info info) { + try { + ((TwainIOMetadata) metadata).setMemory(info); + fireListenerUpdate(metadata.MEMORY); + } catch (Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + } + + protected void negotiateCapabilities(TwainSource source) { + ((TwainIOMetadata) metadata).setSource(source); + fireListenerUpdate(metadata.NEGOTIATE); + if (metadata.getCancel()) { + try { + source.close(); + } catch (Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + } + } + + void setState(TwainSource source) { + metadata.setState(source.getState()); + ((TwainIOMetadata) metadata).setSource(source); + fireListenerUpdate(metadata.STATECHANGE); + } + + void signalInfo(String msg, int val) { + metadata.setInfo(msg + " [0x" + Integer.toHexString(val) + "]"); + fireListenerUpdate(metadata.INFO); + } + + void signalException(String msg) { + Exception e = new TwainException(getClass().getName() + ".setException:\n " + msg); + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + + public TwainIOMetadata getMetadata() { + return metadata; + } + + public void setMetadata(TwainIOMetadata metadata) { + this.metadata = metadata; + } + + public void addListener(TwainListener listener) { + listeners.add(listener); + } + + public void removeListener(TwainListener listener) { + listeners.remove(listener); + } + + public void fireExceptionUpdate(Exception e) { + metadata.setException(e); + fireListenerUpdate(metadata.EXCEPTION); + } + + public void fireListenerUpdate(TwainIOMetadata.Type type) { + for (Iterator e = new ArrayList<>(listeners).iterator(); e.hasNext();) { + TwainListener listener = (TwainListener) e.next(); + listener.update(type, metadata); + } + } + + public static TwainScanner getScanner() { + return new TwainScanner(); + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainSource.java b/src/main/java/org/aohe/core/twain/TwainSource.java new file mode 100644 index 0000000..56eb166 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainSource.java @@ -0,0 +1,559 @@ +package org.aohe.core.twain; + +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.WinDef; +import org.aohe.exceptions.*; +import org.aohe.libs.Win32Twain; +import org.aohe.transfer.TwainTransfer; +import org.aohe.utils.TwainUtils; + +import java.util.concurrent.Semaphore; + +public class TwainSource extends TwainIdentity { + + private boolean busy; + private int state; + private WinDef.HWND hwnd; + + private int showUI = 1; + private int modalUI = 0; + private int iff = Twain.TWFF_BMP; + + private boolean userCancelled; + private TwainTransferFactory transferFactory; + private Semaphore twSemaphore = null; + private boolean twHaveImage = false; + + short callback(int dg, short dat, short msg, Pointer data) { + switch (msg) { + case Twain.MSG_XFERREADY: +// twHaveImage = true; +// twSemaphore.release(); + try { + transferImage(); + } catch (Exception e) { + return Twain.TWRC_FAILURE; + } + break; + case Twain.MSG_CLOSEDSOK: + case Twain.MSG_CLOSEDSREQ: +// twHaveImage = false; +// twSemaphore.release(); + try { + disable(); + close(); + } catch (Exception e) { + return Twain.TWRC_FAILURE; + } + break; + case Twain.MSG_DEVICEEVENT: + case Twain.MSG_NULL: + break; + default: + System.out.println("Unknown message"); + return Twain.TWRC_FAILURE; + } + return Twain.TWRC_SUCCESS; + } + + public TwainSource(TwainSourceManager manager, WinDef.HWND hwnd, boolean busy) { + super(manager); + this.busy = busy; + this.state = 3; + this.hwnd = hwnd; + this.userCancelled = false; + this.transferFactory = new TwainDefaultTransferFactory(); + } + + public Win32Twain.TW_IDENTITY getIdentity() { + return identity; + } + + public boolean isBusy() { + return busy; + } + + protected void setBusy(boolean b) { + busy = b; + Twain.signalStateChange(this); + } + + public int getState() { + return state; + } + + public void setState(int s) { + state = s; + Twain.signalStateChange(this); + } + + public boolean getCancel() { + return userCancelled; + } + + public void setCancel(boolean c) { + userCancelled = c; + } + + protected void checkState(int state) throws TwainException { + if (this.state == state) { + return; + } + throw new TwainException(getClass().getName() + ".checkState: Source not in state " + state + " but in state " + this.state + "."); + } + + private boolean isTwain20() { + return false; +// return (identity.SupportedGroups & 0x40000000) != 0; + } + + @Override + public void open() throws TwainException { + super.open(); + if (isTwain20()) { + Win32Twain.TW_CALLBACK cb = new Win32Twain.TW_CALLBACK(); + cb.Message = 0; + cb.Proc = new TwainCallback(); + + call(Twain.DG_CONTROL, (short) 0x12, (short) 0x902, cb); + } + } + + protected int getConditionCode() throws TwainException { + Win32Twain.TW_FIX32 status = new Win32Twain.TW_FIX32(); + int rc = Twain.callSource(identity, Twain.DG_CONTROL, Twain.DAT_STATUS, Twain.MSG_GET, status); + if (rc != Twain.TWRC_SUCCESS) { + throw new TwainException("Cannot retrive twain source's status. RC = " + rc); + } +// System.out.println(status.Whole + " " + status.Frac); + return status.Whole; + } + + public void call(short dg, short dat, short msg, Object data) throws TwainCheckStatusException, TwainCancelException, TwainNotDSException, TwainTransferDoneException, TwainException { + int rc = Twain.callSource(identity, dg, dat, msg, data); + switch (rc) { + case Twain.TWRC_SUCCESS: + return; + case Twain.TWRC_FAILURE: + int cc = getConditionCode(); + if (cc == 4) { + } else { + throw new TwainException(getClass().getName() + ".call error: " + TwainSourceManager.INFO[cc]); + } + case Twain.TWRC_CHECKSTATUS: + throw new TwainCheckStatusException(); + case Twain.TWRC_CANCEL: + throw new TwainCancelException(); + case Twain.TWRC_DSEVENT: + return; + case Twain.TWRC_NOTDSEVENT: + throw new TwainNotDSException(); + case Twain.TWRC_XFERDONE: + throw new TwainTransferDoneException(); + case Twain.TWRC_ENDOFLIST: + throw new TwainEndOfListException(); + case Twain.TWRC_INFONOTSUPPORTED: + throw new TwainInfNotSupportedException(); + case Twain.TWRC_DATANOTAVAILABLE: + throw new TwainDataNotAvailableException(); + default: + throw new TwainException("Failed to call source. RC = " + rc); + } + } + + public TwainCapability[] getCapabilities() throws TwainException { + return TwainCapability.getCapabilities(this); + } + + public TwainCapability getCapability(int cap) throws TwainException { // use only in state 4 + return new TwainCapability(this, cap); + } + + public TwainCapability getCapability(int cap, int mode) throws TwainException { + return new TwainCapability(this, cap, mode); + } + + public TwainTransferFactory getTransferFactory() { + return transferFactory; + } + + public void setTransferFactory(TwainTransferFactory transferFactory) { + if (transferFactory == null) { + throw new IllegalArgumentException(getClass().getName() + ".setTransferFactory\n\tTwain transfer factory cannot be null."); + } + this.transferFactory = transferFactory; + } + + public void setShowUI(boolean enable) { + showUI = (enable) ? 1 : 0; + } + + public boolean isModalUI() { + return (modalUI == 1); + } + + public void setCapability(int cap, boolean v) throws TwainException { + TwainCapability tc = getCapability(cap, Twain.MSG_GETCURRENT); + if (tc.booleanValue() != v) { + tc.setCurrentValue(v); + if (getCapability(cap).booleanValue() != v) { + throw new TwainException(getClass().getName() + ".setCapability:\n\tCannot set capability " + cap + " to " + v); + } + } + } + + public void setCapability(int cap, int v) throws TwainException { + TwainCapability tc = getCapability(cap, Twain.MSG_GETCURRENT); + if (tc.intValue() != v) { + tc.setCurrentValue(v); + if (getCapability(cap).intValue() != v) { + throw new TwainException(getClass().getName() + ".setCapability:\n\tCannot set capability " + cap + " to " + v); + } + } + } + + public void setCapability(int cap, double v) throws TwainException { + TwainCapability tc = getCapability(cap, Twain.MSG_GETCURRENT); + if (tc.doubleValue() != v) { + tc.setCurrentValue(v); + if (getCapability(cap).doubleValue() != v) { + throw new TwainException(getClass().getName() + ".setCapability:\n\tCannot set capability " + cap + " to " + v); + } + } + } + + public boolean isUIControllable() { + try { + return getCapability(Twain.CAP_UICONTROLLABLE).booleanValue(); + } catch (Exception e) { + Twain.signalException(getClass().getName() + ".isUIControllable:\n\t" + e); + return false; + } + } + + public boolean isDeviceOnline() { + try { + return getCapability(Twain.CAP_DEVICEONLINE).booleanValue(); + } catch (Exception e) { + Twain.signalException(getClass().getName() + ".isOnline:\n\t" + e); + return true; + } + } + + public void setShowUserInterface(boolean show) throws TwainException { + setShowUI(show); + } + + public void setShowProgressBar(boolean show) throws TwainException { + setCapability(Twain.CAP_INDICATORS, show); + } + + public void setResolution(double dpi) throws TwainException { + setCapability(Twain.ICAP_UNITS, Twain.TWUN_INCHES); + setCapability(Twain.ICAP_XRESOLUTION, dpi); + setCapability(Twain.ICAP_YRESOLUTION, dpi); + } + + public void setRegionOfInterest(int x, int y, int w, int h) throws TwainException { + if ((x == -1) && (y == -1) && (w == -1) && (h == -1)) { + new TwainImageLayout(this).reset(); + } else { + setCapability(Twain.ICAP_UNITS, Twain.TWUN_PIXELS); + TwainImageLayout til = new TwainImageLayout(this); + til.get(); + til.setLeft(x); + til.setTop(y); + til.setRight(x + w); + til.setBottom(y + h); + til.set(); + } + } + + public void setRegionOfInterest(double x, double y, double w, double h) throws TwainException { + if ((x == -1) && (y == -1) && (w == -1) && (h == -1)) { + new TwainImageLayout(this).reset(); + } else { + setCapability(Twain.ICAP_UNITS, Twain.TWUN_CENTIMETERS); + TwainImageLayout til = new TwainImageLayout(this); + til.get(); + til.setLeft(x / 10.0); + til.setTop(y / 10.0); + til.setRight((x + w) / 10.0); + til.setBottom((y + h) / 10.0); + til.set(); + } + } + + public void select(String name) throws TwainException { + checkState(3); + TwainSourceManager manager = Twain.getSourceManager(); + try { + TwainIdentity device = new TwainIdentity(manager); + device.getFirst(); + while (true) { + if (device.getProductName().equals(name)) { + device.identity.copyTo(identity); + break; + } + device.getNext(); + } + } catch (TwainEndOfListException treeol) { + throw new TwainException(getClass().getName() + ".select(String name)\n\tCannot find twain data source: '" + name + "'"); + } + } + + void enable() throws TwainException { + checkState(4); + Twain.negotiateCapabilities(this); + if (getState() < 4) { + return; + } + + int xfer = new TwainCapability.XferMech(this).intValue(); + if (xfer == Twain.TWSX_NATIVE) { + } else if (xfer == Twain.TWSX_FILE) { + try { + iff = getCapability(Twain.ICAP_IMAGEFILEFORMAT).intValue(); + } catch (Exception e) { + iff = Twain.TWFF_BMP; + } + } + +// if (isTwain20()) { +// twSemaphore = new Semaphore(0, true); +// twHaveImage = false; +// } + + modalUI = 0; + Win32Twain.TW_USERINTERFACE ui = new Win32Twain.TW_USERINTERFACE(); + ui.ShowUI = showUI != 0; + ui.hParent = hwnd; + + try { + call(Twain.DG_CONTROL, Twain.DAT_USERINTERFACE, Twain.MSG_ENABLEDS, ui); + modalUI = ui.ModalUI ? 1 : 0; + setState(5); + } catch (TwainCheckStatusException trecs) { + setState(5); + } catch (TwainCancelException trec) { + disable(); + close(); + } + +// if (isTwain20()) { +// try { +// +// new Thread(new Runnable() { +// @Override +// public void run() { +// try { +// twSemaphore.tryAcquire(5, TimeUnit.MINUTES); +// twSemaphore.release(); +// +// if (twHaveImage) { +// transferImage(); +// } else { +//// throw new TwainException("Scan timeout"); +// } +// +// +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// }).start(); +// +// } catch (Exception e) { +// e.printStackTrace(); +// throw new TwainException(e); +// } +// } + } + + private void transfer(TwainTransfer tt) throws TwainException { + try { + byte[] pendingXfers = new byte[6]; + do { + setState(6); + TwainUtils.setINT16(pendingXfers, 0, 0); + try { + tt.setCancel(userCancelled); + tt.initiate(); + } catch (TwainTransferDoneException tretd) { + setState(7); + tt.finish(); + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_ENDXFER, pendingXfers); + if (TwainUtils.getINT16(pendingXfers, 0) == 0) { + setState(5); + } + } catch (TwainUserCancelException tuce) { + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_RESET, pendingXfers); + setState(5); + } catch (TwainCancelException trec) { + tt.cancel(); + + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_ENDXFER, pendingXfers); + if (TwainUtils.getINT16(pendingXfers, 0) > 0) { + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_RESET, pendingXfers); + } + setState(5); + } catch (TwainException tfe) { + Twain.signalException(getClass().getName() + ".transfer:\n\t" + tfe); + + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_ENDXFER, pendingXfers); + if (TwainUtils.getINT16(pendingXfers, 0) > 0) { + call(Twain.DG_CONTROL, Twain.DAT_PENDINGXFERS, Twain.MSG_RESET, pendingXfers); + } + setState(5); + } finally { + tt.cleanup(); + } + } while (TwainUtils.getINT16(pendingXfers, 0) != 0); + } finally { + if (userCancelled || (showUI == 0)) { + userCancelled = false; + disable(); + close(); + } + } + } + + void transferImage() throws TwainException { + switch (getXferMech()) { + case Twain.TWSX_NATIVE: + transfer(transferFactory.createNativeTransfer(this)); + break; + case Twain.TWSX_FILE: + transfer(transferFactory.createFileTransfer(this)); + break; + case Twain.TWSX_MEMORY: + transfer(transferFactory.createMemoryTransfer(this)); + break; + default: + break; + } + } + + void disable() throws TwainException { + if (state < 5) { + return; + } + + byte[] gui = new byte[8]; + TwainUtils.setINT16(gui, 0, -1); + TwainUtils.setINT16(gui, 2, 0); + TwainUtils.setINT32(gui, 4, (int) Pointer.nativeValue(hwnd.getPointer())); + + call(Twain.DG_CONTROL, Twain.DAT_USERINTERFACE, Twain.MSG_DISABLEDS, gui); + setState(4); + } + + @Override + public void close() throws TwainException { + if (state != 4) { + return; + } + +// if (isTwain20()) { +// Win32Twain.TW_CALLBACK cb = new Win32Twain.TW_CALLBACK(); +// cb.Message = 0; +// cb.Proc = null;//new TwainCallback(); +// +// call(Twain.DG_CONTROL, (short) 0x12, (short) 0x902, cb); +// } + super.close(); + busy = false; + setState(3); + } + + int handleGetMessage(Pointer msgPtr) throws TwainException { + if (state < 5) { + return Twain.TWRC_NOTDSEVENT; + } + try { + Win32Twain.TW_EVENT event = new Win32Twain.TW_EVENT(); + event.pEvent = msgPtr; + event.TWMessage = 0; + + call(Twain.DG_CONTROL, Twain.DAT_EVENT, Twain.MSG_PROCESSEVENT, event); + + int message = event.TWMessage; + switch (message) { + case Twain.MSG_XFERREADY: + transferImage(); + break; + case Twain.MSG_CLOSEDSOK: + case Twain.MSG_CLOSEDSREQ: + disable(); + close(); + break; + case Twain.MSG_DEVICEEVENT: + case Twain.MSG_NULL: + default: + break; + } + return Twain.TWRC_DSEVENT; + } catch (TwainNotDSException trendse) { + return Twain.TWRC_NOTDSEVENT; + } + } + + public int getXferMech() throws TwainException { + return new TwainCapability.XferMech(this).intValue(); + } + + public void setXferMech(int mech) { + try { + switch (mech) { + case Twain.TWSX_NATIVE: + case Twain.TWSX_FILE: + case Twain.TWSX_MEMORY: + break; + default: + mech = Twain.TWSX_NATIVE; + break; + } + TwainCapability tc; + tc = getCapability(Twain.ICAP_XFERMECH, Twain.MSG_GETCURRENT); + if (tc.intValue() != mech) { + tc.setCurrentValue(mech); + if (getCapability(Twain.ICAP_XFERMECH).intValue() != mech) { + Twain.signalException(getClass().getName() + ".setXferMech:\n\tCannot change transfer mechanism to mode=" + mech); + } + } + } catch (TwainException e) { + Twain.signalException(getClass().getName() + ".setXferMech:\n\t" + e); + } + } + + public int getImageFileFormat() { + return iff; + } + + public void setImageFileFormat(int iff) { + try { + TwainCapability tc; + switch (iff) { + case Twain.TWFF_TIFF: + case Twain.TWFF_BMP: + case Twain.TWFF_JFIF: + case Twain.TWFF_TIFFMULTI: + case Twain.TWFF_PNG: + break; + default: + iff = Twain.TWFF_BMP; + break; + } + tc = getCapability(Twain.ICAP_IMAGEFILEFORMAT, Twain.MSG_GETCURRENT); + if (tc.intValue() != iff) { + tc.setCurrentValue(iff); + if (getCapability(Twain.ICAP_IMAGEFILEFORMAT).intValue() != iff) { + Twain.signalException(getClass().getName() + ".setImageFileFormat:\n\tCannot change file format to format=" + iff); + } + } + } catch (Exception e) { + Twain.signalException(getClass().getName() + ".setImageFileFormat:\n\t" + e); + } + } + +} diff --git a/src/main/java/org/aohe/core/twain/TwainSourceManager.java b/src/main/java/org/aohe/core/twain/TwainSourceManager.java new file mode 100644 index 0000000..e5ca90f --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainSourceManager.java @@ -0,0 +1,173 @@ +package org.aohe.core.twain; + +import com.sun.jna.platform.win32.WinDef; +import org.aohe.exceptions.TwainEndOfListException; +import org.aohe.exceptions.TwainException; +import org.aohe.exceptions.TwainResultException; +import org.aohe.exceptions.TwainTransferDoneException; +import org.aohe.utils.TwainUtils; +import org.aohe.exceptions.TwainCheckStatusException; +import org.aohe.exceptions.TwainDSException; +import org.aohe.exceptions.TwainNotDSException; +import org.aohe.exceptions.TwainCancelException; + + + +import java.util.List; + + +public class TwainSourceManager { + + public static final String[] INFO = { + "Success", + "Failure due to unknown causes", + "Not enough memory to perform operation", + "No Data Source", + "DS is connected to max possible applications", + "DS or DSM reported internal error", + "Unknown capability", + "", + "", + "Unrecognized MSG DG DAT combination", + "Data parameter out of range", + "DG DAT MSG out of expected sequence", + "Unknown destination Application/Source in DSM_Entry", + "Capability not supported by source", + "Operation not supported by capability", + "Capability has dependancy on other capability", + "File System operation is denied (file is protected)", + "Operation failed because file already exists.", + "File not found", + "Operation failed because directory is not empty", + "The feeder is jammed", + "The feeder detected multiple pages", + "Error writing the file (i.e. disk full conditions)", + "The device went offline prior to or during this operation" + }; + private TwainSource source; + + public TwainSourceManager(WinDef.HWND hwnd) { + source = new TwainSource(this, hwnd, false); + source.getDefault(); + } + + String getConditionCodeStr() throws TwainException { + return INFO[getConditionCode()]; + } + + int getConditionCode() throws TwainException { + byte[] status = new byte[4]; + int rc = Twain.callSourceManager(Twain.DG_CONTROL, Twain.DAT_STATUS, Twain.MSG_GET, status); + if (rc != Twain.TWRC_SUCCESS) { + throw new TwainResultException("Cannot retrieve twain source manager's status. RC = " + rc); + } + return TwainUtils.getINT16(status, 0); + } + + void call(int dg, int id, int msg, Object obj) throws TwainException { + int rc = Twain.callSourceManager(dg, id, msg, obj); + switch (rc) { + case Twain.TWRC_SUCCESS: + return; + case Twain.TWRC_FAILURE: + throw new TwainException(getClass().getName() + ".call error: " + getConditionCodeStr()); + case Twain.TWRC_CHECKSTATUS: + throw new TwainCheckStatusException(); + case Twain.TWRC_CANCEL: + throw new TwainCancelException(); + case Twain.TWRC_DSEVENT: + throw new TwainDSException(); + case Twain.TWRC_NOTDSEVENT: + throw new TwainNotDSException(); + case Twain.TWRC_XFERDONE: + throw new TwainTransferDoneException(); + case Twain.TWRC_ENDOFLIST: + throw new TwainEndOfListException(); + + default: + throw new TwainException("Failed to call source. RC = " + rc); + } + } + + public TwainSource getSource() { + return source; + } + + TwainSource selectSource() throws TwainException { + source.checkState(3); + source.setBusy(true); + try { + source.userSelect(); + return source; + } catch (TwainException trec) { + return source; + } finally { + source.setBusy(false); + } + } + + void getIdentities(List identities) throws TwainException { + source.checkState(3); + source.setBusy(true); + try { + TwainIdentity identity = new TwainIdentity(this); + identity.getFirst(); + identities.add(identity); + while (true) { + identity = new TwainIdentity(this); + identity.getNext(); + identities.add(identity); + } + } catch (TwainEndOfListException treeol) { + } catch (TwainException tioe) { + } finally { + source.setBusy(false); + } + } + + public TwainSource selectSource(String name) throws TwainException { + source.checkState(3); + source.setBusy(true); + try { + source.select(name); + return source; + } finally { + source.setBusy(false); + } + } + + public TwainSource openSource() throws TwainException { + source.checkState(3); + source.setBusy(true); + try { + source.open(); + + if (!source.isDeviceOnline()) { + source.close(); + throw new TwainException("Selected twain source is not online."); + } + + source.setState(4); + return source; + } catch (TwainCancelException trec) { + source.setBusy(false); + return source; + } catch (TwainException tioe) { + source.setBusy(false); + throw tioe; + } + } + + public void closeSource() throws TwainException { + source.checkState(4); + source.setBusy(true); + try { + source.close(); + } catch (TwainCancelException trec) { + source.setBusy(false); + } catch (TwainException tioe) { + source.setBusy(false); + throw tioe; + } + } +} diff --git a/src/main/java/org/aohe/core/twain/TwainTransferFactory.java b/src/main/java/org/aohe/core/twain/TwainTransferFactory.java new file mode 100644 index 0000000..decf7b4 --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainTransferFactory.java @@ -0,0 +1,14 @@ +package org.aohe.core.twain; + + +import org.aohe.transfer.TwainTransfer; + + +public interface TwainTransferFactory { + + TwainTransfer createNativeTransfer(TwainSource source); + + TwainTransfer createFileTransfer(TwainSource source); + + TwainTransfer createMemoryTransfer(TwainSource source); +} diff --git a/src/main/java/org/aohe/core/twain/TwainWndProc.java b/src/main/java/org/aohe/core/twain/TwainWndProc.java new file mode 100644 index 0000000..7dec82b --- /dev/null +++ b/src/main/java/org/aohe/core/twain/TwainWndProc.java @@ -0,0 +1,49 @@ +package org.aohe.core.twain; + +import com.sun.jna.platform.win32.User32; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinUser; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.aohe.core.twain.Twain.callMapper; +import static org.aohe.core.twain.Twain.execute; + + +public class TwainWndProc implements WinUser.WindowProc { + + private ExecutorService exec = Executors.newCachedThreadPool(); + + @Override + public WinDef.LRESULT callback(WinDef.HWND hwnd, int uMsg, final WinDef.WPARAM wParam, WinDef.LPARAM lParam) { + switch (uMsg) { + case WinUser.WM_CLOSE: + case WinUser.WM_DESTROY: + if (hwnd.equals(Twain.hwnd)) { + User32.INSTANCE.DestroyWindow(hwnd); + hwnd = null; + Twain.g_AppID = null; + Twain.done(); + } + break; + case WinUser.WM_USER: { + final Object o = callMapper.get(lParam.intValue()); + if (o != null) { +// exec.submit(new Runnable() { +// @Override +// public void run() { + execute(o, wParam.intValue()); +// } +// }); + + } + + } + break; + default: + return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam); + } + return new WinDef.LRESULT(0); + } +} diff --git a/src/main/java/org/aohe/exceptions/TwainCancelException.java b/src/main/java/org/aohe/exceptions/TwainCancelException.java new file mode 100644 index 0000000..2af37c6 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainCancelException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainCancelException extends TwainResultException { + + public TwainCancelException() { + super("User cancelled twain operation."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainCheckStatusException.java b/src/main/java/org/aohe/exceptions/TwainCheckStatusException.java new file mode 100644 index 0000000..4647a9c --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainCheckStatusException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainCheckStatusException extends TwainResultException { + + public TwainCheckStatusException() { + super("\"Source could not fulfill request."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainDSException.java b/src/main/java/org/aohe/exceptions/TwainDSException.java new file mode 100644 index 0000000..e794a6f --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainDSException.java @@ -0,0 +1,9 @@ +package org.aohe.exceptions; + +public class TwainDSException extends TwainResultException { + + public TwainDSException() { + super("Data source event."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainDataNotAvailableException.java b/src/main/java/org/aohe/exceptions/TwainDataNotAvailableException.java new file mode 100644 index 0000000..3827633 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainDataNotAvailableException.java @@ -0,0 +1,9 @@ +package org.aohe.exceptions; + +public class TwainDataNotAvailableException extends TwainResultException { + + public TwainDataNotAvailableException() { + super("TwainDataNotAvailableException"); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainEndOfListException.java b/src/main/java/org/aohe/exceptions/TwainEndOfListException.java new file mode 100644 index 0000000..50913b8 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainEndOfListException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainEndOfListException extends TwainResultException { + + public TwainEndOfListException() { + super("End of List."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainException.java b/src/main/java/org/aohe/exceptions/TwainException.java new file mode 100644 index 0000000..8f0ec70 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainException.java @@ -0,0 +1,25 @@ +package org.aohe.exceptions; + + +public class TwainException extends Exception { + + public TwainException() { + } + + public TwainException(String message) { + super(message); + } + + public TwainException(String message, Throwable cause) { + super(message, cause); + } + + public TwainException(Throwable cause) { + super(cause); + } + + public TwainException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainInfNotSupportedException.java b/src/main/java/org/aohe/exceptions/TwainInfNotSupportedException.java new file mode 100644 index 0000000..3289177 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainInfNotSupportedException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainInfNotSupportedException extends TwainResultException { + + public TwainInfNotSupportedException() { + super("InfNotSupported."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainNotDSException.java b/src/main/java/org/aohe/exceptions/TwainNotDSException.java new file mode 100644 index 0000000..eb9334e --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainNotDSException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainNotDSException extends TwainResultException { + + public TwainNotDSException() { + super("No data source event."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainResultException.java b/src/main/java/org/aohe/exceptions/TwainResultException.java new file mode 100644 index 0000000..3ca59cc --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainResultException.java @@ -0,0 +1,24 @@ +package org.aohe.exceptions; + +public class TwainResultException extends TwainException { + + public TwainResultException() { + } + + public TwainResultException(String message) { + super(message); + } + + public TwainResultException(String message, Throwable cause) { + super(message, cause); + } + + public TwainResultException(Throwable cause) { + super(cause); + } + + public TwainResultException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainTransferDoneException.java b/src/main/java/org/aohe/exceptions/TwainTransferDoneException.java new file mode 100644 index 0000000..a24b965 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainTransferDoneException.java @@ -0,0 +1,10 @@ +package org.aohe.exceptions; + + +public class TwainTransferDoneException extends TwainResultException { + + public TwainTransferDoneException() { + super("Image transfer done."); + } + +} diff --git a/src/main/java/org/aohe/exceptions/TwainUserCancelException.java b/src/main/java/org/aohe/exceptions/TwainUserCancelException.java new file mode 100644 index 0000000..7ef1d56 --- /dev/null +++ b/src/main/java/org/aohe/exceptions/TwainUserCancelException.java @@ -0,0 +1,9 @@ +package org.aohe.exceptions; + +public class TwainUserCancelException extends TwainResultException { + + public TwainUserCancelException() { + super("User cancelled twain operation."); + } + +} diff --git a/src/main/java/org/aohe/libs/Kernel32.java b/src/main/java/org/aohe/libs/Kernel32.java new file mode 100644 index 0000000..2a40a75 --- /dev/null +++ b/src/main/java/org/aohe/libs/Kernel32.java @@ -0,0 +1,140 @@ +package org.aohe.libs; + +import com.sun.jna.Library; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.ptr.IntByReference; + +import java.util.Arrays; +import java.util.List; + + +public interface Kernel32 extends Library { + + boolean Beep(int freq, int duration); + + int GetCurrentDirectoryA(int bufLen, byte buffer[]); + + boolean SetCurrentDirectoryA(String dir); + + int GetLastError(); + + int GetCurrentProcess(); + + int GetCurrentProcessId(); + + int GetTickCount(); + + int LoadLibraryA(String lib); + + Pointer GlobalLock(Pointer hdl); + + boolean GlobalUnlock(Pointer hdl); + + Pointer GlobalLock(int hdl); + + boolean GlobalUnlock(int hdl); + + Pointer GlobalAlloc(int flags, int size); + + int GlobalFree(Pointer hdl); + + int GlobalFree(int hdl); + + int GetLogicalDrives(); + + int GetLogicalDriveStringsA(int bufLen, byte buf[]); + + boolean GetVolumeInformationA(String lpRootPathName, byte lpVolumeNameBuffer[], int nVolumeNameSize, int lpVolumeSerialNumber[], int lpMaximumComponentLength[], int lpFileSystemFlags[], byte lpFileSystemNameBuffer[], int nFileSystemNameSize); + + int GetDriveTypeA(String drive); + + void GetSystemTime(SYSTEMTIME st); + + void GetLocalTime(SYSTEMTIME st); + + void GetComputerName(); + + boolean GetProcessTimes(int processHdl, FILETIME creation, FILETIME exit, FILETIME kernel, FILETIME user); + + boolean GetSystemTimes(FILETIME idle, FILETIME kernel, FILETIME user); + + int CreateFileA(String file, int access, int mode, SECURITY_ATTRIBUTES secAttrs, int disposition, int flagsAndAttribs, int hdlTemplate); + + boolean DeviceIoControl(int hdl, int opCode, byte inBuf[], int inBufSize, byte outBuf[], int outBufSize, int bytesReturned[], OVERLAPPED ol); + + boolean GetSystemPowerStatus(SYSTEM_POWER_STATUS sps); + + boolean GetDiskFreeSpaceA(String s, IntByReference r1, IntByReference r2, IntByReference r3, IntByReference r4); + + boolean GetDiskFreeSpaceEx(String s, IntByReference r1, IntByReference r2, IntByReference r3); + + public static class SYSTEMTIME extends Structure { + + public short wYear; + public short wMonth; + public short wDayOfWeek; + public short wDay; + public short wHour; + public short wMinute; + public short wSecond; + public short wMilliseconds; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"wYear", "wMonth", "wDayOfWeek", "wDay", "wHour", "wMinute", "wSecond", "wMilliseconds"}); + } + } + + public static class SYSTEM_POWER_STATUS extends Structure { + + public byte ACLineStatus; + public byte BatteryFlag; + public byte BatteryLifePercent; + public byte Reserved1; + public int BatteryLifeTime; + public int BatteryFullLifeTime; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"ACLineStatus", "BatteryFlag", "BatteryLifePercent", "Reserved1", "BatteryLifeTime", "BatteryFullLifeTime"}); + } + } + + public static class OVERLAPPED extends Structure { + + int Internal; + int InternalHigh; + int Offset; + int OffsetHigh; + int hEvent; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Internal", "InternalHigh", "Offset", "OffsetHigh", "hEvent"}); + } + } + + public static class SECURITY_ATTRIBUTES extends Structure { + + int nLength; + Pointer lpSecurityDescriptor; + boolean bInheritHandle; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"nLength", "lpSecurityDescriptor", "bInheritHandle"}); + } + } + + public static class FILETIME extends Structure { + + public int dwLowDateTime; + public int dwHighDateTime; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"dwLowDateTime", "dwHighDateTime"}); + } + } +} diff --git a/src/main/java/org/aohe/libs/User32.java b/src/main/java/org/aohe/libs/User32.java new file mode 100644 index 0000000..2d2ac1a --- /dev/null +++ b/src/main/java/org/aohe/libs/User32.java @@ -0,0 +1,94 @@ +package org.aohe.libs; + +import com.sun.jna.*; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinUser; + +import java.util.Arrays; +import java.util.List; + + +public interface User32 extends Library { + + boolean MessageBeep(int uType); + + WinDef.HWND CreateWindowExA(int styleEx, String className, String windowName, int style, int x, int y, int width, int height, int hndParent, int hndMenu, int hndInst, Object parm); + + boolean SetWindowPos(WinDef.HWND hWnd, int hWndInsAfter, int x, int y, int cx, int cy, short uFlgs); + + boolean SetWindowPos(WinDef.HWND hWnd, WinDef.HWND hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags); + + WinDef.ATOM RegisterClassEx(WinUser.WNDCLASSEX lpwcx); + + int DestroyWindow(int hdl); + + int DestroyWindow(WinDef.HWND hdl); + + boolean GetMessageA(MSG lpMsg, int hWnd, int wMsgFilterMin, int wMsgFilterMax); + + boolean TranslateMessage(MSG lpMsg); + + int DispatchMessageA(MSG lpMsg); + + void PostMessage(WinDef.HWND hWnd, int msg, WinDef.WPARAM wParam, WinDef.LPARAM lParam); + + public static class POINT extends Structure { + + public int x; + public int y; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"x", "y"}); + } + } + + public static class MSG extends Structure { + + public int hwnd; + public int message; + public short wParm; + public int lParm; + public int time; + public POINT pt; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"hwnd", "message", "wParm", "lParm", "time", "pt"}); + } + } + public static HANDLE INVALID_HANDLE_VALUE = new HANDLE(Pointer.createConstant(Pointer.SIZE == 8 ? -1 : 0xFFFFFFFFL)); + + public static class HANDLE extends PointerType { + + private boolean immutable; + + public HANDLE() { + } + + public HANDLE(Pointer p) { + setPointer(p); + immutable = true; + } + + @Override + public Object fromNative(Object nativeValue, FromNativeContext context) { + Object o = super.fromNative(nativeValue, context); + if (INVALID_HANDLE_VALUE.equals(o)) { + return INVALID_HANDLE_VALUE; + } + return o; + } + + @Override + public void setPointer(Pointer p) { + if (immutable) { + throw new UnsupportedOperationException("immutable reference"); + } + + super.setPointer(p); + } + + } + +} diff --git a/src/main/java/org/aohe/libs/Win32Twain.java b/src/main/java/org/aohe/libs/Win32Twain.java new file mode 100644 index 0000000..599c03f --- /dev/null +++ b/src/main/java/org/aohe/libs/Win32Twain.java @@ -0,0 +1,280 @@ +package org.aohe.libs; + +import com.sun.jna.Callback; +import com.sun.jna.Library; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.platform.win32.WinDef; + +import java.util.Arrays; +import java.util.List; + + +public interface Win32Twain extends Library { + + public short DSM_Entry(TW_IDENTITY origin, TW_IDENTITY destination, int dg, short dat, short msg, Object p); + + public Pointer DSM_Alloc(int len); + + public void DSM_Free(Pointer handle); + + public Pointer DSM_Lock(Pointer handle); + + public boolean DSM_Unlock(Pointer handle); + + public static class TW_CALLBACK extends Structure { + + public Callback Proc; + public int RefCon; + public short Message; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Proc", "RefCon", "Message"}); + } + } + + public static class TW_STATUS extends Structure { + + public short ConditionCode; + public short Reserved; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"ConditionCode", "Reserved"}); + } + } + + public static class TW_CAPABILITY extends Structure { + + public short Cap; + public short ConType; + public Long Container; + public int reserved; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Cap", "ConType", "Container", "reserved"}); + } + + } + + public static class TW_VERSION extends Structure implements Structure.ByValue { + + public short MajorNum; + public short MinorNum; + public short Language; + public short Country; + public byte Info[] = new byte[34]; + + public TW_VERSION(int align) { + super(); + setAlignType(align); + } + + public TW_VERSION() { + super(); + setAlignType(Structure.ALIGN_NONE); + } + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"MajorNum", "MinorNum", "Language", "Country", "Info"}); + } + + public void setInfo(String m) { + byte[] mb = m.getBytes(); + for (int i = 0; i < Math.min(32, mb.length); ++i) { + Info[i] = mb[i]; + } + } + + public String getInfo() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 32; ++i) { + if (Info[i] == 0) { + break; + } + sb.append((char) Info[i]); + } + return sb.toString(); + } + + } + + public static class TW_IDENTITY extends Structure { + + public int Id; + public TW_VERSION Version = new TW_VERSION(); + public short ProtocolMajor; + public short ProtocolMinor; + public int SupportedGroups; + public byte Manufacturer[] = new byte[34]; + public byte ProductFamily[] = new byte[34]; + public byte ProductName[] = new byte[34]; + + public TW_IDENTITY(int align) { + super(); + setAlignType(align); + } + + public TW_IDENTITY() { + super(); + setAlignType(Structure.ALIGN_NONE); + } + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Id", "Version", "ProtocolMajor", "ProtocolMinor", "SupportedGroups", "Manufacturer", "ProductFamily", "ProductName"}); + } + + public void setManufacturer(String m) { + byte mb[] = m.getBytes(); + for (int i = 0; i < Math.min(32, mb.length); ++i) { + Manufacturer[i] = mb[i]; + } + } + + public String getManufacturer() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 32; ++i) { + if (Manufacturer[i] == 0) { + break; + } + sb.append((char) Manufacturer[i]); + } + return sb.toString(); + } + + public void setProductFamily(String m) { + byte mb[] = m.getBytes(); + for (int i = 0; i < Math.min(32, mb.length); ++i) { + ProductFamily[i] = mb[i]; + } + } + + public String getProductFamily() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 32; ++i) { + if (ProductFamily[i] == 0) { + break; + } + sb.append((char) ProductFamily[i]); + } + return sb.toString(); + } + + public void setProductName(String m) { + byte mb[] = m.getBytes(); + for (int i = 0; i < Math.min(32, mb.length); ++i) { + ProductName[i] = mb[i]; + } + } + + public String getProductName() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 32; ++i) { + if (ProductName[i] == 0) { + break; + } + sb.append((char) ProductName[i]); + } + return sb.toString(); + } + + public void copyTo(TW_IDENTITY identity) { + identity.Id = Id; + + System.arraycopy(Manufacturer, 0, identity.Manufacturer, 0, Manufacturer.length); + System.arraycopy(ProductFamily, 0, identity.ProductFamily, 0, ProductFamily.length); + System.arraycopy(ProductName, 0, identity.ProductName, 0, ProductName.length); + + System.arraycopy(Version.Info, 0, identity.Version.Info, 0, Version.Info.length); + identity.Version.Country = Version.Country; + identity.Version.Language = Version.Language; + identity.Version.MajorNum = Version.MajorNum; + identity.Version.MinorNum = Version.MinorNum; + + identity.ProtocolMajor = ProtocolMajor; + identity.ProtocolMinor = ProtocolMinor; + identity.SupportedGroups = SupportedGroups; + } + + } + + public static class TW_FIX32 extends Structure { + + public short Whole; + public short Frac; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Whole", "Frac"}); + } + } + + public static class TW_USERINTERFACE extends Structure { + + public boolean ShowUI; + public boolean ModalUI; + public WinDef.HWND hParent; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"ShowUI", "ModalUI", "hParent"}); + } + } + + public static class TW_PENDINGXFERS extends Structure { + + public int EOJ; + public int Reserved; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"EOJ", "Reserved"}); + } + } + + public static class TW_EVENT extends Structure { + + public Pointer pEvent; + public short TWMessage; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"pEvent", "TWMessage"}); + } + } + + public static class TW_MEMORY extends Structure { + + public int Flags; + public int Length; + public Pointer TheMem; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Flags", "Length", "TheMem"}); + } + } + + public static class TW_IMAGEMEMXFER extends Structure implements Structure.ByValue { + + public short Compression; + public int BytesPerRow; + public int Columns; + public int Rows; + public int XOffset; + public int YOffset; + public int BytesWritten; + public TW_MEMORY Memory; + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[]{"Compression", "BytesPerRow", "Columns", "Rows", "XOffset", "YOffset", "BytesWritten", "Memory"}); + } + + } + +} diff --git a/src/main/java/org/aohe/result/R.java b/src/main/java/org/aohe/result/R.java new file mode 100644 index 0000000..3621a17 --- /dev/null +++ b/src/main/java/org/aohe/result/R.java @@ -0,0 +1,39 @@ +package org.aohe.result; + +import cn.hutool.json.JSONUtil; +import lombok.Data; + +@Data +public class R { + + private String code; + + private String msg; + + private T data; + + private boolean success; + + public R (String code, String msg, T data, boolean success) { + this.code = code; + this.msg = msg; + this.data = data; + this.success = success; + } + + public static R ok(Object data) { + return new R<>("200", "ok", data, true); + } + + public static R ok() { + return new R<>("200", "ok", null, true); + } + + public static R fail(String msg) { + return new R<>("500", msg, null, false); + } + + public String toJsonStr() { + return JSONUtil.toJsonStr(this); + } +} diff --git a/src/main/java/org/aohe/scan/Source.java b/src/main/java/org/aohe/scan/Source.java new file mode 100644 index 0000000..62f1867 --- /dev/null +++ b/src/main/java/org/aohe/scan/Source.java @@ -0,0 +1,189 @@ +package org.aohe.scan; + +import org.aohe.core.twain.*; +import org.aohe.exceptions.TwainException; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + + +public class Source implements TwainListener { + + private double dpi = 300.0; + private ColorMode color = ColorMode.GRAYSCALE; + private boolean autoDocumentFeeder = true; + private boolean systemUI = true; + + private String name; + + private final Object syncObject = new Object(); + private ExecutorService exec; + + private List fileList = new ArrayList<>(); + + public Source() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getDpi() { + return dpi; + } + + public void setDpi(double dpi) { + this.dpi = dpi; + } + + public ColorMode getColor() { + return color; + } + + public void setColor(ColorMode color) { + this.color = color; + } + + public boolean isAutoDocumentFeeder() { + return autoDocumentFeeder; + } + + public void setAutoDocumentFeeder(boolean autoDocumentFeeder) { + this.autoDocumentFeeder = autoDocumentFeeder; + } + + public boolean isSystemUI() { + return systemUI; + } + + public void setSystemUI(boolean systemUI) { + this.systemUI = systemUI; + } + + @Override + public void update(TwainIOMetadata.Type type, TwainIOMetadata metadata) { +// System.out.println(type + " -> " + metadata.getState() + ": " + metadata.getStateStr()); + if (type == TwainIOMetadata.NEGOTIATE && metadata.getState() == 4) { + setupSource(metadata.getSource()); + } else if (type == TwainIOMetadata.ACQUIRED && metadata.getState() == 7) { + pushImage(metadata.getImage()); + metadata.setImage(null); + } else if (type == TwainIOMetadata.STATECHANGE && metadata.getState() == 3 && metadata.getLastState() == 4) { + jobDone(); + } + } + + private void setupSource(TwainSource source) { + try { + //source.setShowProgressBar(true); + source.setShowUI(systemUI); + source.setImageFileFormat(7); + if (!systemUI) { +// source.setShowUI(false); + source.setResolution(dpi); + TwainCapability pt = source.getCapability(Twain.ICAP_PIXELTYPE); + switch (color) { + case BW: + pt.setCurrentValue(0); + break; + case GRAYSCALE: + pt.setCurrentValue(1); + break; + case COLOR: + pt.setCurrentValue(2); + break; + } + + source.setCapability(Twain.CAP_FEEDERENABLED, autoDocumentFeeder ? 1 : 0); + } + } catch (TwainException e) { + e.printStackTrace(); + } + } + + private void pushImage(final BufferedImage image) { + exec.submit(() -> { + try { + File f = File.createTempFile("img", ".jpg"); + ImageIO.write(image, "JPG", f); + fileList.add(f); + } catch (IOException ignored) { + + } + }); + } + + private void jobDone() { + exec.shutdown(); + try { + while (!exec.awaitTermination(100, TimeUnit.MILLISECONDS)) { + } + } catch (InterruptedException ex) { + } + + synchronized (syncObject) { + syncObject.notifyAll(); + } + + exec = null; + } + + public List scan() { + exec = Executors.newFixedThreadPool(1); + + TwainScanner scanner = TwainScanner.getScanner(); + + try { + scanner.select(name);// + scanner.addListener(this); + scanner.acquire(); + + synchronized (syncObject) { + syncObject.wait(); + } + + } catch (TwainException | InterruptedException e) { + } + + return fileList; + } + + public List scan(TwainScanner scanner) { + exec = Executors.newFixedThreadPool(1); + + try { + + systemUI = false; + + scanner.addListener(this); + scanner.acquire(); + + synchronized (syncObject) { + syncObject.wait(); + } + + } catch (TwainException | InterruptedException e) { + } + + return fileList; + } + + public static enum ColorMode { + BW, + GRAYSCALE, + COLOR + } + +} diff --git a/src/main/java/org/aohe/scan/SourceManager.java b/src/main/java/org/aohe/scan/SourceManager.java new file mode 100644 index 0000000..a972286 --- /dev/null +++ b/src/main/java/org/aohe/scan/SourceManager.java @@ -0,0 +1,39 @@ +package org.aohe.scan; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainScanner; +import org.aohe.exceptions.TwainException; + +import java.util.ArrayList; +import java.util.List; + +public class SourceManager { + + private static SourceManager instance; + + public static SourceManager instance() { + if (instance == null) { + instance = new SourceManager(); + } + return instance; + } + + public List getSources() throws TwainException { + List ret = new ArrayList<>(); + + for (String s : TwainScanner.getScanner().getDeviceNames()) { + Source source = new Source(); + source.setName(s); + + ret.add(source); + } + + return ret; + } + + public void freeResources() { + Twain.done(); + } + +} diff --git a/src/main/java/org/aohe/transfer/TwainFileTransfer.java b/src/main/java/org/aohe/transfer/TwainFileTransfer.java new file mode 100644 index 0000000..690be8a --- /dev/null +++ b/src/main/java/org/aohe/transfer/TwainFileTransfer.java @@ -0,0 +1,76 @@ +package org.aohe.transfer; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainSource; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +import java.io.File; + + +public class TwainFileTransfer extends TwainTransfer { + + protected File file; + + public TwainFileTransfer(TwainSource source) { + super(source); + file = null; + } + + protected int getImageFileFormat() { + return source.getImageFileFormat(); + } + + public void setFile(File f) { + file = f; + } + + public File getFile() { + if (file == null) { + String ext = Twain.ImageFileFormatExts[getImageFileFormat()]; + try { + File dir = new File(System.getProperty("user.home"), "mmsc/tmp"); + dir.mkdirs(); + file = File.createTempFile("mmsctwain", ext, dir); + } catch (Exception e) { + file = new File("c:\\mmsctwain." + ext); + } + } + return file; + } + + @Override + public void initiate() throws TwainException { + super.initiate(); + + String file = getFile().getPath(); + int iff = getImageFileFormat(); + + byte[] setup = new byte[260]; + TwainUtils.setString(setup, 0, file); + TwainUtils.setINT16(setup, 256, iff); + TwainUtils.setINT16(setup, 258, 0); + + source.call(Twain.DG_CONTROL, Twain.DAT_SETUPFILEXFER, Twain.MSG_SET, setup); + source.call(Twain.DG_IMAGE, Twain.DAT_IMAGEFILEXFER, Twain.MSG_GET, null); + } + + @Override + public void finish() throws TwainException { + Twain.transferFileImage(file); + } + + @Override + public void cancel() throws TwainException { + if ((file != null) && file.exists()) { + file.delete(); + } + } + + @Override + public void cleanup() throws TwainException { + setFile(null); + } + +} diff --git a/src/main/java/org/aohe/transfer/TwainMemoryTransfer.java b/src/main/java/org/aohe/transfer/TwainMemoryTransfer.java new file mode 100644 index 0000000..443e716 --- /dev/null +++ b/src/main/java/org/aohe/transfer/TwainMemoryTransfer.java @@ -0,0 +1,107 @@ +package org.aohe.transfer; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainSource; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + + +public class TwainMemoryTransfer extends TwainTransfer { + + private final byte[] imx = new byte[48]; + private Info info; + + protected int minBufSize = -1; + protected int maxBufSize = -1; + protected int preferredSize = -1; + + public TwainMemoryTransfer(TwainSource source) { + super(source); + } + + protected void retrieveBufferSizes() throws TwainException { + byte[] setup = new byte[12]; + TwainUtils.setINT32(setup, 0, minBufSize); + TwainUtils.setINT32(setup, 4, maxBufSize); + TwainUtils.setINT32(setup, 8, preferredSize); + source.call(Twain.DG_CONTROL, Twain.DAT_SETUPMEMXFER, Twain.MSG_GET, setup); + minBufSize = TwainUtils.getINT32(setup, 0); + maxBufSize = TwainUtils.getINT32(setup, 4); + preferredSize = TwainUtils.getINT32(setup, 8); + } + + @Override + public void initiate() throws TwainException { + super.initiate(); + retrieveBufferSizes(); + Twain.nnew(imx, preferredSize); + byte[] buf = new byte[preferredSize]; + info = new Info(imx, buf); + while (true) { + source.call(Twain.DG_IMAGE, Twain.DAT_IMAGEMEMXFER, Twain.MSG_GET, imx); + int bytesWritten = TwainUtils.getINT32(imx, 22); + int bytesCopied = Twain.ncopy(buf, imx, bytesWritten); + if (bytesCopied == bytesWritten) { + Twain.transferMemoryBuffer(info); + } + } + } + + @Override + public void finish() throws TwainException { + int bytesWritten = TwainUtils.getINT32(imx, 22); + int bytesCopied = Twain.ncopy(info.getBuffer(), imx, bytesWritten); + Twain.transferMemoryBuffer(info); + } + + @Override + public void cleanup() throws TwainException { + Twain.ndelete(imx); + } + + public static class Info { + + private byte[] imx; + private byte[] buf; + private int len; + + Info(byte[] imx, byte[] buf) { + this.imx = imx; + this.buf = buf; + } + + public byte[] getBuffer() { + return buf; + } + + public int getCompression() { + return TwainUtils.getINT16(imx, 0); + } + + public int getBytesPerRow() { + return TwainUtils.getINT32(imx, 2); + } + + public int getWidth() { + return TwainUtils.getINT32(imx, 6); + } + + public int getHeight() { + return TwainUtils.getINT32(imx, 10); + } + + public int getTop() { + return TwainUtils.getINT32(imx, 14); + } + + public int getLeft() { + return TwainUtils.getINT32(imx, 18); + } + + public int getLength() { + return TwainUtils.getINT32(imx, 22); + } + + } +} diff --git a/src/main/java/org/aohe/transfer/TwainNativeTransfer.java b/src/main/java/org/aohe/transfer/TwainNativeTransfer.java new file mode 100644 index 0000000..24416e2 --- /dev/null +++ b/src/main/java/org/aohe/transfer/TwainNativeTransfer.java @@ -0,0 +1,33 @@ +package org.aohe.transfer; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainSource; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +/** + * + * @author lucifer + */ +public class TwainNativeTransfer extends TwainTransfer { + + private final byte[] imageHandle = new byte[8]; + + public TwainNativeTransfer(TwainSource source) { + super(source); + } + + @Override + public void initiate() throws TwainException { + super.initiate(); + source.call(Twain.DG_IMAGE, Twain.DAT_IMAGENATIVEXFER, Twain.MSG_GET, imageHandle); + } + + @Override + public void finish() throws TwainException { + int handle = TwainUtils.getINT32(imageHandle, 0); + Twain.transferNativeImage(handle); + } + +} diff --git a/src/main/java/org/aohe/transfer/TwainTransfer.java b/src/main/java/org/aohe/transfer/TwainTransfer.java new file mode 100644 index 0000000..19c3b0e --- /dev/null +++ b/src/main/java/org/aohe/transfer/TwainTransfer.java @@ -0,0 +1,42 @@ +package org.aohe.transfer; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainSource; +import org.aohe.exceptions.TwainException; +import org.aohe.exceptions.TwainUserCancelException; + + +public class TwainTransfer { + + protected TwainSource source; + protected boolean isCancelled; + + public TwainTransfer(TwainSource source) { + this.source = source; + isCancelled = false; + } + + public void initiate() throws TwainException { + commitCancel(); + } + + public void setCancel(boolean isCancelled) { + this.isCancelled = isCancelled; + } + + protected void commitCancel() throws TwainException { + if (isCancelled && (source.getState() == Twain.STATE_TRANSFERREADY)) { + throw new TwainUserCancelException(); + } + } + + public void finish() throws TwainException { + } + + public void cancel() throws TwainException { + } + + public void cleanup() throws TwainException { + } +} diff --git a/src/main/java/org/aohe/utils/TwainUtils.java b/src/main/java/org/aohe/utils/TwainUtils.java new file mode 100644 index 0000000..8a6c99e --- /dev/null +++ b/src/main/java/org/aohe/utils/TwainUtils.java @@ -0,0 +1,64 @@ +package org.aohe.utils; + + +import org.aohe.core.twain.Twain; +import org.aohe.core.twain.TwainScanner; +import org.aohe.core.twain.TwainSource; +import org.aohe.exceptions.TwainException; + + +public class TwainUtils { + + public static int getINT16(byte[] buf, int off) { + return (buf[off++] & 0x00FF) | (buf[off] << 8); + } + + public static void setINT16(byte[] buf, int off, int i) { + buf[off++] = (byte) i; + buf[off++] = (byte) (i >> 8); + } + + public static int getINT32(byte[] buf, int off) { + return (buf[off++] & 0x00FF) | ((buf[off++] & 0x00FF) << 8) | ((buf[off++] & 0x00FF) << 16) | (buf[off] << 24); + } + + public static void setINT32(byte[] buf, int off, int i) { + buf[off++] = (byte) i; + buf[off++] = (byte) (i >> 8); + buf[off++] = (byte) (i >> 16); + buf[off++] = (byte) (i >> 24); + } + + public static long getINT64(byte[] buf, int off) { + return (buf[off++] & 0x00FF) | ((buf[off++] & 0x00FF) << 8) | ((buf[off++] & 0x00FF) << 16) | ((buf[off++] & 0x00FF) << 24) + | ((buf[off++] & 0x00FF) << 32) | ((buf[off++] & 0x00FF) << 40) | ((buf[off++] & 0x00FF) << 48) | (buf[off] << 56); + } + + public static void setINT64(byte[] buf, int off, long i) { + buf[off++] = (byte) i; + buf[off++] = (byte) (i >> 8); + buf[off++] = (byte) (i >> 16); + buf[off++] = (byte) (i >> 24); + buf[off++] = (byte) (i >> 32); + buf[off++] = (byte) (i >> 40); + buf[off++] = (byte) (i >> 48); + buf[off++] = (byte) (i >> 56); + } + + public static double getFIX32(byte[] buf, int off) { + int whole = ((buf[off++] & 0x00FF) | (buf[off++] << 8)); + int frac = ((buf[off++] & 0x00FF) | ((buf[off] & 0x00FF) << 8)); + return ((double) whole) + ((double) frac) / 65536.0; + } + + public static void setFIX32(byte[] buf, int off, double d) { + int value = (int) (d * 65536.0 + ((d < 0) ? (-0.5) : 0.5)); + setINT16(buf, off, value >> 16); + setINT16(buf, off + 2, value & 0x0000FFFF); + } + + public static void setString(byte[] buf, int off, String s) { + System.arraycopy(s.getBytes(), 0, buf, 0, s.length()); + } + +} diff --git a/src/main/java/org/aohe/variable/TwainArray.java b/src/main/java/org/aohe/variable/TwainArray.java new file mode 100644 index 0000000..4901f26 --- /dev/null +++ b/src/main/java/org/aohe/variable/TwainArray.java @@ -0,0 +1,70 @@ +package org.aohe.variable; + +import java.util.ArrayList; +import java.util.List; + +import org.aohe.core.twain.Twain; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +public class TwainArray extends TwainContainer { + + int count; + List items = new ArrayList<>(); + + public TwainArray(int cap, byte[] container) { + super(cap, container); + count = TwainUtils.getINT32(container, 2); + + for (int i = 0, off = 6; i < count; i++) { + items.add(getObjectAt(container, off)); + off += TYPE_SIZES[type]; + } + } + + @Override + public int getType() { + return Twain.TWON_ARRAY; + } + + @Override + public byte[] getBytes() { + int count = items.size(); + int len = 6 + count * TYPE_SIZES[type]; + byte[] container = new byte[len]; + TwainUtils.setINT16(container, 0, type); + TwainUtils.setINT32(container, 2, count); + + for (int i = 0, off = 6; i < count; i++) { + setObjectAt(container, off, items.get(i)); + off += TYPE_SIZES[type]; + } + return container; + } + + @Override + public Object getCurrentValue() throws TwainException { + throw new TwainException(getClass().getName() + ".getCurrentValue:\n\tnot applicable"); + } + + @Override + public void setCurrentValue(Object obj) throws TwainException { + throw new TwainException(getClass().getName() + ".setCurrentValue:\n\tnot applicable"); + } + + @Override + public Object getDefaultValue() throws TwainException { + throw new TwainException(getClass().getName() + ".getDefaultValue:\n\tnot applicable"); + } + + @Override + public void setDefaultValue(Object obj) throws TwainException { + throw new TwainException(getClass().getName() + ".setDefaultValue:\n\tnot applicable"); + } + + @Override + public T[] getItems() { + return (T[]) items.toArray(); + } + +} diff --git a/src/main/java/org/aohe/variable/TwainContainer.java b/src/main/java/org/aohe/variable/TwainContainer.java new file mode 100644 index 0000000..dc499b6 --- /dev/null +++ b/src/main/java/org/aohe/variable/TwainContainer.java @@ -0,0 +1,295 @@ +/* + * Copyright 2018 (c) Denis Andreev (lucifer). + * + * 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 org.aohe.variable; + +import org.aohe.core.twain.Twain; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +import java.awt.geom.Rectangle2D; + +public abstract class TwainContainer { + + public static final int[] TYPE_SIZES = { + 1, 2, 4, + 1, 2, 4, + 2, 4, 16, + 34, 66, 130, 256, + 1026, 1024 + }; + protected int cap; + protected int type; + + TwainContainer(int cap, byte[] container) { + this.cap = cap; + this.type = TwainUtils.getINT16(container, 0); + } + + TwainContainer(int cap, int type) { + this.cap = cap; + this.type = type; + } + + public int getCapabilityId() { + return cap; + } + + public abstract int getType(); + + public abstract byte[] getBytes(); + + public int getItemType() { + return type; + } + + abstract public T[] getItems(); + + private boolean booleanValue(Object obj) throws TwainException { + if (obj instanceof Number) { + return (((Number) obj).intValue() != 0); + } else if (obj instanceof Boolean) { + return ((Boolean) obj).booleanValue(); + } else if (obj instanceof String) { + return Boolean.valueOf((String) obj).booleanValue(); + } + throw new TwainException(getClass().getName() + ".booleanValue:\n\tUnsupported data type: " + obj.getClass().getName()); + } + + private int intValue(Object obj) throws TwainException { + if (obj instanceof Number) { + return ((Number) obj).intValue(); + } else if (obj instanceof Boolean) { + return ((((Boolean) obj).booleanValue()) ? 1 : 0); + } else if (obj instanceof String) { + String s = (String) obj; + try { + return Integer.parseInt(s); + } catch (Exception e) { + throw new TwainException(getClass().getName() + ".intValue:\n\tCannot convert string [\"" + s + "\"] to int."); + } + } + throw new TwainException(getClass().getName() + ".intValue:\n\tUnsupported data type: " + obj.getClass().getName()); + } + + private double doubleValue(Object obj) throws TwainException { + if (obj instanceof Number) { + return ((Number) obj).doubleValue(); + } else if (obj instanceof Boolean) { + return ((((Boolean) obj).booleanValue()) ? 1 : 0); + } else if (obj instanceof String) { + String s = (String) obj; + try { + return Double.parseDouble(s); + } catch (Exception e) { + throw new TwainException(getClass().getName() + ".doubleValue:\n\tCannot convert string [\"" + s + "\"] to double."); + } + } + throw new TwainException(getClass().getName() + ".doubleValue:\n\tUnsupported data type: " + obj.getClass().getName()); + } + + abstract public Object getCurrentValue() throws TwainException; + + public boolean booleanValue() throws TwainException { + return booleanValue(getCurrentValue()); + } + + public int intValue() throws TwainException { + return intValue(getCurrentValue()); + } + + public double doubleValue() throws TwainException { + return doubleValue(getCurrentValue()); + } + + abstract public void setCurrentValue(Object v) throws TwainException; + + public void setCurrentValue(boolean v) throws TwainException { + setCurrentValue(new Boolean(v)); + } + + public void setCurrentValue(int v) throws TwainException { + setCurrentValue(new Integer(v)); + } + + public void setCurrentValue(double v) throws TwainException { + setCurrentValue(new Double(v)); + } + + abstract public Object getDefaultValue() throws TwainException; + + public boolean booleanDefaultValue() throws TwainException { + return booleanValue(getDefaultValue()); + } + + public int intDefaultValue() throws TwainException { + return intValue(getDefaultValue()); + } + + public double doubleDefaultValue() throws TwainException { + return doubleValue(getDefaultValue()); + } + + abstract public void setDefaultValue(Object v) throws TwainException; + + public void setDefaultValue(boolean v) throws TwainException { + setDefaultValue(new Boolean(v)); + } + + public void setDefaultValue(int v) throws TwainException { + setDefaultValue(new Integer(v)); + } + + public void setDefaultValue(double v) throws TwainException { + setDefaultValue(new Double(v)); + } + + protected Object get32BitObjectAt(byte[] container, int index) { + switch (type) { + case Twain.TWTY_INT8: + case Twain.TWTY_INT16: + case Twain.TWTY_INT32: + return TwainUtils.getINT32(container, index); + case Twain.TWTY_UINT8: + return TwainUtils.getINT32(container, index) & 0x000000FF; + case Twain.TWTY_UINT16: + return TwainUtils.getINT32(container, index) & 0x0000FFFF; + case Twain.TWTY_UINT32: + return ((long) TwainUtils.getINT32(container, index)) & 0x00000000FFFFFFFFL; + case Twain.TWTY_BOOL: + return (TwainUtils.getINT32(container, index) != 0); + case Twain.TWTY_FIX32: + return TwainUtils.getFIX32(container, index); + + case Twain.TWTY_FRAME: + case Twain.TWTY_STR32: + case Twain.TWTY_STR64: + case Twain.TWTY_STR128: + case Twain.TWTY_STR255: + case Twain.TWTY_STR1024: + case Twain.TWTY_UNI512: + return TwainUtils.getINT32(container, index); + default: + } + return null; + } + + protected void set32BitObjectAt(byte[] container, int index, Object item) { + if (item instanceof Integer) { + int v = ((Integer) item); + switch (type) { + case Twain.TWTY_FIX32: + TwainUtils.setFIX32(container, index, v); + break; + case Twain.TWTY_BOOL: + TwainUtils.setINT32(container, index, (v == 0) ? 0 : 1); + break; + default: + TwainUtils.setINT32(container, index, v); + break; + } + } else if (item instanceof Double) { + double v = ((Double) item); + switch (type) { + case Twain.TWTY_FIX32: + TwainUtils.setFIX32(container, index, v); + break; + case Twain.TWTY_BOOL: + TwainUtils.setINT32(container, index, (v == 0) ? 0 : 1); + break; + default: + TwainUtils.setINT32(container, index, (int) v); + break; + } + } else if (item instanceof Boolean) { + int v = (((Boolean) item)) ? 1 : 0; + if (type == Twain.TWTY_FIX32) { + TwainUtils.setFIX32(container, index, v); + } else { + TwainUtils.setINT32(container, index, v); + } + } else if (item instanceof String) { + if (type == Twain.TWTY_FIX32) { + this.set32BitObjectAt(container, index, new Double((String) item)); + } else { + this.set32BitObjectAt(container, index, new Integer((String) item)); + } + } + } + + protected Object getObjectAt(byte[] container, int index) { + switch (type) { + case Twain.TWTY_INT8: + return new Integer(container[index]); + case Twain.TWTY_INT16: + return TwainUtils.getINT16(container, index); + case Twain.TWTY_INT32: + return TwainUtils.getINT32(container, index); + case Twain.TWTY_UINT8: + return container[index] & 0x000000FF; + case Twain.TWTY_UINT16: + return TwainUtils.getINT16(container, index) & 0x0000FFFF; + case Twain.TWTY_UINT32: + return ((long) TwainUtils.getINT32(container, index)) & 0x00000000FFFFFFFFL; + case Twain.TWTY_BOOL: + return (TwainUtils.getINT16(container, index) != 0); + case Twain.TWTY_FIX32: + return TwainUtils.getFIX32(container, index); + case Twain.TWTY_FRAME: + double x = TwainUtils.getFIX32(container, index); // left + double y = TwainUtils.getFIX32(container, index + 4); // top + double w = TwainUtils.getFIX32(container, index + 8) - x; // right + double h = TwainUtils.getFIX32(container, index + 12) - y; // bottom + return new Rectangle2D.Double(x, y, w, h); + case Twain.TWTY_STR32: + case Twain.TWTY_STR64: + case Twain.TWTY_STR128: + case Twain.TWTY_STR255: + String s = ""; + for (int i = 0; (container[index + i] != 0) && (i < TYPE_SIZES[type]); i++) { + s += (char) container[index + i]; + } + return s; + default: + } + return null; + } + + private void set16BitObjectAt(byte[] container, int index, Object item) { + if (item instanceof Number) { + int v = (((Number) item).intValue()); + TwainUtils.setINT16(container, index, v); + } else if (item instanceof Boolean) { + int v = (((Boolean) item)) ? 1 : 0; + TwainUtils.setINT16(container, index, v); + } + } + + protected void setObjectAt(byte[] container, int index, Object item) { + switch (type) { + case Twain.TWTY_INT16: + case Twain.TWTY_UINT16: + set16BitObjectAt(container, index, item); + break; + case Twain.TWTY_FIX32: + case Twain.TWTY_INT32: + case Twain.TWTY_UINT32: + set32BitObjectAt(container, index, item); + break; + default: + + } + } +} diff --git a/src/main/java/org/aohe/variable/TwainEnumeration.java b/src/main/java/org/aohe/variable/TwainEnumeration.java new file mode 100644 index 0000000..ca3fc81 --- /dev/null +++ b/src/main/java/org/aohe/variable/TwainEnumeration.java @@ -0,0 +1,92 @@ +package org.aohe.variable; + +import org.aohe.core.twain.Twain; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +import java.util.ArrayList; +import java.util.List; + +public class TwainEnumeration extends TwainContainer { + + int count; + int currentIndex; + int defaultIndex; + List items = new ArrayList<>(); + + public TwainEnumeration(int cap, byte[] container) { + super(cap, container); + count = TwainUtils.getINT32(container, 2); + currentIndex = TwainUtils.getINT32(container, 6); + defaultIndex = TwainUtils.getINT32(container, 10); + + for (int i = 0, off = 14; i < count; i++) { + items.add(getObjectAt(container, off)); + off += TYPE_SIZES[type]; + } + } + + @Override + public int getType() { + return Twain.TWON_ENUMERATION; + } + + @Override + public T[] getItems() { + return (T[]) items.toArray(); + } + + @Override + public byte[] getBytes() { + int count = items.size(); + int len = 14 + count * TYPE_SIZES[type]; + byte[] container = new byte[len]; + TwainUtils.setINT16(container, 0, type); + TwainUtils.setINT32(container, 2, count); + TwainUtils.setINT32(container, 6, currentIndex); + TwainUtils.setINT32(container, 10, defaultIndex); + + for (int i = 0, off = 14; i < count; i++) { + setObjectAt(container, off, items.get(i)); + off += TYPE_SIZES[type]; + } + return container; + } + + @Override + public Object getCurrentValue() throws TwainException { + return items.get(currentIndex); + } + + @Override + public void setCurrentValue(Object obj) throws TwainException { + int count = items.size(); + for (int i = 0; i < count; i++) { + Object item = items.get(i); + if (obj.equals(item)) { + currentIndex = i; + return; + } + } + throw new TwainException(getClass().getName() + ".setCurrentValue:\n\tCould not find " + obj.toString()); + } + + @Override + public Object getDefaultValue() throws TwainException { + return items.get(defaultIndex); + } + + @Override + public void setDefaultValue(Object obj) throws TwainException { + int count = items.size(); + for (int i = 0; i < count; i++) { + Object item = items.get(i); + if (obj.equals(item)) { + defaultIndex = i; + return; + } + } + throw new TwainException(getClass().getName() + ".setDefaultValue:\n\tCould not find " + obj.toString()); + } + +} diff --git a/src/main/java/org/aohe/variable/TwainOneValue.java b/src/main/java/org/aohe/variable/TwainOneValue.java new file mode 100644 index 0000000..2fcdfa8 --- /dev/null +++ b/src/main/java/org/aohe/variable/TwainOneValue.java @@ -0,0 +1,55 @@ +package org.aohe.variable; + +import org.aohe.core.twain.Twain; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + +public class TwainOneValue extends TwainContainer { + + Object item; + + public TwainOneValue(int cap, byte[] container) { + super(cap, container); + item = get32BitObjectAt(container, 2); + } + + @Override + public int getType() { + return Twain.TWON_ONEVALUE; + } + + @Override + public byte[] getBytes() { + byte[] container = new byte[6]; + TwainUtils.setINT16(container, 0, type); + set32BitObjectAt(container, 2, item); + return container; + } + + @Override + public Object getCurrentValue() throws TwainException { + return item; + } + + @Override + public void setCurrentValue(Object obj) throws TwainException { + item = obj; + } + + @Override + public Object getDefaultValue() throws TwainException { + return item; + } + + @Override + public void setDefaultValue(Object obj) throws TwainException { + item = obj; + } + + @Override + public T[] getItems() { + Object[] items = new Object[1]; + items[0] = item; + return (T[]) items; + } +} diff --git a/src/main/java/org/aohe/variable/TwainRange.java b/src/main/java/org/aohe/variable/TwainRange.java new file mode 100644 index 0000000..0e82a12 --- /dev/null +++ b/src/main/java/org/aohe/variable/TwainRange.java @@ -0,0 +1,70 @@ +package org.aohe.variable; + + +import org.aohe.core.twain.Twain; +import org.aohe.exceptions.TwainException; +import org.aohe.utils.TwainUtils; + + +public class TwainRange extends TwainContainer { + + private final Object minValue; + private final Object maxValue; + private final Object stepSize; + private Object defaultValue; + private Object currentValue; + + public TwainRange(int cap, byte[] container) { + super(cap, container); + minValue = get32BitObjectAt(container, 2); + maxValue = get32BitObjectAt(container, 6); + stepSize = get32BitObjectAt(container, 10); + defaultValue = get32BitObjectAt(container, 14); + currentValue = get32BitObjectAt(container, 18); + } + + @Override + public int getType() { + return Twain.TWON_RANGE; + } + + @Override + public byte[] getBytes() { + byte[] container = new byte[22]; + TwainUtils.setINT16(container, 0, type); + set32BitObjectAt(container, 2, minValue); + set32BitObjectAt(container, 6, maxValue); + set32BitObjectAt(container, 10, stepSize); + set32BitObjectAt(container, 14, defaultValue); + set32BitObjectAt(container, 18, currentValue); + return container; + } + + @Override + public Object getCurrentValue() throws TwainException { + return currentValue; + } + + @Override + public void setCurrentValue(Object obj) throws TwainException { + currentValue = obj; + } + + @Override + public Object getDefaultValue() throws TwainException { + return defaultValue; + } + + @Override + public void setDefaultValue(Object obj) throws TwainException { + defaultValue = obj; + } + + @Override + public Object[] getItems() { + Object[] items = new Object[1]; + items[0] = currentValue; + return items; + } + +} diff --git a/src/main/java/org/aohe/web/SocketServer.java b/src/main/java/org/aohe/web/SocketServer.java new file mode 100644 index 0000000..fc2aaa9 --- /dev/null +++ b/src/main/java/org/aohe/web/SocketServer.java @@ -0,0 +1,70 @@ +//package org.aohe.web; +// +// +//import cn.hutool.log.Log; +//import cn.hutool.log.LogFactory; +//import cn.hutool.log.StaticLog; +//import org.aohe.result.R; +//import org.java_websocket.WebSocket; +//import org.java_websocket.handshake.ClientHandshake; +//import org.java_websocket.server.WebSocketServer; +// +//import java.net.InetSocketAddress; +//import java.net.UnknownHostException; +// +//import static org.aohe.control.Operational.selectOperational; +// +//public class SocketServer extends WebSocketServer { +// +// private static final Log log = LogFactory.get(); +// +// public SocketServer(int port) throws UnknownHostException { +// super(new InetSocketAddress(port)); +// } +// +// public SocketServer(InetSocketAddress address) { +// super(address); +// } +// +// @Override +// public void onOpen(WebSocket conn, ClientHandshake handshake) { +// //conn.send("Welcome to the server!"); // This method sends a message to the new client +// //broadcast("new connection: " + handshake.getResourceDescriptor()); // This method sends a message to all clients connected +// //System.out.println(conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!"); +// StaticLog.info("ws用户已连接"); +// } +// +// @Override +// public void onClose(WebSocket conn, int code, String reason, boolean remote) { +// StaticLog.info("ws用户关闭连接"); +// //这里执行关闭扫描仪连接 +// } +// +// @Override +// public void onMessage(WebSocket conn, String message) { +// StaticLog.info("用户发送了数据:\n"+message); +// conn.send(selectOperational(message)); +// } +// +// @Override +// public void onError(WebSocket conn, Exception ex) { +// ex.printStackTrace(); +// if (conn != null) { +// conn.send(R.fail("error").toJsonStr()); +// //绑定不到就退出 +// //System.exit(0); +// // some errors like port binding failed may not be assignable to a specific +// // websocket +// } +// +// } +// +// @Override +// public void onStart() { +// System.out.println("Server started!"); +// setConnectionLostTimeout(0); +// setConnectionLostTimeout(100); +// +// } +// +//} diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..c730527 --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: org.aohe.Main + diff --git a/src/main/resources/META-INF/native-image/jni-config.json b/src/main/resources/META-INF/native-image/jni-config.json new file mode 100644 index 0000000..2830080 --- /dev/null +++ b/src/main/resources/META-INF/native-image/jni-config.json @@ -0,0 +1,175 @@ +[ +{ + "name":"[Ljava.lang.Object;" +}, +{ + "name":"com.sun.jna.Callback" +}, +{ + "name":"com.sun.jna.CallbackProxy", + "methods":[{"name":"callback","parameterTypes":["java.lang.Object[]"] }] +}, +{ + "name":"com.sun.jna.CallbackReference", + "methods":[{"name":"getCallback","parameterTypes":["java.lang.Class","com.sun.jna.Pointer","boolean"] }, {"name":"getFunctionPointer","parameterTypes":["com.sun.jna.Callback","boolean"] }, {"name":"getNativeString","parameterTypes":["java.lang.Object","boolean"] }, {"name":"initializeThread","parameterTypes":["com.sun.jna.Callback","com.sun.jna.CallbackReference$AttachOptions"] }] +}, +{ + "name":"com.sun.jna.CallbackReference$AttachOptions" +}, +{ + "name":"com.sun.jna.IntegerType", + "fields":[{"name":"value"}] +}, +{ + "name":"com.sun.jna.JNIEnv" +}, +{ + "name":"com.sun.jna.Native", + "methods":[{"name":"dispose","parameterTypes":[] }, {"name":"fromNative","parameterTypes":["com.sun.jna.FromNativeConverter","java.lang.Object","java.lang.reflect.Method"] }, {"name":"fromNative","parameterTypes":["java.lang.Class","java.lang.Object"] }, {"name":"fromNative","parameterTypes":["java.lang.reflect.Method","java.lang.Object"] }, {"name":"nativeType","parameterTypes":["java.lang.Class"] }, {"name":"toNative","parameterTypes":["com.sun.jna.ToNativeConverter","java.lang.Object"] }] +}, +{ + "name":"com.sun.jna.Native$ffi_callback", + "methods":[{"name":"invoke","parameterTypes":["long","long","long"] }] +}, +{ + "name":"com.sun.jna.NativeMapped", + "methods":[{"name":"toNative","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.Pointer", + "fields":[{"name":"peer"}], + "methods":[{"name":"","parameterTypes":["long"] }] +}, +{ + "name":"com.sun.jna.PointerType", + "fields":[{"name":"pointer"}] +}, +{ + "name":"com.sun.jna.Structure", + "fields":[{"name":"memory"}, {"name":"typeInfo"}], + "methods":[{"name":"autoRead","parameterTypes":[] }, {"name":"autoWrite","parameterTypes":[] }, {"name":"getTypeInfo","parameterTypes":[] }, {"name":"newInstance","parameterTypes":["java.lang.Class","long"] }] +}, +{ + "name":"com.sun.jna.Structure$ByValue" +}, +{ + "name":"com.sun.jna.Structure$FFIType$FFITypes", + "fields":[{"name":"ffi_type_double"}, {"name":"ffi_type_float"}, {"name":"ffi_type_longdouble"}, {"name":"ffi_type_pointer"}, {"name":"ffi_type_sint16"}, {"name":"ffi_type_sint32"}, {"name":"ffi_type_sint64"}, {"name":"ffi_type_sint8"}, {"name":"ffi_type_uint16"}, {"name":"ffi_type_uint32"}, {"name":"ffi_type_uint64"}, {"name":"ffi_type_uint8"}, {"name":"ffi_type_void"}] +}, +{ + "name":"com.sun.jna.WString", + "methods":[{"name":"","parameterTypes":["java.lang.String"] }] +}, +{ + "name":"java.lang.Boolean", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["boolean"] }, {"name":"getBoolean","parameterTypes":["java.lang.String"] }] +}, +{ + "name":"java.lang.Byte", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["byte"] }] +}, +{ + "name":"java.lang.Character", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["char"] }] +}, +{ + "name":"java.lang.Class", + "methods":[{"name":"getComponentType","parameterTypes":[] }] +}, +{ + "name":"java.lang.Double", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["double"] }] +}, +{ + "name":"java.lang.Error", + "methods":[{"name":"","parameterTypes":["java.lang.String"] }] +}, +{ + "name":"java.lang.Float", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["float"] }] +}, +{ + "name":"java.lang.Integer", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["int"] }] +}, +{ + "name":"java.lang.Long", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["long"] }] +}, +{ + "name":"java.lang.Object", + "methods":[{"name":"toString","parameterTypes":[] }] +}, +{ + "name":"java.lang.SecurityManager", + "fields":[{"name":"initialized"}] +}, +{ + "name":"java.lang.Short", + "fields":[{"name":"TYPE"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["short"] }] +}, +{ + "name":"java.lang.String", + "methods":[{"name":"","parameterTypes":["byte[]"] }, {"name":"","parameterTypes":["byte[]","java.lang.String"] }, {"name":"getBytes","parameterTypes":[] }, {"name":"getBytes","parameterTypes":["java.lang.String"] }, {"name":"toCharArray","parameterTypes":[] }] +}, +{ + "name":"java.lang.System", + "methods":[{"name":"getProperty","parameterTypes":["java.lang.String"] }] +}, +{ + "name":"java.lang.UnsatisfiedLinkError", + "methods":[{"name":"","parameterTypes":["java.lang.String"] }] +}, +{ + "name":"java.lang.Void", + "fields":[{"name":"TYPE"}] +}, +{ + "name":"java.lang.reflect.Method", + "methods":[{"name":"getParameterTypes","parameterTypes":[] }, {"name":"getReturnType","parameterTypes":[] }] +}, +{ + "name":"java.nio.Buffer", + "methods":[{"name":"position","parameterTypes":[] }] +}, +{ + "name":"java.nio.ByteBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.CharBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.DoubleBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.FloatBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.IntBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.LongBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"java.nio.ShortBuffer", + "methods":[{"name":"array","parameterTypes":[] }, {"name":"arrayOffset","parameterTypes":[] }] +}, +{ + "name":"sun.management.VMManagementImpl", + "fields":[{"name":"compTimeMonitoringSupport"}, {"name":"currentThreadCpuTimeSupport"}, {"name":"objectMonitorUsageSupport"}, {"name":"otherThreadCpuTimeSupport"}, {"name":"remoteDiagnosticCommandsSupport"}, {"name":"synchronizerUsageSupport"}, {"name":"threadAllocatedMemorySupport"}, {"name":"threadContentionMonitoringSupport"}] +} +] diff --git a/src/main/resources/META-INF/native-image/predefined-classes-config.json b/src/main/resources/META-INF/native-image/predefined-classes-config.json new file mode 100644 index 0000000..0e79b2c --- /dev/null +++ b/src/main/resources/META-INF/native-image/predefined-classes-config.json @@ -0,0 +1,8 @@ +[ + { + "type":"agent-extracted", + "classes":[ + ] + } +] + diff --git a/src/main/resources/META-INF/native-image/proxy-config.json b/src/main/resources/META-INF/native-image/proxy-config.json new file mode 100644 index 0000000..b8da948 --- /dev/null +++ b/src/main/resources/META-INF/native-image/proxy-config.json @@ -0,0 +1,11 @@ +[ + { + "interfaces":["com.sun.jna.platform.win32.User32"] + }, + { + "interfaces":["org.aohe.libs.Kernel32"] + }, + { + "interfaces":["org.aohe.libs.Win32Twain"] + } +] diff --git a/src/main/resources/META-INF/native-image/reflect-config.json b/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 0000000..c1347fb --- /dev/null +++ b/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,225 @@ +[ +{ + "name":"[B", + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"[Ljava.lang.reflect.Method;" +}, +{ + "name":"byte", + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"com.alibaba.fastjson.JSONArray" +}, +{ + "name":"com.alibaba.fastjson.JSONObject" +}, +{ + "name":"com.alibaba.fastjson2.JSONFactory$CacheItem", + "fields":[{"name":"bytes"}, {"name":"chars"}] +}, +{ + "name":"com.alibaba.fastjson2.JSONObject", + "queryAllDeclaredConstructors":true +}, +{ + "name":"com.alibaba.fastjson2.util.TypeUtils$Cache", + "fields":[{"name":"chars"}] +}, +{ + "name":"com.sun.jna.CallbackProxy", + "methods":[{"name":"callback","parameterTypes":["java.lang.Object[]"] }] +}, +{ + "name":"com.sun.jna.Structure$FFIType", + "allDeclaredFields":true, + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"com.sun.jna.Structure$FFIType$size_t", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$ATOM", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$HBRUSH", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$HCURSOR", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$HICON", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$HINSTANCE", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$HWND", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$LPARAM", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$LRESULT", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$POINT", + "allDeclaredFields":true, + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}], + "methods":[{"name":"","parameterTypes":["com.sun.jna.Pointer"] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinDef$WPARAM", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinNT$HANDLEByReference", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.sun.jna.platform.win32.WinUser$MSG", + "allDeclaredFields":true, + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"com.sun.jna.platform.win32.WinUser$WNDCLASSEX", + "allDeclaredFields":true, + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"com.sun.jna.platform.win32.WinUser$WindowProc", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true, + "methods":[{"name":"callback","parameterTypes":["com.sun.jna.platform.win32.WinDef$HWND","int","com.sun.jna.platform.win32.WinDef$WPARAM","com.sun.jna.platform.win32.WinDef$LPARAM"] }] +}, +{ + "name":"java.beans.Transient" +}, +{ + "name":"java.lang.Object", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"equals","parameterTypes":["java.lang.Object"] }, {"name":"hashCode","parameterTypes":[] }, {"name":"toString","parameterTypes":[] }] +}, +{ + "name":"java.lang.String", + "fields":[{"name":"COMPACT_STRINGS"}, {"name":"coder"}, {"name":"value"}], + "methods":[{"name":"","parameterTypes":["byte[]","byte"] }, {"name":"coder","parameterTypes":[] }, {"name":"isASCII","parameterTypes":["byte[]"] }, {"name":"value","parameterTypes":[] }] +}, +{ + "name":"java.lang.StringCoding", + "methods":[{"name":"hasNegatives","parameterTypes":["byte[]","int","int"] }] +}, +{ + "name":"java.lang.invoke.MethodHandles$Lookup", + "fields":[{"name":"IMPL_LOOKUP"}], + "methods":[{"name":"","parameterTypes":["java.lang.Class","java.lang.Class","int"] }] +}, +{ + "name":"java.lang.management.ManagementFactory", + "methods":[{"name":"getRuntimeMXBean","parameterTypes":[] }] +}, +{ + "name":"java.lang.management.RuntimeMXBean", + "methods":[{"name":"getInputArguments","parameterTypes":[] }] +}, +{ + "name":"java.lang.reflect.Method", + "methods":[{"name":"isVarArgs","parameterTypes":[] }] +}, +{ + "name":"java.math.BigDecimal", + "fields":[{"name":"intCompact"}] +}, +{ + "name":"java.math.BigInteger", + "fields":[{"name":"mag"}] +}, +{ + "name":"java.nio.Buffer" +}, +{ + "name":"java.security.SecureRandomParameters" +}, +{ + "name":"java.sql.Date" +}, +{ + "name":"java.sql.Timestamp" +}, +{ + "name":"java.util.Collections$UnmodifiableCollection" +}, +{ + "name":"java.util.Collections$UnmodifiableMap" +}, +{ + "name":"java.util.concurrent.atomic.AtomicBoolean", + "fields":[{"name":"value"}] +}, +{ + "name":"java.util.concurrent.atomic.AtomicReference", + "fields":[{"name":"value"}] +}, +{ + "name":"javax.sql.DataSource" +}, +{ + "name":"javax.sql.RowSet" +}, +{ + "name":"org.aohe.core.twain.TwainWndProc", + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"org.aohe.libs.Win32Twain$TW_CAPABILITY", + "allDeclaredFields":true +}, +{ + "name":"org.aohe.libs.Win32Twain$TW_IDENTITY", + "allDeclaredFields":true +}, +{ + "name":"org.aohe.libs.Win32Twain$TW_VERSION", + "allDeclaredFields":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["com.sun.jna.Pointer"] }] +}, +{ + "name":"org.aohe.result.R", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true, + "methods":[{"name":"getCode","parameterTypes":[] }, {"name":"getData","parameterTypes":[] }, {"name":"getMsg","parameterTypes":[] }, {"name":"isSuccess","parameterTypes":[] }] +}, +{ + "name":"short", + "fields":[{"name":"OPTIONS"}, {"name":"STRING_ENCODING"}, {"name":"STRUCTURE_ALIGNMENT"}, {"name":"TYPE_MAPPER"}] +}, +{ + "name":"sun.misc.Unsafe", + "fields":[{"name":"theUnsafe"}] +}, +{ + "name":"sun.security.provider.DRBG", + "methods":[{"name":"","parameterTypes":["java.security.SecureRandomParameters"] }] +}, +{ + "name":"sun.security.provider.SHA", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"sun.security.provider.SHA2$SHA256", + "methods":[{"name":"","parameterTypes":[] }] +} +] diff --git a/src/main/resources/META-INF/native-image/resource-config.json b/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 0000000..d35c7fb --- /dev/null +++ b/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,9 @@ +{ + "resources":{ + "includes":[{ + "pattern":"\\QMETA-INF/services/cn.hutool.log.LogFactory\\E" + }, { + "pattern":"\\Qcom/sun/jna/win32-x86-64/jnidispatch.dll\\E" + }]}, + "bundles":[] +} diff --git a/src/main/resources/META-INF/native-image/serialization-config.json b/src/main/resources/META-INF/native-image/serialization-config.json new file mode 100644 index 0000000..f3d7e06 --- /dev/null +++ b/src/main/resources/META-INF/native-image/serialization-config.json @@ -0,0 +1,8 @@ +{ + "types":[ + ], + "lambdaCapturingTypes":[ + ], + "proxies":[ + ] +} diff --git a/src/main/resources/logbcak.xml b/src/main/resources/logbcak.xml new file mode 100644 index 0000000..c2c222a --- /dev/null +++ b/src/main/resources/logbcak.xml @@ -0,0 +1,81 @@ + + + + + + + + + ${LOG_CONTEXT_NAME} + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n + utf-8 + + + INFO + + + + + + true + + + ${LOG_HOME}/%d{yyyy-MM-dd}/info/aohe.scan.info.%d{yyyy-MM-dd-HH}.%i.log + + + + 30 + + + 10MB + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n + utf-8 + + + + INFO + ACCEPT + DENY + + + + + + + + + ERROR + ACCEPT + DENY + + + + + + + + WARN + ACCEPT + DENY + + + + + + + + + + + + + \ No newline at end of file