条码通常用于识别零售产品。我们也可以使用它们来标记文档。例如,我们可能需要扫描一批表单。每份表单都有几页内容,第一页上有一个表示表单编号的条码。我们可以使用条码拆分文档,并将表单编号和拆分的文档进行对应。
在本文中,我们将编写一个Web应用,使用Dynamic Web TWAIN扫描文档,并通过Dynamsoft Barcode Reader读取的条码对文档进行拆分。
最终结果的演示视频:
在网页中扫描文档
让我们先编写一个扫描文档的网页。
-
创建一个包含以下模板的新HTML文件。
<!DOCTYPE html> <html> <head> <title>Document Scanning via TWAIN</title> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" /> </head> <body> <h2>Document Scanning via TWAIN</h2> <script type="text/javascript"> </script> </body> </html>
-
在head引入Dynamic Web TWAIN的库。
<script src="https://unpkg.com/dwt@18.5.0/dist/dynamsoft.webtwain.min.js"></script>
-
初始化一个Web TWAIN的实例并将其控件绑定到一个容器。可以在此处申请其许可证。
HTML:
<div id="dwtcontrolContainer"></div>
JavaScript:
let DWObject; let scanners; initDWT(); function initDWT(){ Dynamsoft.DWT.AutoLoad = false; Dynamsoft.DWT.Containers = []; Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.5.0/dist"; let oneDayTrialLicense = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; Dynamsoft.DWT.ProductKey = oneDayTrialLicense; Dynamsoft.DWT.CreateDWTObjectEx( { WebTwainId: 'dwtcontrol' }, function(obj) { DWObject = obj; DWObject.Viewer.bind(document.getElementById('dwtcontrolContainer')); DWObject.Viewer.height = "480px"; DWObject.Viewer.width = "360px"; DWObject.Viewer.show(); DWObject.Viewer.setViewMode(2,2); }, function(err) { console.log(err); } ); }
-
列出连接的扫描仪。
let scanners; async function loadScanners(){ scanners = await DWObject.GetDevicesAsync(); let selScanners = document.getElementById("select-scanner"); selScanners.innerHTML = ""; for (let index = 0; index < scanners.length; index++) { const scanner = scanners[index]; let option = new Option(scanner.displayName,index); selScanners.appendChild(option); } }
-
使用所选扫描仪扫描文档。它将显示扫描仪的配置界面以执行扫描。
HTML:
<input type="button" value="Scan" onclick="AcquireImage();" />
JavaScript:
async function AcquireImage() { if (DWObject) { const selectedIndex = document.getElementById("select-scanner").selectedIndex; const options = { IfShowUI:true, }; await DWObject.SelectDeviceAsync(scanners[selectedIndex]); await DWObject.OpenSourceAsync(); await DWObject.AcquireImageAsync(options); await DWObject.CloseSourceAsync(); } }
除了使用扫描仪自身的界面进行配置外,我们通过代码直接配置扫描行为。例如自动进纸、分辨率、像素类型、双页扫描等等。
HTML:
<label> Auto Document Feeder: <input type="checkbox" id="ADF"/> </label> <br/> <label> Duplex: <input type="checkbox" id="duplex"/> </label> <br/> <label> Resolution: <select id="select-resolution"> <option value="100">100</option> <option value="200">200</option> <option value="300" selected>300</option> </select> </label> <br/> <label> Pixel Type: <select id="select-pixeltype"> <option>Black & White</option> <option>Gray</option> <option selected>Color</option> </select> </label>
JavaScript:
const selectedIndex = document.getElementById("select-scanner").selectedIndex; const options = { IfShowUI:document.getElementById("showUI").checked, PixelType:document.getElementById("select-pixeltype").selectedIndex, Resolution:document.getElementById("select-resolution").selectedOptions[0].value, IfFeederEnabled:document.getElementById("ADF").checked, IfDuplexEnabled:document.getElementById("duplex").checked }; await DWObject.SelectDeviceAsync(scanners[selectedIndex]); await DWObject.OpenSourceAsync(); await DWObject.AcquireImageAsync(options); await DWObject.CloseSourceAsync();
-
加载已有文件。这可以方便后续的文档拆分测试。
HTML:
<input type="button" value="Load Files" onclick="LoadFiles();" />
JavaScript:
function LoadFiles(){ DWObject.LoadImageEx( "", //file name can be empty if "Open File" dialog is called. Dynamsoft.DWT.EnumDWT_ImageType.IT_ALL, function () { console.log("success"); }, function (errorCode, errorString) { console.log(errorString); } ); }
读取页面上的条码
接下来,让我们使用 Dynamsoft Barcode Reader来读取页面上的条码。
-
包含Dynamsoft Barcode Reader使用的库。
<script src="https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.30/dist/core.js"></script> <script src="https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.2.10/dist/dbr.js"></script> <script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.30/dist/cvr.js"></script> <script src="https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.21/dist/license.js"></script>
-
初始化其许可证。可以在此处申请许可证。
Dynamsoft.License.LicenseManager.initLicense("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="); //one-day trial
-
创建Capture Vision Router的实例以调用Dynamsoft Barcode Reader。
Dynamsoft.Core.CoreModule.loadWasm(["dbr"]); //load the wasm files of barcode reader let router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
-
编写一个将页面图像转换为blob的函数。
async function convertToBlob(index){ return new Promise((resolve, reject) => { DWObject.ConvertToBlob( [index], Dynamsoft.DWT.EnumDWT_ImageType.IT_PNG, function (result, indices, type) { resolve(result); }, function (errorCode, errorString) { reject(errorString); } ); }) }
-
从blob读取条码。
const i = 0; //the first scanned page const blob = await convertToBlob(i); let barcodeReadingResult = await router.capture(blob, "ReadBarcodes_Balance");
按条码拆分文档
不同的文档使用条码的方式各不相同。通常,有两种方式:将条码放在第一页,将条码放在最后一页。
-
创建用于选择使用哪种方式的
select
元素。<label> Barcode Position: <select class="barcode-position"> <option>First Page</option> <option>Last Page</option> </select> </label>
-
读取每页上的条码,并根据页面是否包含条码进行拆分。
const FIRST = 0; const LAST = 1; const total = DWObject.HowManyImagesInBuffer; let documents = []; let doc; for (let i = 0; i < total; i++) { DWObject.SelectImages([i]); const blob = await convertToBlob(i); let barcodeReadingResult = await router.capture(blob, "ReadBarcodes_Balance"); if (barcodeReadingResult.items.length>0) { if (doc) { if (barcodePosition === LAST) { doc.imageIndex.push(i); doc.barcodes = barcodeReadingResult.items; } documents.push(doc); } doc = {barcodes:[],imageIndex:[]} //reinit a document if (barcodePosition === FIRST) { doc.imageIndex.push(i); doc.barcodes = barcodeReadingResult.items; } }else{ if (barcodePosition === FIRST) { if (doc) { doc.imageIndex.push(i); } }else{ if (!doc) { doc = {barcodes:[],imageIndex:[]} //init a document } doc.imageIndex.push(i); } } } if (doc) { documents.push(doc); }
-
列出按条码分类的文档。
function ListClassifiedDocuments(){ const documentsContainer = document.getElementsByClassName("documents")[0]; documentsContainer.innerHTML = ""; for (let i = 0; i < documents.length; i++) { const doc = documents[i]; let documentContainer = document.createElement("div"); let title = document.createElement("div"); title.innerHTML = doc.barcodes[0].text; documentContainer.appendChild(title); let thumbnailsContainer = document.createElement("div"); thumbnailsContainer.className = "thumbnails"; for (let j = 0; j < doc.imageIndex.length; j++) { const imageIndex = doc.imageIndex[j]; const a = document.createElement("a"); const thumbnailImage = document.createElement("img"); thumbnailImage.className = "thumbnail"; thumbnailImage.src = DWObject.GetImageURL(imageIndex); a.appendChild(thumbnailImage); a.href = thumbnailImage.src; a.target = "_blank"; thumbnailsContainer.appendChild(a); } documentContainer.appendChild(thumbnailsContainer); let saveButton = document.createElement("button"); saveButton.innerText = "Save as PDF"; saveButton.className = "save-button"; saveButton.type = "button"; documentContainer.appendChild(saveButton); saveButton.addEventListener("click",function(){ DWObject.SelectImages(doc.imageIndex); DWObject.SaveSelectedImagesAsMultiPagePDF("form-"+(i+1)+".pdf") }) documentsContainer.appendChild(documentContainer); } }
源代码
欢迎下载源代码并尝试使用:
https://github.com/tony-xlh/Dynamic-Web-TWAIN-samples/tree/main/Classification-with-Barcode