Your Name 3 years ago
commit
f6b2ffbda7
46 changed files with 4226 additions and 0 deletions
  1. 73 0
      Resources/Readme.txt
  2. BIN
      Resources/dist/DynamsoftServiceSetup-arm64.deb
  3. BIN
      Resources/dist/DynamsoftServiceSetup.msi
  4. BIN
      Resources/dist/DynamsoftServiceSetup.pkg
  5. 113 0
      Resources/dist/LICENSE
  6. 139 0
      Resources/dynamsoft.webtwain.config.js
  7. 17 0
      Resources/dynamsoft.webtwain.initiate.js
  8. 376 0
      Resources/dynamsoft.webtwain.install.js
  9. BIN
      Resources/src/dynamsoft.crypto-1.7.1.wasm
  10. BIN
      Resources/src/dynamsoft.imageProc-1.7.1.wasm
  11. BIN
      Resources/src/dynamsoft.imagecore-1.7.1.wasm
  12. BIN
      Resources/src/dynamsoft.imageio-1.7.1.wasm
  13. 128 0
      Resources/src/dynamsoft.imageio.js
  14. 106 0
      Resources/src/dynamsoft.imageio_wasm-1.7.1.js
  15. 666 0
      Resources/src/dynamsoft.lts.js
  16. BIN
      Resources/src/dynamsoft.pdfReader-1.7.1.wasm
  17. BIN
      Resources/src/dynamsoft.pdfWriter-1.7.1.wasm
  18. 2 0
      Resources/src/dynamsoft.viewer.css
  19. 2 0
      Resources/src/dynamsoft.viewer.js
  20. 1103 0
      Resources/src/dynamsoft.webtwain.css
  21. 29 0
      a.html
  22. 72 0
      css/index.css
  23. 116 0
      index.html
  24. 45 0
      js/api.js
  25. 68 0
      js/scan.js
  26. 144 0
      js/xscan.js
  27. 1 0
      layui/css/layui.css
  28. 1 0
      layui/css/modules/code.css
  29. 1 0
      layui/css/modules/laydate/default/laydate.css
  30. BIN
      layui/css/modules/layer/default/icon-ext.png
  31. BIN
      layui/css/modules/layer/default/icon.png
  32. 1 0
      layui/css/modules/layer/default/layer.css
  33. BIN
      layui/css/modules/layer/default/loading-0.gif
  34. BIN
      layui/css/modules/layer/default/loading-1.gif
  35. BIN
      layui/css/modules/layer/default/loading-2.gif
  36. BIN
      layui/font/iconfont.eot
  37. 554 0
      layui/font/iconfont.svg
  38. BIN
      layui/font/iconfont.ttf
  39. BIN
      layui/font/iconfont.woff
  40. BIN
      layui/font/iconfont.woff2
  41. 5 0
      layui/layui.js
  42. 80 0
      login.html
  43. 89 0
      scan.html
  44. 78 0
      test.html
  45. 172 0
      twainscan.py
  46. 45 0
      xscanserver.py

+ 73 - 0
Resources/Readme.txt

@@ -0,0 +1,73 @@
+// @2021/04/20
+
+* Product: Dynamsoft Web TWAIN SDK v17.x
+* Summary: this Readme.txt is to help you understand the files under the Resources folder
+
+====== Dynamsoft JavaScript Libraries ======
+
+- dynamsoft.webtwain.config.js
+This file is used to make basic configuration of the Dynamic Web TWAIN library. It's where you enter the product key for the product and to change the initial viewer size, etc.
+
+- dynamsoft.webtwain.initiate.js
+This file is the core of the Dynamic Web TWAIN library. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- dynamsoft.webtwain.install.js
+This file is used to configure the dialogs which are shown when the Dynamic Web TWAIN library is not installed or needs to be upgraded. This file is already referenced inside the dynamsoft.webtwain.initiate.js
+
+
+- addon/dynamsoft.webtwain.addon.barcode.js
+This file contains the functionalities of the Barcode addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- addon/dynamsoft.webtwain.addon.ocr.js
+This file contains the functionalities of the OCR Basic addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- addon/dynamsoft.webtwain.addon.ocrpro.js
+This file contains the functionalities of the OCR Professional addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- addon/dynamsoft.webtwain.addon.pdf.js
+This file contains the functionalities of the PDF Rasterizer addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- addon/dynamsoft.webtwain.addon.webcam.js
+This file contains the functionalities of the Webcam addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- addon/dynamsoft.upload.js
+This file contains the functionalities of the Dynamsoft Upload Module. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- dynamsoft.webtwain.addon.camera.js
+This file contains the functionalities of the Camera addon. You're not supposed to change it without consulting the Dynamsoft Support Team.
+
+- src/dynamsoft.imagecore-1.7.x.wasm & dynamsoft.imageio-1.7.x.wasm & dynamsoft.imageio.js & dynamsoft.imageio_wasm-1.7.x.js & dynamsoft.imageProc-1.7.x.wasm & dynamsoft.crypto-1.7.x.wasm & dynamsoft.lts.js
+These files contain functionalities for image input & output + decode & encode.
+
+- src/dynamsoft.pdfReader-1.7.x.wasm & dynamsoft.pdfWriter-1.7.x.wasm
+These files contain functionalities for PDF reading & writing.
+
+- src/dynamsoft.viewer.css & dynamsoft.viewer.js
+These files are for buidling the UI of the Dynamic Web TWAIN library
+
+- src/dynamsoft.webtwain.css
+This file contains the style definitions for the general HTML elements created and used by the Dynamic Web TWAIN library
+
+
+====== End-user Distribution files ======
+
+Under dist/
+
+Under this directory are the installers for the Dynamsoft Service which needs to be manually installed on each client machine that uses the Dynamic Web TWAIN library as a service.
+
+- DynamsoftServiceSetup.msi
+For Windows
+
+- DynamsoftServiceSetup.pkg
+For macOS
+
+- DynamsoftServiceSetup.rpm
+- DynamsoftServiceSetup.deb
+- DynamsoftServiceSetup-arm64.deb
+- DynamsoftServiceSetup-mips64el.deb
+For Linux
+
+There is also a file for the license declaration
+
+- LICENSE
+

BIN
Resources/dist/DynamsoftServiceSetup-arm64.deb


BIN
Resources/dist/DynamsoftServiceSetup.msi


BIN
Resources/dist/DynamsoftServiceSetup.pkg


+ 113 - 0
Resources/dist/LICENSE

@@ -0,0 +1,113 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------
+
+Copyright jQuery Foundation and other contributors, https://jquery.org/
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/sizzle
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.
+
+------------------------------------------------------------------------
+
+bluebird js
+URL: https://github.com/petkaantonov/bluebird/
+
+The MIT License (MIT)
+
+Copyright (c) 2013-2020 Petka Antonov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+Copyright (c) ViliusL
+https://github.com/viliusle
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 139 - 0
Resources/dynamsoft.webtwain.config.js

@@ -0,0 +1,139 @@
+//
+// Dynamsoft JavaScript Library for Basic Initiation of Dynamic Web TWAIN
+// More info on DWT: http://www.dynamsoft.com/Products/WebTWAIN_Overview.aspx
+//
+// Copyright 2021, Dynamsoft Corporation 
+// Author: Dynamsoft Team
+// Version: 17.1.1
+//
+/// <reference path="dynamsoft.webtwain.initiate.js" />
+var Dynamsoft = Dynamsoft || { DWT: {} };
+
+///
+Dynamsoft.DWT.AutoLoad = true;
+
+///
+Dynamsoft.DWT.Containers = [{ContainerId:'dwtcontrolContainer', Width:270, Height:350}];
+
+/////////////////////////////////////////////////////////////////////////////////////
+//  WARNING:  The productKey in this file is protected by copyright law            //
+//  and international treaty provisions. Unauthorized reproduction or              //
+//  distribution of this  productKey, or any portion of it, may result in severe   //
+//  criminal and civil penalties, and will be prosecuted to the maximum            //
+//  extent possible under the law.  Further, you may not reverse engineer,         //
+//  decompile, disassemble, or modify the productKey .                             //
+/////////////////////////////////////////////////////////////////////////////////////
+/// If you need to use multiple keys on the same server, you can combine keys and write like this 
+/// Dynamsoft.DWT.ProductKey = 'key1;key2;key3';
+Dynamsoft.DWT.ProductKey = 't00996QAAALIA3OwPMSUho+zgGvwRAQ+EuxN/nu9mdbbtEnSoyLHSaYyaaYpCJ6yhG9uGC0OVTSPC1DQciFzynPrHMjvwmKSgfiu6MLk13WoSvHM1zUx1o8nMlagmMooW8AFI0jC2';
+
+///
+// Dynamsoft.DWT.ResourcesPath = 'Resources';
+
+///
+Dynamsoft.DWT.IfAddMD5InUploadHeader = false;
+
+///
+Dynamsoft.DWT.IfConfineMaskWithinTheViewer = false;
+
+
+///
+/*Dynamsoft.DWT.CustomizableDisplayInfo = {
+
+    errorMessages: {
+
+        // launch
+        ERR_MODULE_NOT_INSTALLED: 'Error: The Dynamic Web TWAIN module is not installed.',
+        ERR_BROWSER_NOT_SUPPORT: 'Error: This browser is currently not supported.',
+        ERR_CreateID_MustNotInContainers: 'Error: Duplicate ID detected for creating Dynamic Web TWAIN objects, please check and modify.',
+		ERR_CreateID_NotContainer: 'Error: The ID of the DIV for creating the new DWT object is invalid.',
+        ERR_DWT_NOT_DOWNLOADED: 'Error: Failed to download the Dynamic Web TWAIN module.',
+
+        // image view
+        limitReachedForZoomIn: "Error: You have reached the limit for zooming in",
+        limitReachedForZoomOut: "Error: You have reached the limit for zooming out",
+
+        // image editor
+        insufficientParas: 'Error: Not enough parameters.',
+        invalidAngle: 'Error: The angle you entered is invalid.',
+        invalidHeightOrWidth: "Error: The height or width you entered is invalid.",
+        imageNotChanged: "Error: You have not changed the current image."
+
+    },
+
+    // launch
+    generalMessages: {
+        checkingDWTVersion: 'Checking WebTwain version ...',
+        updatingDService: 'Dynamsoft Service is updating ...',
+        downloadingDWTModule: 'Downloading the Dynamic Web TWAIN module.',
+        refreshNeeded: 'Please REFRESH your browser.',
+        downloadNeeded: 'Please download and install the Dynamic Web TWAIN.',
+        DWTmoduleLoaded: 'The Dynamic Web TWAIN module is loaded.'
+    },
+
+    customProgressText: {
+
+        // html5 event
+        upload: 'uploading...',
+        download: 'Downloading...',
+        load: 'Loading...',
+        decode: 'Decoding...',
+        decodeTIFF: 'Decoding tiff...',
+        decodePDF: 'Decoding pdf...',
+        encode: 'Encoding...',
+        encodeTIFF: 'Encoding tiff...',
+        encodePDF: 'Encoding pdf...',
+
+        // image control
+        canvasLoading: 'Loading ...'
+    },
+
+    // image editor
+    buttons: {
+        titles: {
+            'previous': 'Previous Image',
+            'next': 'Next Image',
+            'print': 'Print Image',
+            'scan': 'Acquire new Image(s)',
+            'load': 'Load local Image(s)',
+            'rotateleft': 'Rotate Left',
+            'rotate': 'Rotate',
+            'rotateright': 'Rotate Right',
+            'deskew': 'Deskew',
+            'crop': 'Crop Selected Area',
+            'cut': 'Cut Selected Area',
+            'changeimagesize': 'Change Image Size',
+            'flip': 'Flip Image',
+            'mirror': 'Mirror Image',
+            'zoomin': 'Zoom In',
+            'originalsize': 'Show Original Size',
+            'zoomout': 'Zoom Out',
+            'stretch': 'Stretch Mode',
+            'fit': 'Fit Window',
+            'fitw': 'Fit Horizontally',
+            'fith': 'Fit Vertically',
+            'hand': 'Hand Mode',
+            'rectselect': 'Select Mode',
+            'zoom': 'Click to Zoom In',
+            'restore': 'Restore Orginal Image',
+            'save': 'Save Changes',
+            'close': 'Close the Editor',
+            'removeall': 'Remove All Images',
+            'removeselected': 'Remove All Selected Images'
+        }
+	},
+	
+    dialogText: {
+        dlgRotateAnyAngle: ['Angle :', 'Interpolation:', 'Keep size', '  OK  ', 'Cancel'],
+        dlgChangeImageSize: ['New Height :', 'New Width :', 'Interpolation method:', '  OK  ', 'Cancel'],
+        saveChangedImage: ['You have changed the image, do you want to keep the change(s)?', '  Yes  ', '  No  '],
+        selectSource: ['Select Source:', 'Select', 'Cancel', 'There is no source available!']
+    }
+};*/
+
+
+/// All callbacks are defined in the dynamsoft.webtwain.install.js file, you can customize them.
+// Dynamsoft.DWT.RegisterEvent('OnWebTwainReady', function(){
+// 		// webtwain has been inited
+// });
+

File diff suppressed because it is too large
+ 17 - 0
Resources/dynamsoft.webtwain.initiate.js


File diff suppressed because it is too large
+ 376 - 0
Resources/dynamsoft.webtwain.install.js


BIN
Resources/src/dynamsoft.crypto-1.7.1.wasm


BIN
Resources/src/dynamsoft.imageProc-1.7.1.wasm


BIN
Resources/src/dynamsoft.imagecore-1.7.1.wasm


BIN
Resources/src/dynamsoft.imageio-1.7.1.wasm


File diff suppressed because it is too large
+ 128 - 0
Resources/src/dynamsoft.imageio.js


File diff suppressed because it is too large
+ 106 - 0
Resources/src/dynamsoft.imageio_wasm-1.7.1.js


File diff suppressed because it is too large
+ 666 - 0
Resources/src/dynamsoft.lts.js


BIN
Resources/src/dynamsoft.pdfReader-1.7.1.wasm


BIN
Resources/src/dynamsoft.pdfWriter-1.7.1.wasm


File diff suppressed because it is too large
+ 2 - 0
Resources/src/dynamsoft.viewer.css


File diff suppressed because it is too large
+ 2 - 0
Resources/src/dynamsoft.viewer.js


File diff suppressed because it is too large
+ 1103 - 0
Resources/src/dynamsoft.webtwain.css


+ 29 - 0
a.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>Layui</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+</head>
+<script src="js/xscan.js"></script>
+<body>
+  <!-- <div id="xcanner-model" style="width:300px;position: absolute;border:1px solid #dddddd;background: #eeeeee;left:0; right:0;top:89px;margin:auto;box-shadow:0 1px 5px rgb(0 0 0 / 5%);border-radius:6px;z-index:10000000;">
+    <div id="xcanner-content" style="padding: 15px 20px 0px 20px;">
+      <h4 style="margin:0px;">请选择扫描仪:</h4>
+      <div id="xscanner-sourcelist">
+        <ul style="background: #fff;list-style: none;margin:0px;padding:5px;border-left:2px solid #777777;border-top:2px solid #777777;">
+          <li>1111</li>
+          <li>2222</li>
+        </ul>
+      </div>
+      <div><button style="margin:10px 10px 20px 0px;min-width: 80px;">确定</button><button style="margin:10px 10px 20px 0px;min-width: 80px;">取消</button></div>
+    </div>
+  </div> -->
+  <script src="js/xscan.js" charset="utf-8"></script>
+
+</body>
+
+</html>

+ 72 - 0
css/index.css

@@ -0,0 +1,72 @@
+.main{
+    width: 500px;
+    margin: auto;
+    margin-top:15%;
+    border:1px solid #ccc;
+}
+.main form{
+    margin: 45px 20px;
+}
+.top{
+    height: 10%;
+    background: #ccc;
+}
+.bottom{
+    position:absolute;
+    height: 5%;
+    background: #ccc;
+    bottom: 0px;
+}
+.layui-fluid{
+    padding:0px;
+}
+.container{
+    width: 100%;
+    height: 100vh;
+}
+.content{
+    height: 70%;
+    padding: 30px;
+}
+.item{
+    height: 100%;
+    /* border:1px solid red; */
+}
+.item .task{
+    border:1px solid #23e;
+    border-radius: 5px;
+    height: 100%;
+    background: #ddd;
+    padding:10px;
+    width: 100%;
+}
+.dvs-WebViewer{
+    width: 98%!important;
+    height: 100%!important;
+}
+.item .task .name,.school,.grade,.subject{
+    padding:10px;
+}
+.item .task .grade span{
+    display: inline-block;
+    width: 32%;
+}
+/* scan */
+.scan_content{
+    height: 84%;
+    padding: 10px;
+}
+.left{
+    height: 100%;
+    background: #ccc;
+}
+.middle{
+    height: 100%;
+    background: #eee;
+    padding-left:10px;
+}
+.right{
+    height: 100%;
+    background: #ccc;
+    padding-left: 10px;
+}

+ 116 - 0
index.html

@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>Layui</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+  <link rel="stylesheet" href="layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="css/index.css" media="all">
+
+</head>
+
+<body>
+  <div class="layui-fluid container">
+    <div class="layui-row top">
+      <div class="layui-col-lg12">
+      </div>
+    </div>
+    <div class="layui-row layui-col-space10 content">
+      <div class="layui-col-lg3 item">
+        <div class="task">
+          <h2 class="name">测试测试测试测试测试测试</h2>
+          <p class="school">中和中学</p>
+          <p class="grade">
+            <span>高一</span>
+            <span>19班</span>
+            <span>2021-09-05 15:14:34</span>
+          </p>
+          <p class="subject">
+            <a href="scan.html" class="layui-btn layui-btn-normal layui-btn-sm">数学</a>
+          </p>
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+
+        </div>
+      </div>
+    </div>
+    <div class="layui-row">
+      <div class="layui-col-lg12 bottom"></div>
+    </div>
+  </div>
+  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
+  <script src="layui/layui.js" charset="utf-8"></script>
+  <script src="js/api.js" charset="utf-8"></script>
+  <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
+  <script>
+    var token = localStorage.getItem("token")
+    // 获取管理员信息
+    LayuiGetJson({
+      url: ACCOUNTINFOAPI,
+      data: {},
+      token:token
+    }).then(res => {
+      console.log(res)
+    }).catch(err => {
+      window.location.href = "login.html"
+    })
+  </script>
+
+</body>
+
+</html>

+ 45 - 0
js/api.js

@@ -0,0 +1,45 @@
+var Authorization = localStorage.getItem("token")
+var LayuiGetJson = param => {
+    return new Promise((resovle, reject) => {
+        $.ajax({
+            type: param.type || "get",
+            async: param.async || true,
+            url: param.url,
+            data: param.data || {},
+            headers:{
+                "Content-Type": "application/json;charset=utf-8",
+                "Authorization": "Bearer " + Authorization
+            },
+            success: res => {
+                resovle(res);
+            },
+            error: err => {
+                reject(err);
+            }
+        })
+    })
+}
+var LayuiPostJson = param => {
+    return new Promise((resovle, reject) => {
+        $.ajax({
+            type: param.type || "post",
+            async: param.async || true,
+            url: param.url,
+            data: param.data || {},
+            header:{
+                "Content-Type": "application/json;charset=utf-8",
+                "Authorization":"Bearer " + Authorization
+            },
+            success: res => {
+                resovle(res);
+            },
+            error: err => {
+                reject(err);
+            }
+        })
+    })
+}
+// 接口配置
+const HOST = "http://47.108.130.28:8000"
+var LOGINAPI = HOST + "/v1/login"
+var ACCOUNTINFOAPI = HOST + "/v1/admin/account"

+ 68 - 0
js/scan.js

@@ -0,0 +1,68 @@
+Dynamsoft.DWT.RegisterEvent('OnWebTwainReady', Dynamsoft_OnReady);
+var DWObject;
+function Dynamsoft_OnReady() {
+    DWObject = Dynamsoft.DWT.GetWebTwain('dwtcontrolContainer');
+}
+
+function AcquireImage() {
+    if (DWObject) {
+        DWObject.SelectSource(function () {
+            var OnAcquireImageSuccess, OnAcquireImageFailure;
+
+            OnAcquireImageSuccess = OnAcquireImageFailure = function () {
+                UploadImage()
+                console.log(DWObject.CurrentImageIndexInBuffer)
+                DWObject.CloseSource();
+            };
+
+            DWObject.OpenSource();
+
+            DWObject.IfFeederEnabled = false
+            DWObject.IfShowUI = false; //Disable scanner UI.
+            DWObject.IfDisableSourceAfterAcquire = true;//Scanner source will be disabled automatically after scan.
+
+            // if (document.getElementById("ADF").checked && DWObject.IfFeederEnabled == true)  // if paper is NOT loaded on the feeder
+            if (DWObject.IfFeederEnabled && DWObject.IfFeederEnabled == true)
+            {
+                if (DWObject.IfFeederLoaded != true && DWObject.ErrorCode == 0) {
+                    alert("No paper detected! Please load papers and try again!");
+                    return;
+                }
+            }
+
+            DWObject.AcquireImage(OnAcquireImageSuccess, OnAcquireImageFailure);
+        }, function () {
+            console.log('SelectSource failed!');
+        });
+    }
+}
+
+function UploadImage() {
+    if (DWObject) {
+        // If no image in buffer, return the function
+        if (DWObject.HowManyImagesInBuffer == 0)
+            return;
+
+        var strHTTPServer = location.hostname; //The name of the HTTP server. For example: "www.dynamsoft.com";
+        var CurrentPathName = unescape(location.pathname);
+        var CurrentPath = CurrentPathName.substring(0, CurrentPathName.lastIndexOf("/") + 1);
+        var strActionPage = CurrentPath + "SaveToFile.aspx";
+
+        var strHTTPServer = "xcode.scxjc.club"
+        var strActionPage = "/api/admin/uploadfile"
+        DWObject.IfSSL = false; // Set whether SSL is used
+        DWObject.HTTPPort = 80//location.port == "" ? 80 : location.port;
+
+        var Digital = new Date();
+        var uploadfilename = Digital.getMilliseconds(); // Uses milliseconds according to local time as the file name
+        DWObject.HTTPUploadThroughPost(strHTTPServer, DWObject.CurrentImageIndexInBuffer, strActionPage, uploadfilename + ".jpg", OnHttpUploadSuccess, OnHttpUploadFailure);
+    }
+}
+
+function OnHttpUploadSuccess() {
+    console.log('successful');
+}
+
+function OnHttpUploadFailure(errorCode, errorString, sHttpResponse) {
+    alert(errorString + sHttpResponse);
+}

+ 144 - 0
js/xscan.js

@@ -0,0 +1,144 @@
+function ajax(options) {
+    var options = options || {};
+    options.type = (options.type || 'GET').toUpperCase();
+    options.dataType = options.dataType || 'json';
+    params = formatParams(options.data);
+
+    //创建-第一步
+    var xhr;
+    //非IE6
+    if (window.XMLHttpRequest) {
+        xhr = new XMLHttpRequest();
+    } else {
+        //ie6及其以下版本浏览器
+        xhr = ActiveXObject('Microsoft.XMLHTTP');
+    }
+
+    //接收-第三步
+    xhr.onreadystatechange = function () {
+        if (xhr.readyState == 4) {
+            var status = xhr.status;
+            if (status >= 200 && status < 300) {
+                options.success && options.success(xhr.responseText, xhr.responseXML);
+            } else {
+                options.error && options.error(status);
+            }
+        }
+    }
+
+    //连接和发送-第二步
+    if (options.type == 'GET') {
+        xhr.open('GET', options.url + '?' + params, true);
+        xhr.send(null);
+    } else if (options.type == 'POST') {
+        xhr.open('POST', options.url, true);
+        //设置表单提交时的内容类型
+        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+        xhr.send(params);
+    }else if (options.type == 'HEAD') {
+        xhr.open('Head', options.url + '?' + params, true);
+        xhr.send(null);
+    }
+}
+
+//格式化参数
+function formatParams(data) {
+    var arr = [];
+    for (var name in data) {
+        arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
+    }
+    // arr.push(('v='+Math.random()).replace('.',''));
+    return arr.join('&');
+}
+
+function OpenDwSource() {
+    var host = "http://localhost:19882"
+    var xsource = '<div style="width:300px;position: absolute;border:1px solid #dddddd;background: #eeeeee;left:0; right:0;top:89px;margin:auto;box-shadow:0 1px 5px rgb(0 0 0 / 5%);border-radius:6px;z-index:10000000;">';
+    xsource += '<div id="xcanner-content" style="padding: 15px 20px 0px 20px;">';
+    xsource += '<h4 style="margin:0px;">请选择扫描仪:</h4>';
+    xsource += '<div id="xscanner-sourcelist">';
+    xsource += '<ul style="background: #fff;list-style: none;margin:0px;padding:0px;border-left:2px solid #777777;border-top:2px solid #777777;">';
+    xsource += '</ul></div>';
+    xsource += '<div><button id="xscanner-confirm-btn" style="margin:10px 10px 20px 0px;min-width: 80px;">确定</button><button id="xscanner-cancel-btn" style="margin:10px 10px 20px 0px;min-width: 80px;">取消</button></div>';
+    var sourcediv = document.createElement("div")
+    sourcediv.id = "xscanner-model"
+    sourcediv.innerHTML = xsource;
+    document.getElementsByTagName("body")[0].appendChild(sourcediv)
+    // 
+    ajax({
+        url: host + '/xscanSourceList.aspx',
+        type: 'get',
+        dataType: 'json',
+        data: {},
+        success: function (response, xml) {
+            var listr = ""
+            JSON.parse(response).forEach((item, index) => {
+                if (index == 0) {
+                    listr += "<li style='background:rgb(199, 222, 252);'>" + item + "</li>";
+                } else {
+                    listr += "<li>" + item + "</li>";
+                }
+            })
+            document.getElementById("xscanner-sourcelist").children[0].innerHTML = listr;
+        },
+        error: function (status) {
+            //失败后执行的代码
+        }
+    });
+    // 确定
+    document.getElementById("xscanner-confirm-btn").addEventListener("click", function () {
+        ajax({
+            url: host + '/xscanAction.aspx',
+            type: 'GET',
+            dataType: 'json',
+            data:{tid:123},
+            success: function (response, xml) {
+                if (response) {
+
+                }
+            },
+            error: function (status) {
+                //失败后执行的代码
+            }
+        });
+        var last = null;
+        var counter = "15982"
+        var i = 0;
+        var timer = window.setInterval(function () {
+            i += 1
+            var xscannercontainer = document.getElementById("XScannerContainer")
+            xscannercontainer.style = "overflow:scroll;padding:10px 20px 20px 20px;"
+            last = xscannercontainer.firstChild;
+            ajax({
+                url: host + '/xscanImgUri.aspx',
+                type: 'GET',
+                dataType: 'json',
+                data: {t:new Date().getTime()},
+                success: function (response, xml) {
+                    console.log(response)
+                    if (response) {
+                        response.split(",").forEach((item,index)=>{
+                            var img = document.createElement("img")
+                            img.src = host + "/xscanImgReview.aspx?imgid="+item
+                            img.style = "width:100%;margin-bottom:10px;"
+                            if (last) {
+                                xscannercontainer.insertBefore(img, last)
+                            } else {
+                                xscannercontainer.append(img)
+                            }
+                        })
+                    }
+
+                },
+                error: function (status) {
+                    //失败后执行的代码
+                }
+            });
+        }, 1000)
+        document.getElementById("xscanner-model").remove();
+    })
+    // 取消
+    document.getElementById("xscanner-cancel-btn").addEventListener("click", function () {
+        document.getElementById("xscanner-model").remove();
+    })
+}

File diff suppressed because it is too large
+ 1 - 0
layui/css/layui.css


File diff suppressed because it is too large
+ 1 - 0
layui/css/modules/code.css


File diff suppressed because it is too large
+ 1 - 0
layui/css/modules/laydate/default/laydate.css


BIN
layui/css/modules/layer/default/icon-ext.png


BIN
layui/css/modules/layer/default/icon.png


File diff suppressed because it is too large
+ 1 - 0
layui/css/modules/layer/default/layer.css


BIN
layui/css/modules/layer/default/loading-0.gif


BIN
layui/css/modules/layer/default/loading-1.gif


BIN
layui/css/modules/layer/default/loading-2.gif


BIN
layui/font/iconfont.eot


File diff suppressed because it is too large
+ 554 - 0
layui/font/iconfont.svg


BIN
layui/font/iconfont.ttf


BIN
layui/font/iconfont.woff


BIN
layui/font/iconfont.woff2


File diff suppressed because it is too large
+ 5 - 0
layui/layui.js


+ 80 - 0
login.html

@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>Layui</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+  <link rel="stylesheet" href="layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="css/index.css" media="all">
+
+</head>
+
+<body>
+  <div class="main">
+    <form class="layui-form" action="" lay-filter="login">
+      <div class="layui-form-item">
+        <label class="layui-form-label">用户名</label>
+        <div class="layui-input-block">
+          <input type="text" name="username" lay-verify="username" autocomplete="off" placeholder="请输入用户名"
+            class="layui-input">
+        </div>
+      </div>
+      <div class="layui-form-item">
+        <label class="layui-form-label">密码</label>
+        <div class="layui-input-block">
+          <input type="password" name="password" lay-verify="password" lay-reqtext="请输入密码" placeholder="请输入密码"
+            autocomplete="off" class="layui-input">
+        </div>
+      </div>
+      <div class="layui-form-item">
+        <div class="layui-input-block">
+          <button type="submit" class="layui-btn" lay-submit="" lay-filter="demo1">登录</button>
+        </div>
+      </div>
+    </form>
+  </div>
+  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
+  <script src="layui/layui.js" charset="utf-8"></script>
+  <script src="js/api.js" charset="utf-8"></script>
+  <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
+  <script>
+    layui.use(['form','laytpl'], function () {
+      var form = layui.form
+      var layer = layui.layer
+      var laytpl = layui.laytpl
+      //自定义验证规则
+      form.verify({
+        username: function (value) {
+          console.log(value)
+          if (value.length < 1) {
+            return '请输入用户名!';
+          }
+        }
+        , password: [
+          /^[\S]{6,12}$/
+          , '密码必须6到12位,且不能出现空格!'
+        ]
+      });
+      //监听提交
+      form.on('submit(login)', function (data) {
+        var data = form.val("login")
+        LayuiPostJson({
+          url: LOGINAPI,
+          data: data
+        }).then(res => {
+          localStorage.setItem("token",res.access_token)
+          window.location.href = "index.html"
+        }).catch(err => {
+          layer.msg("账号或密码错误!")
+        })
+        return false;
+      });
+    });
+  </script>
+
+</body>
+
+</html>

+ 89 - 0
scan.html

@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>Layui</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+  <link rel="stylesheet" href="layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="css/index.css" media="all">
+
+</head>
+
+<body>
+  <div class="layui-fluid container">
+    <div class="layui-row top">
+      <div class="layui-col-lg12">
+      </div>
+    </div>
+    <div class="layui-row layui-col-space10 scan_content">
+      <div class="layui-col-lg3 left">
+        <div class="task">
+          <h2 class="name">测试测试测试测试测试测试</h2>
+          <p class="school">中和中学</p>
+          <p class="grade">
+            <span>高一</span>
+            <span>19班</span>
+            <span>2021-09-05 15:14:34</span>
+          </p>
+          <p class="subject">
+            <a href="" class="layui-btn layui-btn-normal layui-btn-sm">数学</a>
+          </p>
+        </div>
+      </div>
+      <div class="layui-col-lg7 middle">
+        <div class="task">
+          <h2 class="name">测试测试测试测试测试测试</h2>
+          <p class="school">中和中学</p>
+          <p class="grade">
+            <span>高一</span>
+            <span>19班</span>
+            <span>2021-09-05 15:14:34</span>
+          </p>
+          <p class="subject">
+            <a href="" class="layui-btn layui-btn-normal layui-btn-sm">数学</a>
+          </p>
+        </div>
+      </div>
+      <div class="layui-col-lg2 right">
+        <div class="task">
+          <h2 class="name">测试测试测试测试测试测试</h2>
+          <p class="school">中和中学</p>
+          <p class="grade">
+            <span>高一</span>
+            <span>19班</span>
+            <span>2021-09-05 15:14:34</span>
+          </p>
+          <p class="subject">
+            <a href="" class="layui-btn layui-btn-normal layui-btn-sm">开始</a>
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="layui-row">
+      <div class="layui-col-lg12 bottom"></div>
+    </div>
+  </div>
+  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
+  <script src="layui/layui.js" charset="utf-8"></script>
+  <script src="js/api.js" charset="utf-8"></script>
+  <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
+  <script>
+    var token = localStorage.getItem("token")
+    // 获取管理员信息
+    LayuiGetJson({
+      url: ACCOUNTINFOAPI,
+      data: {},
+      token:token
+    }).then(res => {
+      console.log(res)
+    }).catch(err => {
+      window.location.href = "login.html"
+    })
+  </script>
+
+</body>
+
+</html>

+ 78 - 0
test.html

@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <title>Layui</title>
+  <meta name="renderer" content="webkit">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+  <link rel="stylesheet" href="layui/css/layui.css" media="all">
+  <link rel="stylesheet" href="css/index.css" media="all">
+</head>
+
+<body>
+  <div class="layui-fluid container">
+    <div class="layui-row top">
+      <div class="layui-col-lg12">
+      </div>
+    </div>
+    <div class="layui-row layui-col-space10 content">
+      <div class="layui-col-lg3 item">
+          <div class="task">
+
+          </div>
+      </div>
+      <div class="layui-col-lg6 item">
+        <div class="task" id="XScannerContainer">
+
+        </div>
+      </div>
+      <div class="layui-col-lg3 item">
+        <div class="task">
+            <button type="button" class="layui-btn layui-btn-normal" onclick="OpenDwSource()">开始扫描</button>
+        </div>
+      </div>
+    </div>
+    <div class="layui-row">
+      <div class="layui-col-lg12 bottom"></div>
+    </div>
+  </div>
+  <script src="js/xscan.js" charset="utf-8"></script>
+  <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
+  <script>
+    layui.use(['form'], function () {
+      var form = layui.form
+      layer = layui.layer
+      //自定义验证规则
+      form.verify({
+        username: function (value) {
+          console.log(value)
+          if (value.length < 1) {
+            return '请输入用户名!';
+          }
+        }
+        , password: [
+          /^[\S]{6,12}$/
+          , '密码必须6到12位,且不能出现空格!'
+        ]
+      });
+      //监听提交
+      form.on('submit(login)', function (data) {
+        var data = form.val("login")
+        LayuiPostJson({
+          url: LOGINAPI,
+          data: data
+        }).then(res => {
+          localStorage.setItem("token",res.access_token)
+        }).catch(err => {
+          layer.msg("账号或密码错误!")
+        })
+        return false;
+      });
+    });
+  </script>
+
+</body>
+
+</html>

+ 172 - 0
twainscan.py

@@ -0,0 +1,172 @@
+#!-*-coding:utf-8 -*-
+import twain 
+import traceback
+import uuid
+import sys,os
+import locale
+import SocketServer
+import BaseHTTPServer 
+import re
+import json
+from Queue import Queue
+from threading import Thread
+from multiprocessing import Process
+
+reload(sys)
+sys.setdefaultencoding("utf-8")
+
+root = "c:\\AppData\\Xscanner"
+xqueue = Queue()
+
+class XHttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+    """
+    """
+    def do_HEAD(self):
+        """Serve a HEAD request."""
+        self.send_response(200)
+        self.send_header("Access-Control-Allow-Origin","*")
+        self.send_header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE,HEAD")
+        self.send_header("Access-Control-Allow-Headers","x-requested-with,content-type")
+        self.send_header("Content-Type","application/json;charset=UTF-8")
+        self.end_headers()
+            
+    def read_local_file(self,path):
+        f = open(path,'rb')
+        read = f.read()
+        f.close()
+        #print path
+        return read
+        
+    def send_response(self, code, message=None):
+        """Send the response header and log the response code.
+
+        Also send two standard headers with the server software
+        version and the current date.
+
+        """
+        self.log_request(code)
+        if message is None:
+            if code in self.responses:
+                message = self.responses[code][0]
+            else:
+                message = ''
+        if self.request_version != 'HTTP/0.9':
+            self.wfile.write("%s %d %s\r\n" %
+                             (self.protocol_version, code, message))
+        self.send_header('Date', self.date_time_string())
+        
+    def do_GET(self):
+        """
+        """
+        if self.path.split("?")[0] == '/xscanAction.aspx':
+            print self.path
+            try:
+                id = int(re.search(r"tid=(.*)",self.path).groups()[0])
+            except Exception as e:
+                id = None
+                print e
+            if id:
+                t = Thread(target = start_scan)
+                t.start()
+                self.send_response(200)
+                self.send_header("Content-Type","text/html;charset=UTF-8")
+                self.end_headers()
+                self.wfile.write("success")
+        if self.path.split("?")[0] == '/xscanSourceList.aspx':
+            snames = get_source_names()
+            self.send_response(200)
+            self.send_header("Access-Control-Allow-Origin","*")
+            self.send_header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE")
+            self.send_header("Access-Control-Allow-Headers","x-requested-with,content-type")
+            self.send_header("Content-Type","application/json;charset=UTF-8")
+            self.end_headers()
+            self.wfile.write(json.dumps(snames))
+            
+        if self.path.split("?")[0] == '/xscanImgUri.aspx':
+            imgs = []
+            while True:
+                if not xqueue.empty():
+                    imgs.append(xqueue.get(block=False))
+                    continue
+                break
+            img = ",".join(imgs)
+            self.send_response(200)
+            self.send_header("Access-Control-Allow-Origin","*")
+            self.send_header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE")
+            self.send_header("Access-Control-Allow-Headers","x-requested-with,content-type")
+            
+            self.send_header("Content-Type","application/json;charset=UTF-8")
+            self.end_headers()
+            self.wfile.write(img)
+            
+        if self.path.split("?")[0] == '/xscanImgReview.aspx':
+            try:
+                imgid = re.search(r"imgid=(.*)",self.path).groups()[0]
+            except Exception as e:
+                imgid = None
+                print e
+               
+            imgpath = os.path.join(root,imgid)
+            content = self.read_local_file(imgpath)
+            
+            self.send_response(200)
+            self.send_header("Access-Control-Allow-Origin","*")
+            self.send_header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE")
+            self.send_header("Access-Control-Allow-Headers","x-requested-with,content-type")
+            
+            self.send_header("Content-Type","image/png")
+            #self.send_header("Content-Type","application/json;charset=UTF-8")
+            self.end_headers()
+            self.wfile.write(content)
+        if self.path == '/':
+            self.path = "index.html"
+        
+        
+def server():
+    try:
+        addr = len(sys.argv) < 2 and "localhost" or sys.argv[1]
+        port = len(sys.argv) < 3 and 19882 or locale.atoi(sys.argv[2])
+
+        handler = XHttpHandler
+        httpd = SocketServer.TCPServer((addr, port), handler)
+        print ("HTTP server is at: http://%s:%d/" % (addr, port))
+        httpd.serve_forever()
+    except KeyboardInterrupt:
+        sys.exit()
+        
+def get_source_names():
+    """
+    """
+    sm = twain.SourceManager(0)
+    return sm.GetSourceList()
+
+def start_scan():
+    try:
+        sm = twain.SourceManager(0) 
+        ss = sm.OpenSource("AT360") 
+        ss.RequestAcquire(0,0) 
+        try: 
+            if not os.path.exists(root):
+                os.makedirs(root)
+            while True:
+                try:
+                    rv = ss.XferImageNatively()
+                    if rv is None: 
+                        break 
+                    else: 
+                        (handle, count) = rv
+                        imgname = '{}.png'.format(uuid.uuid4())
+                        imgfile = os.path.join(root,imgname)
+                        twain.DIBToBMFile(handle, imgfile) 
+                        xqueue.put(imgname)
+                except:
+                    traceback.print_exc()
+                    break
+        except: 
+            traceback.print_exc()
+            print "Error!"
+    except Exception:
+        return False,u"找不到扫描仪!"
+        
+if __name__ == "__main__":
+    server()

+ 45 - 0
xscanserver.py

@@ -0,0 +1,45 @@
+#!-*-coding:utf-8 -*-
+import sys
+import win32serviceutil 
+import win32service 
+import win32event
+from twainscan import server 
+import servicemanager
+import winerror
+ 
+class PythonService(win32serviceutil.ServiceFramework): 
+    #服务名
+    _svc_name_ = "PythonService"
+    #服务在windows系统中显示的名称
+    _svc_display_name_ = "Python Service Test"
+    #服务的描述
+    _svc_description_ = "This code is a Python service Test"
+ 
+    def __init__(self, args): 
+        win32serviceutil.ServiceFramework.__init__(self, args) 
+        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
+ 
+    def SvcDoRun(self):
+        # 把自己的代码放到这里,就OK
+        # 等待服务被停止
+        server()
+        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) 
+            
+    def SvcStop(self): 
+        # 先告诉SCM停止这个过程 
+        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
+        # 设置事件 
+        win32event.SetEvent(self.hWaitStop) 
+ 
+if __name__=='__main__': 
+    if len(sys.argv) == 1:
+        try:
+            evtsrc_dll = os.path.abspath(servicemanager.__file__)
+            servicemanager.PrepareToHostSingle(PythonService)
+            servicemanager.Initialize('PythonService', evtsrc_dll)
+            servicemanager.StartServiceCtrlDispatcher()
+        except win32service.error, details:
+            if details[0] == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
+                win32serviceutil.usage()
+    else:
+        win32serviceutil.HandleCommandLine(PythonService)