All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.asprise.imaging.core.Imaging Maven / Gradle / Ivy

/**********************************************************************************************
 *
 * Asprise Scanning and Imaging API - http://asprise.com/document-scanner-image-pdf/java-scanning-api-overview.html
 * Copyright (C) 1998-2018. Asprise Inc. 
 *
 * This file is licensed under the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation.
 *
 * 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.
 *
 * You should have received a copy of the GNU Affero General Public License.  If not, please
 * visit .
 *
 **********************************************************************************************/
package com.asprise.imaging.core;

import com.asprise.imaging.core.prefs.Base64;
import com.asprise.imaging.core.scan.twain.Source;
import com.asprise.imaging.core.scan.twain.TwainException;
import com.asprise.imaging.core.scan.twain.TwainNative;
import com.asprise.imaging.core.scan.twain.TwainUtil;
import com.asprise.imaging.core.util.JsonUtils;
import com.asprise.imaging.core.util.TranslationProps;
import com.asprise.imaging.core.util.system.NativeScanLibHelper;
import com.asprise.imaging.core.util.system.StringUtils;
import com.asprise.imaging.core.util.system.Utils;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JSONComposer;
import com.fasterxml.jackson.jr.ob.comp.ArrayComposer;
import com.fasterxml.jackson.jr.ob.comp.ObjectComposer;

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Imaging API.
 */
public class Imaging {
    /** Turn of logging */
    public static final int LOG_LEVEL_OFF = 0;
    public static final int LOG_LEVEL_ERROR = 1;
    public static final int LOG_LEVEL_WARN = 2;
    /** Info: the default. */
    public static final int LOG_LEVEL_INFO = 3;
    public static final int LOG_LEVEL_DEBUG = 4;

    public static final String LOG_TO_STDOUT = "stdout";
    public static final String LOG_TO_STDERR = "stderr";

    public static final String OUTPUT_RETURN_BASE64 = "return-base64";
    public static final String OUTPUT_RETURN_BASE64_THUMB = "return-base64-thumbnail";
    public static final String OUTPUT_RETURN_HANDLE = "return-handle";
    public static final String OUTPUT_RETURN_HANDLE_THUMB = "return-handle-thumbnail";
    public static final String OUTPUT_SAVE = "save";
    public static final String OUTPUT_SAVE_THUMB = "save-thumbnail";
    public static final String OUTPUT_UPLOAD = "upload";
    public static final String OUTPUT_UPLOAD_THUMB = "upload-thumbnail";

    public static final String FORMAT_JPG = "jpg";
    public static final String FORMAT_PNG = "png";
    public static final String FORMAT_BMP = "bmp";
    public static final String FORMAT_TIF = "tif";
    public static final String FORMAT_PDF = "pdf";

    public static final String TIFF_COMPRESSION_CCITT_G3 = "G3";
    public static final String TIFF_COMPRESSION_CCITT_G4 = "G4";
    public static final String TIFF_COMPRESSION_LZW	= "LZW";
    public static final String TIFF_COMPRESSION_RLE	= "RLE";
    public static final String TIFF_COMPRESSION_NONE = "NONE";

    public static final String TIFF_COMPRESSION_PACKBITS = "PACKBITS";
    public static final String TIFF_COMPRESSION_ZIP	= "ZIP";

    public static final String EXIF_NAME_DocumentName = "DocumentName";
    public static final String EXIF_NAME_ImageDescription = "ImageDescription";
    public static final String EXIF_NAME_EquipMake = "EquipMake";
    public static final String EXIF_NAME_EquipModel	= "EquipModel";
    // public static final String EXIF_NAME_SoftwareUsed = "SoftwareUsed"
    /** Limit length to max 20 */
    // public static final String EXIF_NAME_DateTime			"DateTime"
    public static final String EXIF_NAME_Copyright = "Copyright";
    public static final String EXIF_NAME_UserComment = "UserComment";

    /** Operating system name. */
    public static final String SYSTEM_INFO_OS = "os";
    /** User's preferred locale ID (LCID), e.g, 1033; result of GetUserDefaultLCID() */
    public static final String SYSTEM_INFO_USER_DEFAULT_LC_ID = "user_default_lc_id";
    /** User's preferred locale code (LCID), e.g, 'en_US'; result of GetUserDefaultLCID() */
    public static final String SYSTEM_INFO_USER_DEFAULT_LC_CODE = "user_default_lc_code";
    /** User's preferred language ID (LANGID), e.g, 1033; result of GetUserDefaultUILanguage() */
    public static final String SYSTEM_INFO_USER_DEFAULT_UI_LANG_ID = "user_default_ui_lang_id";
    /** User's preferred language ID (LANGID), e.g, 'en_US'; result of GetUserDefaultUILanguage() */
    public static final String SYSTEM_INFO_USER_DEFAULT_UI_LANG_CODE = "user_default_ui_lang_code";
    /** the language of the installed OS, e.g, 1033; result of GetUserDefaultLangID() */
    public static final String SYSTEM_INFO_OS_LANG_ID = "user_default_lang_id";
    /** the language of the installed OS, e.g, 'en_US'; result of GetUserDefaultLangID() */
    public static final String SYSTEM_INFO_OS_LANG_CODE = "user_default_lang_code";
    /** User geo id of nation, e.g, 244; result of GetUserGeoID(GEOCLASS_NATION) */
    public static final String SYSTEM_INFO_GEO_NATION_ID = "user_geo_nation_id";
    /** User geo name of nation, e.g, 'US; United States'; result of GetUserGeoID(GEOCLASS_NATION) */
    public static final String SYSTEM_INFO_GEO_NATION_NAME = "user_geo_nation_name";
    /** User geo id of region; result of GetUserGeoID(GEOCLASS_REGION) */
    public static final String SYSTEM_INFO_GEO_REGION_ID = "user_geo_region_id";
    /** User geo id of region; result of GetUserGeoID(GEOCLASS_REGION) */
    public static final String SYSTEM_INFO_GEO_REGION_NAME = "user_geo_region_name";

    /** daylight | standard | <error: ...>; result of GetTimeZoneInformation */
    public static final String SYSTEM_INFO_TIMEZONE_TYPE = "timezone_type";
    /** TIME_ZONE_INFORMATION.DaylightName or TIME_ZONE_INFORMATION.StandardName or null depending on tz type. */
    public static final String SYSTEM_INFO_TIMEZONE_NAME = "timezone_name";
    /** TIME_ZONE_INFORMATION.Bias:  bias in minutes for local time translation. UTC = local time + bias */
    public static final String SYSTEM_INFO_TIMEZONE_BIAS = "timezone_bias";
    /** TWAIN data source manager version */
    public static final String SYSTEM_INFO_TWAIN_VERSION = "twain_version";
    /** Default paper size: letter | legal | a3 | a4 */
    public static final String SYSTEM_INFO_DEFAULT_PAPER_SIZE = "default_paper_size";
    /** Measurement system: metric | us */
    public static final String SYSTEM_INFO_MEASUREMENT_SYSTEM = "measurement_system";

    static {
        try {
            NativeScanLibHelper.loadScanLib();
        } catch (Throwable t) {
            System.err.println("Unable to load native library: " + t);
            t.printStackTrace();
            JOptionPane.showMessageDialog(null, "Error: " + t.getMessage(), "Unable to load native library", JOptionPane.ERROR_MESSAGE);
        }
    }

    String appId;
    int windowHandle;

    /** Invoking thread id. */
    private volatile long it;

    /** Flex license. */
    private String license = "";
    private static Object globalClientConnectionObj;

    /** Whether to use Asprise source select UI instead of system UI for "select" */
    private Boolean useAspriseSourceSelectUI;

    public Imaging(String appId, int windowHandle) {
        this.appId = appId;
        this.windowHandle = windowHandle;
        this.it = Thread.currentThread().getId();
        license = System.getProperty("GLOBAL_FLEX_LICENSE");
        if(globalClientConnectionObj != null) {
            TwainNative.onClientConnected(globalClientConnectionObj);
        }
    }

    /** Allows ScanServer to reset properly. */
    public void resetIt() {
        this.it = Thread.currentThread().getId();
    }

    private Component owningComponent;
    public Imaging(Component owningUI) {
        this("Java", (int) Utils.getOwningWindowHandle(owningUI));
        this.owningComponent = owningUI;
    }

    public void setLicense(String license) {
        this.license = license;
    }

    public String getLicense() {
        return license;
    }

    public Imaging setUseAspriseSourceSelectUI(boolean value) {
        this.useAspriseSourceSelectUI = value;
        return this;
    }

    /**
     * Whether to use Asprise Swing based source select UI; default to true.
     * Set system property use_asprise_source_select_ui to false to turn off or explicitly set it.
     * @return
     */
    public boolean getUseAspriseSourceSelectUI() {
        if(!Utils.isEval(this) && Utils.getLicenseType(this) <= Utils.LIC_TYPE_STD) { // Only PRO and ENT are allowed.
            return false;
        }

        if(useAspriseSourceSelectUI != null) { // explicitly specified.
            return useAspriseSourceSelectUI;
        }

        String propKey = "use_asprise_source_select_ui";
        String propValue = System.getProperty(propKey);
        if(StringUtils.isEmpty(propValue)) {
            propValue = System.getenv(propKey);
        }

        if(StringUtils.isEmpty(propValue)) {
            return true;
        } else {
            return ! (propValue.equalsIgnoreCase("false") || propValue.equalsIgnoreCase("0"));
        }
    }

    /**
     * Performs swing based source selection is sourceName is "select" and swing based source select UI is enabled.
     * @param sourceName
     * @return name of the source selected or "select" if user cancels.
     */
    public String doSelectSourceIfUsingAspriseSelectUI(String sourceName) {
        if(! ("select".equalsIgnoreCase(sourceName) && getUseAspriseSourceSelectUI())) {
            return sourceName;
        }

        String result = doSelectSourceUsingAspriseSelectUI();
        return result == null ? sourceName : result;
    }

    private String doSelectSourceUsingAspriseSelectUI() {
        try {
            Class cls = null;
            cls = Class.forName("com.asprise.imaging.scan.ui.workbench.ScannerSelectUI");
            Method meth = cls.getMethod("select", Component.class, String.class, Properties.class);
            String result = (String) meth.invoke(null, owningComponent, license, i18n); // static method doesn't have an instance
            return result;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }

    /** To be used by scanner select UI only */
    Properties i18n;
    /** Sets to i18n to be used by ScanSelectUI */
    public void setI18n(Properties i18n) {
        if(Utils.isEnterpriseOrEvaluation(this)) {
            this.i18n = i18n;
        } else {
            if(i18n != null && !(i18n.size() == 1 && "en".equalsIgnoreCase(i18n.getProperty("lang")))) {
                System.err.println("i18n is not supported under the current license: " + i18n);
            }
        }
    }

    public static void setGlobalClientConnectionObj(Object clientConnectionObj) {
        globalClientConnectionObj = clientConnectionObj;
    }

    public void setOwning(Component owningUI) {
        this.windowHandle = (int)Utils.getOwningWindowHandle(owningUI);
    }

//    /** Sets the invoking thread id. */
//    private void setIt(long value) {
//        this.it = value;
//    }

    private static ExecutorService executorServiceForScanning;

    /** Use this executor service to make sure that all scanning related code is executed from the same thread. */
    public static ExecutorService getDefaultExecutorServiceForScanning() {
        if(executorServiceForScanning == null) {
            synchronized (Imaging.class) {
                if(executorServiceForScanning == null) {
                    executorServiceForScanning = Executors.newSingleThreadExecutor(new ThreadFactory() { // custom factory for user-friendly thread name
                        final AtomicInteger threadNumber = new AtomicInteger(1);
                        ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();

                        public Thread newThread(Runnable r) {
                            Thread thread = defaultThreadFactory.newThread(r);
                            thread.setName("scan" + (threadNumber.get() == 1 ? "" : "-" + threadNumber));
                            return thread;
                        }
                    });
                }
            }
        }
        return executorServiceForScanning;
    }

    /**
     * Executes and wait indefinitely until the result is returned or exception occurs
     * @param callable
     * @param 
     * @return
     * @throws Throwable in case of exeception occurred during execution
     */
    public static  R executeInDefaultExecutorServiceAndWaitTillReturn(Callable callable) throws Throwable {
        List> list = new ArrayList>();
        list.add(callable);
        try {
            List> futures = getDefaultExecutorServiceForScanning().invokeAll(list);
            Future returned = futures.get(0);
            return returned.get();
        } catch (Throwable e) {
            if(e instanceof ExecutionException) {
                throw ((ExecutionException)e).getCause();
            } else {
                throw e;
            }
        }
    }

    /**
     * Performs scanning from a device and output (return, save, and/or upload).
     * @param request scan request object.
     * @param sourceName the exact source name or "select" to prompt dialog selection; "default" to use default source; "current" refers to current opened source if any.
     * @param showUI set to true to use scanner UI or false to hide the UI. Set to true for maximum compatibility.
     * @param modalUI whether the scanner UI should be modal. Set to to true if you are not sure.
     * @return Scan result or null if user cancels.
     * @throws TwainException if failed.
     */
    public Result scan(Request request, String sourceName, boolean showUI, boolean modalUI) {
        return scan(JsonUtils.jsonSerialize(request.toJsonObject(), true), sourceName, showUI, modalUI);
    }

    /**
     * Performs scanning from a device and output (return, save, and/or upload).
     * @param scanRequestInJson scan request in JSON format.
     * @param sourceName the exact source name or "select" to prompt dialog selection; "default" to use default source; "current" refers to current opened source if any.
     * @param showUI set to true to use scanner UI or false to hide the UI. Set to true for maximum compatibility.
     * @param modalUI whether the scanner UI should be modal. Set to to true if you are not sure.
     * @return Scan result or null if user cancels.
     * @throws TwainException if failed.
     */
    public Result scan(String scanRequestInJson, String sourceName, boolean showUI, boolean modalUI) {
        ensureScanFuncsCallInTheSameThread();
        String rawResult = scanAndReturnRaw(scanRequestInJson, sourceName, showUI, modalUI);
        if(rawResult == null) {
            return null; // user cancels
        }
        if(rawResult != null && rawResult.startsWith(" root = JSON.std.mapFrom(rawResult);
            Result r = Result.createScanResult(root);
            return r;
        } catch (Throwable t) {
            throw new TwainException(rawResult, t);
        }
    }

    /**
     * Performs scanning from a device and output result in JSON.
     * @param scanRequestInJson scan request in JSON format.
     * @param sourceName the exact source name or "select" to prompt dialog selection; "default" to use default source; "current" refers to current opened source if any.
     * @param showUI set to true to use scanner UI or false to hide the UI. Set to true for maximum compatibility.
     * @param modalUI whether the scanner UI should be modal. Set to to true if you are not sure.
     * @return Scan result in JSON or null if user cancels.
     * @throws TwainException if failed.
     */
    public String scanAndReturnRaw(String scanRequestInJson, String sourceName, boolean showUI, boolean modalUI) {
        ensureScanFuncsCallInTheSameThread();
        System.setProperty("it", String.valueOf(this.it));
        System.setProperty("ASCAN_FLEX_LICENSE", license == null ? "" : license);

        try {
            Request request = Request.fromJson(scanRequestInJson);
            boolean fallbackToEn = false;
            if(request != null) {
                Properties i18nToSet = TranslationProps.loadLangIfAvailable(request.getI18n(), Request.I18N_PROPS_PREFIX);
                if (Utils.isEnterpriseOrEvaluation(this)) {
                    if (i18nToSet != null && i18nToSet.size() > 0) {
                        // carry to native code
                        String scanMoreTitle = i18nToSet.getProperty(Request.I18N_SCAN_MORE_DIALOG_TITLE);
                        String scanMoreMesg = i18nToSet.getProperty(Request.I18N_SCAN_MORE_DIALOG_MESSAGE);
                        if (scanMoreTitle != null && scanMoreTitle.trim().length() > 0) {
                            request.setI18n(Request.I18N_SCAN_MORE_DIALOG_TITLE,
                                    scanMoreTitle.startsWith("base64,") ? scanMoreTitle : "base64," + Base64.byteArrayToBase64(scanMoreTitle.getBytes("UTF-8")));
                        }
                        if (scanMoreMesg != null && scanMoreMesg.trim().length() > 0) {
                            request.setI18n(Request.I18N_SCAN_MORE_DIALOG_MESSAGE,
                                    scanMoreMesg.startsWith("base64,") ? scanMoreMesg : "base64," + Base64.byteArrayToBase64(scanMoreMesg.getBytes("UTF-8")));
                        }

                        setI18n(i18nToSet);
                    } else {
                        fallbackToEn = true;
                    }
                } else {
                    fallbackToEn = true;
                    if(request.getI18n() != null && request.getI18n().size() > 0) {
                        if(! (request.getI18n().size() == 1 && "en".equalsIgnoreCase(request.getI18n().getProperty("lang")))) {
                            JOptionPane.showMessageDialog(null, "i18n is not supported under the current license", "Warn", JOptionPane.OK_OPTION | JOptionPane.WARNING_MESSAGE);
                        }
                        request.clearI18n(null);
                    }
                }
            }

            if(fallbackToEn) { // If the UI was in other languages, we need to fallback to 'en' to display EN.
                Properties propTmp = new Properties();
                propTmp.setProperty(Request.I18N_LANG, "en");
                setI18n(TranslationProps.loadLangIfAvailable(propTmp, Request.I18N_PROPS_PREFIX));
            }

            scanRequestInJson = request.toJson(true);
        } catch (Throwable e) {
            e.printStackTrace();
        }

        sourceName = doSelectSourceIfUsingAspriseSelectUI(sourceName);
        if(getUseAspriseSourceSelectUI() && "select".equalsIgnoreCase(sourceName)) { // user cancels
            return null;
        }

        String rawResult = callNativeFunc(TwainNative.FUNC_twain_scan, appId,
                // FUJITSU fi-5120Cdj waits forever if we use windowHandle (from JFrame) here
                0, // windowHandle,
                scanRequestInJson, sourceName, showUI, modalUI);
        if(rawResult != null && rawResult.contains("failed to open data source: TWRC_CANCEL")) {
            return null;
        }
        return rawResult;
    }

    /**
     * Performs image conversion and output (return, save, and/or upload).
     * @param request scan request object.
     * @return Scan result or null if user cancels.
     * @throws TwainException if failed.
     */
    public Result convert(Request request) {
        System.setProperty("it", String.valueOf(this.it));
        System.setProperty("ASCAN_FLEX_LICENSE", license == null ? "" : license);

        String requestInJson = JsonUtils.jsonSerialize(request.toJsonObject(), true);
        String result = callNativeFunc(TwainNative.FUNC_image_output, requestInJson);
        if(result != null && result.startsWith(" root = JSON.std.mapFrom(result);
            return Result.createScanResult(root);
        } catch (Throwable t) {
            throw new TwainException(result, t);
        }
    }

    /**
     * Get information about the image, e.g. bytes, width, height, etc.
     * @param imageFile Path to the image file.
     * @return Information as map
     * @throws TwainException if failed.
     */
    public Map getImageInfo(String imageFile) {
        String result = callNativeFunc(TwainNative.FUNC_image_info, imageFile);
        try {
            Map root = JSON.std.mapFrom(result);
            return root;
        } catch (Throwable t) {
            throw new TwainException(result, t);
        }
    }

    /**
     * Performs operations on image, e.g., rotate, crop, scale, gray, etc.
     * @param inputImageFile Path to the input file.
     * @param commands Processing commands
     * @param outputImageFile Path to the output file.
     * @return Information as map
     * @throws TwainException if failed.
     */
    public Map processImage(String inputImageFile, String commands, String outputImageFile) {
        System.setProperty("it", String.valueOf(this.it));
        System.setProperty("ASCAN_FLEX_LICENSE", license == null ? "" : license);

        String result = callNativeFunc(TwainNative.FUNC_image_process, inputImageFile, commands, outputImageFile);
        try {
            Map root = JSON.std.mapFrom(result);
            return root;
        } catch (Throwable t) {
            throw new TwainException(result, t);
        }
    }

    /**
     * Retrieve list of sources (i.e., devices) optionally with caps; the default source has "default": true in JSON format.
     * @param nameOnly if true, return list of device names separated by ',' otherwise return device info in JSON format.
     * @param capsToRetrieve only effective if nameOnly is false - If set, return JSON string; can be cap name or code separated by comma or 'all' to list all caps supported.
     * @param detectDeviceType detect whether the device has ADF and/or flatbed.
     * @param excludeTwainDsOnWia exclude WIA synthesized sources
     * @return JSON or comma separated string depending on nameOnly.
     */
    public List scanListSources(boolean nameOnly, String capsToRetrieve, boolean detectDeviceType, boolean excludeTwainDsOnWia) {
        ensureScanFuncsCallInTheSameThread();
        String raw = callNativeFunc(TwainNative.FUNC_twain_list_sources, appId, windowHandle, nameOnly, capsToRetrieve, false, detectDeviceType, excludeTwainDsOnWia);
        if(raw == null || raw.startsWith(" sources = new ArrayList();
        if(nameOnly) {
            if(raw.trim().length() == 0) {
                return sources;
            }

            StringTokenizer st = new StringTokenizer(raw, ",");
            while(st.hasMoreTokens()) {
                String name = st.nextToken();
                if(name != null && name.trim().length() > 0) {
                    sources.add(new Source(name));
                }
            }
        } else {
            sources = Source.createSourceList((List) TwainUtil.jsonDeserialize(raw));
        }

        return sources;
    }

    /**
     * Retrieve list of sources (i.e., devices) with all caps; the default source has "default": true in JSON format.
     * @return JSON representation of all sources with details.
     */
    public List scanListSourcesWithFullDetails() {
        return scanListSources(false, "all", true, false);
    }

    /**
     * Lists all sources with names only.
     * @return sources with names only.
     */
    public List scanListSources() {
        return scanListSources(true, null, false, false);
    }

    /**
     * Gets the name of the default source or null if none presents.
     * @return the name of the default source or null if none presents.
     */
    public String scanGetDefaultSourceName() {
        ensureScanFuncsCallInTheSameThread();
        String result = callNativeFunc(TwainNative.FUNC_twain_get_default_source_name, appId, windowHandle);
        return result;
    }

    /**
     * Prompts system device selection dialog for the user to select the default device.
     * @param defaultSelectedSourceName the name of the source to be pre-selected or null to use the system default.
     * return: the name of the source selected or empty string if user cancels or error occurs.
     */
    public String scanSelectDefaultSource(String defaultSelectedSourceName) {
        ensureScanFuncsCallInTheSameThread();
        return callNativeFunc(TwainNative.FUNC_twain_select_default_source, appId, windowHandle, defaultSelectedSourceName);
    }

    /**
     * Prompts system device selection dialog for the user to select the default device.
     * return: the name of the source selected or empty string if user cancels or error occurs.
     */
    public String scanSelectDefaultSource() {
        return scanSelectDefaultSource(null);
    }

    /**
     * Select Source using Asprise source selection UI.
     * @return the name of the selected source or null if cancelled.
     */
    public String scanSelectSource() {
        return doSelectSourceUsingAspriseSelectUI();
    }

    /**
     * Retrieve the source info optionally with caps.
     * @param sourceName the exact source name or "default" to open default source; "select" to prompt dialog selection
     * @param nameOnly if true, return the device name only
     * @param capsToRetrieve only effective if nameOnly is false - can be cap name or code separated by comma or 'all' to list all caps supported.
     * @param getCurrent true to return current value false to return current value as well as value range if available.
     * @param detectDeviceType detect whether the device has ADF and/or flatbed.
     * @param capsToSet optionally, you may set capabilities before getting capabilities, e.g, 'ICAP_PIXELTYPE: TWPT_GRAY,TWPT_BW; ICAP_XSCALING/RESET; ICAP_XRESOLUTION: 200'
     * @return JSON or comma separated string depending on nameOnly.
     */
    public Source getSource(String sourceName, boolean nameOnly, String capsToRetrieve,
                            boolean getCurrent, boolean detectDeviceType, String capsToSet) {
        ensureScanFuncsCallInTheSameThread();
        sourceName = doSelectSourceIfUsingAspriseSelectUI(sourceName);
        if(getUseAspriseSourceSelectUI() && "select".equalsIgnoreCase(sourceName)) { // user cancels
            return null;
        }

        if(getUseAspriseSourceSelectUI() && nameOnly) { // name only
            return new Source(sourceName);
        }

        String raw = callNativeFunc(TwainNative.FUNC_twain_get_source, appId, windowHandle, sourceName, nameOnly,
            capsToRetrieve, getCurrent, detectDeviceType, capsToSet);

        if(raw == null || raw.startsWith(") TwainUtil.jsonDeserialize(raw));
    }

    public String licRequest(String lic) {
        System.setProperty("it", String.valueOf(this.it));
        System.setProperty("ASCAN_FLEX_LICENSE", license == null ? "" : license);
        return Imaging.callNativeFunc("asprise_check_flex_lic", lic);
    }

    /**
     * Gets the current Asprise Scan version.
     * @return the current Asprise Scan version.
     */
    public static String getLibraryVersion() {
        return callNativeFunc(TwainNative.FUNC_version);
    }

    /**
     * Gets the current Asprise Scan library build info.
     * @return the library build info.
     */
    public static String getLibraryBuildInfo() {
        return callNativeFunc(TwainNative.FUNC_buildInfo);
    }

    /** Whether TWAIN is loaded. */
    public static boolean isTwainLoaded() {
        String result = callNativeFunc(TwainNative.FUNC_twain_is_loaded, "info");
        return "1".equalsIgnoreCase(result) || "true".equalsIgnoreCase(result);
    }

    /**
     * Loads twain_32.dll
     * @return true if successful false otherwise.
     */
    public static boolean loadTwain() {
        String result = callNativeFunc(TwainNative.FUNC_twain_load, "info");
        return "1".equalsIgnoreCase(result) || "true".equalsIgnoreCase(result);
    }

    /**
     * Unloads twain_32.dll
     * @return true if successful false otherwise
     */
    public static boolean unloadTwain() {
        String result = callNativeFunc(TwainNative.FUNC_twain_unload, "info");
        return "1".equalsIgnoreCase(result) || "true".equalsIgnoreCase(result);
    }

    public static final String TWAIN_CONFIG_system_twain_version = "system_twain_version";
    public static final String TWAIN_CONFIG_twain_config_invocation = "twain_config_invocation";
    public static final String TWAIN_CONFIG_twain_config_version = "twain_config_version";
    public static final String TWAIN_CONFIG_twain_loaded = "twain_loaded";
    public static final String TWAIN_CONFIG_twain_version_in_use = "twain_version_in_use";

    // Must be in sync with C:\J\dev\asprise\scan\projects\c\scan\scan-core\asprise_scan_internal.h
    public static final int TWAIN_CONFIG_VERSION_AUTO = 0;
    public static final int TWAIN_CONFIG_VERSION_SYSTEM = 1;
    public static final int TWAIN_CONFIG_VERSION_BUNDLED = 2;

    public static final int TWAIN_CONFIG_INVOCATION_AUTO = 0;
    public static final int TWAIN_CONFIG_INVOCATION_ALWAYS_CREATE_NEW_WINDOW = 1;
    public static final int TWAIN_CONFIG_INVOCATION_REUSE_WINDOW = 2;

    /**
     * Returns TWAIN related properties containing something like: 
     * "system_twain_version" : "1.7.1.0, 1.7.1.3",
     * "twain_config_invocation" : 1,
     * "twain_config_version" : 2,
     * "twain_loaded" : true,
     * "twain_version_in_use" : "2.3.0.0, 2.3.0.0"
     * 
* @return */ public static Properties getTwainConfig() { try { Map map = new HashMap(); try { map = JsonUtils.parseJson(callNativeFunc(TwainNative.FUNC_twain_config_get)); } catch (IOException e) { e.printStackTrace(); } Properties props = new Properties(); props.putAll(map); return props; } catch (Throwable t) { t.printStackTrace(); return null; } } /** * Returns the twain invocation mode in use, any of TWAIN_CONFIG_INVOCATION_AUTO */ public static int getTwainConfigInvocation() { Properties props = getTwainConfig(); String invocation = String.valueOf(props.get(TWAIN_CONFIG_twain_config_invocation)); if (invocation == null) { return TWAIN_CONFIG_INVOCATION_AUTO; } try { int parsed = Integer.parseInt(invocation); if(parsed >= 0 && parsed <= 2) { return parsed; } else { return TWAIN_CONFIG_INVOCATION_AUTO; } } catch (Throwable t) { t.printStackTrace(); return TWAIN_CONFIG_INVOCATION_AUTO; } } /** * Returns the twain version config, any of TWAIN_CONFIG_VERSION_AUTO */ public static int getTwainConfigVersion() { Properties props = getTwainConfig(); String version = String.valueOf(props.get(TWAIN_CONFIG_twain_config_version)); if (version == null) { return TWAIN_CONFIG_VERSION_AUTO; } try { int parsed = Integer.parseInt(version); if(parsed >= 0 && parsed <= 2) { return parsed; } else { return TWAIN_CONFIG_VERSION_AUTO; } } catch (Throwable t) { t.printStackTrace(); return TWAIN_CONFIG_VERSION_AUTO; } } /** * Returns the loaded twain version or null if not loaded */ public static String getTwainVersionLoaded() { Properties props = getTwainConfig(); String version = props == null ? null : String.valueOf(props.get(TWAIN_CONFIG_twain_version_in_use)); if (version == null) { return null; } int commaPos = version.indexOf(','); return commaPos < 0 ? version : version.substring(0, commaPos); } /** * Returns the system twain version */ public static String getTwainVersionSystem() { Properties props = getTwainConfig(); String version = props == null ? null : String.valueOf(props.get(TWAIN_CONFIG_system_twain_version)); if(version == null) { return null; } int commaPos = version.indexOf(','); return commaPos < 0 ? version : version.substring(0, commaPos); } /** * Configures TWAIN. * @param version 0: Auto; 1: Use system; 2: Use bundled * @param invocation 0: Auto; 1: always creates a new window handle; 2: reuse existing window handle * @return whether setting is successful */ public static boolean setTwainConfig(int version, int invocation) { String result = callNativeFunc(TwainNative.FUNC_twain_config_set, version, invocation); return "1".equalsIgnoreCase(result) || "true".equalsIgnoreCase(result); } /** * Gets the system related properties. * @return the system properties. */ public static Properties getSystemInfo() { Map map = new HashMap(); try { map = JsonUtils.parseJson(callNativeFunc(TwainNative.FUNC_systemInfo)); } catch (IOException e) { e.printStackTrace(); } Properties props = new Properties(); props.putAll(map); return props; } /** Returns user's preferred locale code, e.g, 'en_US' or null if failed. */ public static String getSystemInfoUserLocale() { return getSystemInfo().getProperty(Imaging.SYSTEM_INFO_USER_DEFAULT_LC_CODE); } /** * Gets the current Asprise Scan version number. * @return */ public static String getLibraryVersionNumberOnly() { String libVersion = getLibraryVersion(); Pattern pattern = Pattern.compile("(\\d+(\\.\\d+)?)"); Matcher matcher = pattern.matcher(libVersion); return matcher.find() ? matcher.group() : "0.0"; } private volatile Thread calledInThread; protected void ensureScanFuncsCallInTheSameThread() { if(calledInThread == null) { calledInThread = Thread.currentThread(); } else { if(calledInThread != Thread.currentThread()) { throw new TwainException("Scan operations should be performed in the same thread. Previous used thread: " + calledInThread.getName() + ", current thread: " + Thread.currentThread().getName()); } } } /** * * @param functionName * @param args Must be of type: String, Integer or Boolean; * @return * @throws RuntimeException if failed to form request in JSON format. */ public static String callNativeFunc(String functionName, Object... args) { if(args != null && args.length == 1) { // expands if there is only one arg and it's a list or an array. if(args[0] instanceof List) { args = ((List)args[0]).toArray(); } else if(args[0] instanceof Object[]) { args = (Object[])args[0]; } } String jsonRequest = null; try { ArrayComposer>> argArray = JSON.std.composeString().startObject().put("function", functionName).startArrayField("args"); for(int i = 0; args != null && i < args.length; i++) { Object arg = args[i]; if(arg instanceof String) { argArray = argArray.add((String)arg); } else if(arg instanceof Integer) { argArray = argArray.add(((Number)arg).intValue()); } else if(arg instanceof Long) { argArray = argArray.add(((Number)arg).longValue()); } else if(arg instanceof Boolean) { argArray = argArray.add(((Boolean) arg).booleanValue()); } else if(arg == null) { argArray = argArray.addNull(); } else { throw new IllegalArgumentException("Unsupported arg type: " + arg.getClass().getName() + "; object: " + arg); } } jsonRequest = argArray.end().end().finish(); } catch (Throwable e) { if(e instanceof RuntimeException) { throw (RuntimeException)e; } else { throw new RuntimeException(e); } } if(jsonRequest == null || jsonRequest.length() == 0) { throw new IllegalArgumentException("Invalid requst: " + jsonRequest); } // System.out.println(jsonRequest); String result = TwainNative.invokeFunc(jsonRequest); return result; } /** * Configure logging settings. * @param level Any of {@linkplain #LOG_LEVEL_INFO} (default), {@linkplain #LOG_LEVEL_WARN}, etc. * @param logFilePath path to the target output file or special values: "stdout", "stderr" for console logging, null or empty string to disable logging. */ public static void configureNativeLogging(int level, String logFilePath) { TwainNative.configureLogging(level, logFilePath); } public static void main(String[] args) { if(args == null) { args = new String[0]; } if(Utils.isJava5()) { System.out.println("Asprise Scan fully supports Java 5. However, demo UI may not work properly in Java 5."); } // Try UI mode if possible try { if(!(args.length > 0 && "console".equalsIgnoreCase(args[args.length - 1])) && !java.awt.GraphicsEnvironment.isHeadless()) { Class cls = Class.forName("com.asprise.imaging.scan.ui.workbench.demo.FrameScanDemo"); Method meth = cls.getMethod("main", String[].class); String[] params = null; // init params accordingly meth.invoke(null, (Object) args); // static method doesn't have an instance return; } } catch (Throwable e) { if(System.getenv("ASPRISE_DEV") != null) { e.printStackTrace(); } } // No UI String copyright = "Copyright Asprise, " + Calendar.getInstance().get(Calendar.YEAR) + ". All Rights Reserved. Visit www.asprise.com"; String version = "Library version: " + getLibraryVersion(); try { JOptionPane.showMessageDialog(null, version + (Utils.isJava5() ? "\nAsprise Scan fully supports Java 5. However, demo UI may not work properly in Java 5." : "") , copyright, JOptionPane.OK_OPTION | JOptionPane.INFORMATION_MESSAGE); } catch (Throwable t) { // ignore exception } System.out.println(copyright); System.out.println(version + " built on " + getLibraryBuildInfo()); System.out.println(Utils.getEnvInfo(false)); if(args.length > 0 && "test".equals(args[0])) { try { Imaging imaging = new Imaging("Java", 0); Result result = imaging.scan("{\n" + " \"output_settings\" : [ {\n" + " \"type\" : \"save\",\n" + " \"format\" : \"jpg\",\n" + " \"save_path\" : \"${TMP}\\\\${TMS}${EXT}\"\n" + " } ]\n" + "}", "select", true, false); List files = result.getImageFiles(); if (files != null) { for (File file : files) { if(!Utils.openFileUsingDesktop(file)) { System.out.println("File: " + file); } } } } catch (Throwable t) { t.printStackTrace(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy