Merge branch 'develop' of https://gitlab.steamware.net/egalware/egwcorelib into develop
This commit is contained in:
@@ -91,11 +91,41 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BarcodeReader ScanResult="(e) => ScanDoneHandler(e)"
|
||||
ScanBtnTitle="Scan"
|
||||
ResetBtnTitle="Reset"
|
||||
CloseBtnTitle="Close"
|
||||
UseBuiltinDiv="false"
|
||||
@ref="barcodeReaderCustom"
|
||||
SelectDeviceBtnTitle="Select Device">
|
||||
</BarcodeReader>
|
||||
|
||||
<div @ref="barcodeReaderCustom.Element" class="d-flex justify-content-center">
|
||||
@* <div style="width: 480px; max-width: 100%"> *@
|
||||
<div class="col-12 col-md-8 col-lg-6">
|
||||
<button class="btn btn-outline-success p-2 m-1 w-25" data-action="startButton">Scan</button>
|
||||
<button class="btn btn-outline-success p-2 m-1 w-25" data-action="resetButton">Reset</button>
|
||||
|
||||
<div data-action="sourceSelectPanel" style="display:none">
|
||||
<label for="sourceSelect">Source:</label>
|
||||
<select data-action="sourceSelect" style="max-width:100%" class="form-control">
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<video id="video" playsinline="true" autoplay="true" class="w-100 h-100 border rounded shadow" muted="true"></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private int currentCount = 0;
|
||||
|
||||
protected BarcodeReader barcodeReaderCustom { get; set; } = null!;
|
||||
protected Random rnd = new Random();
|
||||
|
||||
protected async Task ScanDoneHandler(string value)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
}
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
||||
|
||||
@if (UseBuiltinDiv)
|
||||
{
|
||||
<div class="modal alert-popup" tabindex="-1" style="display:block" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<!-- Edit form for the current item -->
|
||||
<div class="modal-body" @ref="Element">
|
||||
|
||||
<button class="btn btn-primary p-2 m-1 w-25" data-action="startButton">@ScanBtnTitle</button>
|
||||
<button class="btn btn-secondary p-2 m-1 w-25" data-action="resetButton">@ResetBtnTitle</button>
|
||||
<button type="button" class="btn btn-info p-2 m-1 w-25" data-action="closeButton">@CloseBtnTitle</button>
|
||||
|
||||
<div data-action="sourceSelectPanel" style="display:none">
|
||||
<label for="sourceSelect">@SelectDeviceBtnTitle:</label>
|
||||
<select data-action="sourceSelect" style="max-width:100%" class="form-select form-control">
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<video id="video"
|
||||
muted
|
||||
webkit-playsinline
|
||||
playsinline
|
||||
x-webkit-airplay="allow"
|
||||
x5-video-player-type="h5"
|
||||
x5-video-player-fullscreen="true"
|
||||
x5-video-orientation="portraint"
|
||||
style="min-height:150px;max-height:50%; max-width: 100%;border: 1px solid gray"></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using EgwCoreLib.Utils;
|
||||
using ZXingBlazor.Components;
|
||||
|
||||
namespace EgwCoreLib.Razor
|
||||
{
|
||||
public partial class BarcodeReader : IAsyncDisposable
|
||||
{
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IJSRuntime? JS { get; set; }
|
||||
|
||||
private IJSObjectReference? module;
|
||||
|
||||
private DotNetObjectReference<BarcodeReader>? Instance { get; set; }
|
||||
|
||||
[NotNull]
|
||||
private StorageService? Storage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scan button title
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string ScanBtnTitle { get; set; } = "扫码";
|
||||
|
||||
/// <summary>
|
||||
/// Reset button title
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string ResetBtnTitle { get; set; } = "复位";
|
||||
|
||||
/// <summary>
|
||||
/// Close button title
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string CloseBtnTitle { get; set; } = "关闭";
|
||||
|
||||
/// <summary>
|
||||
/// Select device button title
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string SelectDeviceBtnTitle { get; set; } = "选择设备";
|
||||
|
||||
/// <summary>
|
||||
/// Scan result callback method
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback<string> ScanResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Close scan code callback method
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public EventCallback Close { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Error callback method
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string, Task>? OnError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use builtin Div
|
||||
/// </summary>
|
||||
[Parameter] public bool UseBuiltinDiv { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Decode only Pdf417 format
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Pdf417Only { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Decode Once or Decode Continuously, default is Once
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool Decodeonce { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Decode All Formats, performance is poor, you can set options.formats to customize specify the encoding formats. The default is false
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool DecodeAllFormats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ZXingOptions
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ZXingOptions? Options { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ElementReference Element { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Device ID
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? DeviceID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Save the last used device ID to be called automatically next time
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool SaveDeviceID { get; set; } = true;
|
||||
|
||||
// To prevent making JavaScript interop calls during prerendering
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!firstRender) return;
|
||||
Storage = new StorageService(JS);
|
||||
module = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js" + "?v=" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
|
||||
Instance = DotNetObjectReference.Create(this);
|
||||
if (Options == null)
|
||||
{
|
||||
Options = new ZXingOptions()
|
||||
{
|
||||
Pdf417 = Pdf417Only,
|
||||
Decodeonce = Decodeonce,
|
||||
DecodeAllFormats = DecodeAllFormats,
|
||||
//TRY_HARDER = true
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
if (SaveDeviceID) DeviceID = await Storage.GetValue("CamsDeviceID", DeviceID);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
await module.InvokeVoidAsync("init", Instance, Element, Element.Id, Options, DeviceID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (OnError != null) await OnError.Invoke(e.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
await module!.InvokeVoidAsync("start", Element.Id);
|
||||
}
|
||||
|
||||
public async Task Stop()
|
||||
{
|
||||
await module!.InvokeVoidAsync("stop", Element.Id);
|
||||
}
|
||||
|
||||
public async Task Reload()
|
||||
{
|
||||
await module!.InvokeVoidAsync("reload", Element.Id);
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task GetResult(string val) => await ScanResult.InvokeAsync(val);
|
||||
|
||||
[JSInvokable]
|
||||
public async Task CloseScan() => await Close.InvokeAsync();
|
||||
|
||||
[JSInvokable]
|
||||
public async Task GetError(string err)
|
||||
{
|
||||
if (OnError != null) await OnError.Invoke(err);
|
||||
}
|
||||
|
||||
async ValueTask IAsyncDisposable.DisposeAsync()
|
||||
{
|
||||
await module!.InvokeVoidAsync("destroy", Element.Id);
|
||||
Instance?.Dispose();
|
||||
if (module is not null)
|
||||
{
|
||||
await module.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选择摄像头回调方法
|
||||
/// </summary>
|
||||
/// <param name="base64encodedstring"></param>
|
||||
/// <returns></returns>
|
||||
[JSInvokable]
|
||||
public async Task SelectDeviceID(string deviceID, string deviceName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SaveDeviceID)
|
||||
{
|
||||
await Storage.SetValue("CamsDeviceID", deviceID);
|
||||
await Storage.SetValue("CamsDeviceName", deviceName);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#region StorageService
|
||||
private class StorageService
|
||||
{
|
||||
private readonly IJSRuntime JSRuntime;
|
||||
|
||||
public StorageService(IJSRuntime jsRuntime)
|
||||
{
|
||||
JSRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public async Task SetValue<TValue>(string key, TValue value)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("eval", $"localStorage.setItem('{key}', '{value}')");
|
||||
}
|
||||
|
||||
public async Task<TValue?> GetValue<TValue>(string key, TValue? def)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cValue = await JSRuntime.InvokeAsync<TValue>("eval", $"localStorage.getItem('{key}');");
|
||||
return cValue ?? def;
|
||||
}
|
||||
catch
|
||||
{
|
||||
var cValue = await JSRuntime.InvokeAsync<string>("eval", $"localStorage.getItem('{key}');");
|
||||
if (cValue == null)
|
||||
return def;
|
||||
|
||||
var newValue = GetValueI<TValue>(cValue);
|
||||
return newValue ?? def;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static T? GetValueI<T>(string value)
|
||||
{
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
|
||||
if (converter != null)
|
||||
{
|
||||
return (T?)converter.ConvertFrom(value);
|
||||
}
|
||||
return default;
|
||||
//return (T)Convert.ChangeType(value, typeof(T));
|
||||
}
|
||||
|
||||
public async Task RemoveValue(string key)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("eval", $"localStorage.removeItem('{key}')");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
import './lib/zxing/zxing.min.js';
|
||||
let codeReader = null;
|
||||
let id = null;
|
||||
let supportsVibrate = false;
|
||||
let opt = null;
|
||||
let inst = null;
|
||||
let selectedDeviceId = null;
|
||||
let deviceID = null;
|
||||
let element = null;
|
||||
let debug = false;
|
||||
export function vibrate() {
|
||||
if (supportsVibrate) navigator.vibrate(1000);
|
||||
}
|
||||
export function init(instance, ele, elementid, options, deviceid) {
|
||||
console.log('init' + elementid);
|
||||
inst = instance;
|
||||
opt = options;
|
||||
id = elementid;
|
||||
deviceID = deviceid;
|
||||
element = ele;
|
||||
debug = options.debug;
|
||||
supportsVibrate = "vibrate" in navigator;
|
||||
let startButton = element.querySelector("[data-action=startButton]");
|
||||
let resetButton = element.querySelector("[data-action=resetButton]");
|
||||
let closeButton = element.querySelector("[data-action=closeButton]");
|
||||
|
||||
if (startButton) startButton.addEventListener('click', () => {
|
||||
start(elementid);
|
||||
})
|
||||
|
||||
if (resetButton) resetButton.addEventListener('click', () => {
|
||||
stop(elementid);
|
||||
if (debug) console.log('Reset.')
|
||||
})
|
||||
|
||||
if (closeButton) closeButton.addEventListener('click', () => {
|
||||
stop(elementid);
|
||||
if (debug) console.log('closeButton.')
|
||||
instance.invokeMethodAsync("CloseScan");
|
||||
})
|
||||
|
||||
load(elementid);
|
||||
}
|
||||
|
||||
export function reload(elementid) {
|
||||
load(elementid);
|
||||
}
|
||||
|
||||
function genHints(opt) {
|
||||
const hints = new Map();
|
||||
if (opt.TRY_HARDER) {
|
||||
hints.set(ZXing.DecodeHintType.TRY_HARDER, opt.TRY_HARDER);
|
||||
}
|
||||
if (opt.ASSUME_CODE_39_CHECK_DIGIT) {
|
||||
hints.set(ZXing.DecodeHintType.ASSUME_CODE_39_CHECK_DIGIT, opt.ASSUME_CODE_39_CHECK_DIGIT);
|
||||
}
|
||||
if (opt.ASSUME_GS1) {
|
||||
hints.set(ZXing.DecodeHintType.ASSUME_GS1, opt.ASSUME_GS1);
|
||||
}
|
||||
if (opt.CHARACTER_SET) {
|
||||
hints.set(ZXing.DecodeHintType.CHARACTER_SET, opt.CHARACTER_SET);
|
||||
}
|
||||
if (opt.OTHER) {
|
||||
hints.set(ZXing.DecodeHintType.OTHER, opt.OTHER);
|
||||
}
|
||||
if (opt.PURE_BARCODE) {
|
||||
hints.set(ZXing.DecodeHintType.PURE_BARCODE, opt.PURE_BARCODE);
|
||||
}
|
||||
if (opt.RETURN_CODABAR_START_END) {
|
||||
hints.set(ZXing.DecodeHintType.RETURN_CODABAR_START_END, opt.RETURN_CODABAR_START_END);
|
||||
}
|
||||
if (opt.TRY_HARDER) {
|
||||
hints.set(ZXing.DecodeHintType.TRY_HARDER, opt.TRY_HARDER);
|
||||
}
|
||||
return hints;
|
||||
}
|
||||
|
||||
export function load(elementid) {
|
||||
if (id == elementid) {
|
||||
|
||||
const sourceSelect = element.querySelector("[data-action=sourceSelect]");
|
||||
const sourceSelectPanel = element.querySelector("[data-action=sourceSelectPanel]");
|
||||
const hints = genHints(opt);
|
||||
|
||||
if (opt.pdf417) {
|
||||
codeReader = new ZXing.BrowserPDF417Reader(hints);
|
||||
if (debug) console.log('ZXing code PDF417 reader initialized')
|
||||
} else if (opt.decodeAllFormats) {
|
||||
const formats = opt.formats;
|
||||
hints.set(ZXing.DecodeHintType.POSSIBLE_FORMATS, formats);
|
||||
codeReader = new ZXing.BrowserMultiFormatReader(hints)
|
||||
if (debug) console.log('ZXing code reader initialized with all formats')
|
||||
} else {
|
||||
codeReader = new ZXing.BrowserMultiFormatReader(hints)
|
||||
if (debug) console.log('ZXing code reader initialized')
|
||||
}
|
||||
codeReader.timeBetweenDecodingAttempts = opt.timeBetweenDecodingAttempts;
|
||||
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ audio: false, video: true })
|
||||
.then(() => {
|
||||
|
||||
codeReader.listVideoInputDevices()
|
||||
.then((videoInputDevices) => {
|
||||
if (deviceID != null) {
|
||||
selectedDeviceId = deviceID
|
||||
} else if (videoInputDevices.length > 1) {
|
||||
selectedDeviceId = videoInputDevices[1].deviceId
|
||||
} else {
|
||||
selectedDeviceId = videoInputDevices[0].deviceId
|
||||
}
|
||||
if (debug) console.log('videoInputDevices:' + videoInputDevices.length);
|
||||
if (videoInputDevices.length > 1) {
|
||||
sourceSelect.innerHTML = '';
|
||||
videoInputDevices.forEach((device) => {
|
||||
const sourceOption = document.createElement('option');
|
||||
if (device.label === '') {
|
||||
sourceOption.text = 'Camera' + (sourceSelect.length + 1);
|
||||
} else {
|
||||
sourceOption.text = device.label
|
||||
}
|
||||
sourceOption.value = device.deviceId
|
||||
if (selectedDeviceId != null && device.deviceId == selectedDeviceId) {
|
||||
sourceOption.selected = true
|
||||
}
|
||||
sourceSelect.appendChild(sourceOption)
|
||||
})
|
||||
|
||||
sourceSelect.onchange = () => {
|
||||
selectedDeviceId = sourceSelect.value;
|
||||
inst.invokeMethodAsync('SelectDeviceID', selectedDeviceId, sourceSelect.options[sourceSelect.selectedIndex].text);
|
||||
codeReader.reset();
|
||||
start(elementid);
|
||||
}
|
||||
|
||||
sourceSelectPanel.style.display = 'block'
|
||||
}
|
||||
|
||||
start(elementid);
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
inst.invokeMethodAsync("GetError", err + '');
|
||||
})
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`An error occurred: ${err}`);
|
||||
inst.invokeMethodAsync('GetError', `An error occurred: ${err}`);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function start(elementid) {
|
||||
if (undefined !== codeReader && null !== codeReader && id == elementid) {
|
||||
if (opt.decodeonce) {
|
||||
codeReader.decodeOnceFromVideoDevice(selectedDeviceId, 'video').then((result) => {
|
||||
if (debug) console.log(result)
|
||||
vibrate();
|
||||
if (debug) console.log('autostop');
|
||||
codeReader.reset();
|
||||
return inst.invokeMethodAsync("GetResult", result.text);
|
||||
}).catch((err) => {
|
||||
if (err && !(err instanceof ZXing.NotFoundException)) {
|
||||
console.log(err)
|
||||
inst.invokeMethodAsync("GetError", err + '');
|
||||
}
|
||||
})
|
||||
} else {
|
||||
codeReader.decodeFromVideoDevice(selectedDeviceId, 'video', (result, err) => {
|
||||
if (result) {
|
||||
if (debug) console.log(result)
|
||||
vibrate();
|
||||
if (debug) console.log('None-stop');
|
||||
inst.invokeMethodAsync("GetResult", result.text);
|
||||
}
|
||||
if (err && !(err instanceof ZXing.NotFoundException)) {
|
||||
console.log(err)
|
||||
inst.invokeMethodAsync("GetError", err + '');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var x = `decodeContinuously`;
|
||||
if (opt.decodeonce) x = `decodeOnce`;
|
||||
if (debug) console.log(`Started ` + x + ` decode from camera with id ${selectedDeviceId}`)
|
||||
if (debug) console.log(id, 'start');
|
||||
}
|
||||
}
|
||||
|
||||
export function stop(elementid) {
|
||||
if (undefined !== codeReader && null !== codeReader && id == elementid) {
|
||||
codeReader.reset();
|
||||
if (debug) console.log(id, 'stop');
|
||||
}
|
||||
}
|
||||
|
||||
export function QRCodeSvg(instance, input, element, tobase64, size = 300) {
|
||||
const codeWriter = new ZXing.BrowserQRCodeSvgWriter()
|
||||
|
||||
if (debug) console.log('ZXing code writer initialized')
|
||||
|
||||
if (tobase64) {
|
||||
const elementTemp = document.createElement('elementTemp');
|
||||
codeWriter.writeToDom(elementTemp, input, size, size)
|
||||
let svgElement = elementTemp.firstChild
|
||||
const svgData = (new XMLSerializer()).serializeToString(svgElement)
|
||||
//const blob = new Blob([svgData])
|
||||
instance.invokeMethodAsync("GetQRCode", svgData);
|
||||
} else {
|
||||
codeWriter.writeToDom(element.querySelector("[data-action=result]"), input, size, size)
|
||||
}
|
||||
}
|
||||
|
||||
export function DecodeFormImage(instance, element, options, data) {
|
||||
var codeReaderImage = null;
|
||||
const hints = genHints(options);
|
||||
if (options.pdf417) {
|
||||
codeReaderImage = new ZXing.BrowserPDF417Reader(hints);
|
||||
if (debug) console.log('ZXing code PDF417 reader initialized')
|
||||
} else if (options.decodeAllFormats) {
|
||||
const formats = options.formats;
|
||||
hints.set(ZXing.DecodeHintType.POSSIBLE_FORMATS, formats);
|
||||
codeReaderImage = new ZXing.BrowserMultiFormatReader(hints)
|
||||
if (debug) console.log('ZXing code reader initialized with all formats')
|
||||
} else {
|
||||
codeReaderImage = new ZXing.BrowserMultiFormatReader(hints)
|
||||
if (debug) console.log('ZXing code reader initialized')
|
||||
}
|
||||
if (debug) console.log('ZXing code reader initialized')
|
||||
|
||||
if (data != null) {
|
||||
codeReaderImage.decodeFromImageUrl(data).then(result => {
|
||||
if (result) {
|
||||
vibrate();
|
||||
if (debug) console.log(result.text);
|
||||
instance.invokeMethodAsync('GetResult', result.text)
|
||||
}
|
||||
}).catch((err) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
instance.invokeMethodAsync('GetError', err.message)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
else {
|
||||
const resetFile = () => {
|
||||
let file = element.querySelector('[type="file"]')
|
||||
if (file) {
|
||||
file.removeEventListener('change', scanImageHandler)
|
||||
file.remove()
|
||||
}
|
||||
file = document.createElement('input')
|
||||
file.setAttribute('type', 'file')
|
||||
file.setAttribute('hidden', 'true')
|
||||
file.setAttribute('accept', 'image/*')
|
||||
//file.setAttribute('capture', 'true')
|
||||
element.append(file)
|
||||
file.addEventListener('change', scanImageHandler)
|
||||
codeReaderImage.file = file
|
||||
return file
|
||||
}
|
||||
|
||||
const scanImageHandler = () => {
|
||||
const files = codeReaderImage.file.files
|
||||
if (files.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const reader = new FileReader()
|
||||
reader.onloadend = e => {
|
||||
|
||||
codeReaderImage.decodeFromImageUrl(e.target.result).then(result => {
|
||||
if (result) {
|
||||
vibrate();
|
||||
if (debug) console.log(result.text);
|
||||
instance.invokeMethodAsync('GetResult', result.text)
|
||||
} else {
|
||||
instance.invokeMethodAsync('GetError', "no valid barcode detected")
|
||||
}
|
||||
}).catch((err) => {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
instance.invokeMethodAsync('GetError', err.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
reader.readAsDataURL(files[0])
|
||||
}
|
||||
|
||||
let file = resetFile()
|
||||
file.click()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function destroy(elementid) {
|
||||
if (undefined !== codeReader && null !== codeReader && id == elementid) {
|
||||
codeReader.reset();
|
||||
codeReader = null;
|
||||
//id = null;
|
||||
id = null;
|
||||
opt = null;
|
||||
inst = null;
|
||||
selectedDeviceId = null;
|
||||
deviceID = null;
|
||||
element = null;
|
||||
if (debug) console.log(id, 'destroy');
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,189 @@
|
||||
// **********************************
|
||||
// Densen Informatica 中讯科技
|
||||
// 作者:Alex Chow
|
||||
// e-mail:zhouchuanglin@gmail.com
|
||||
// **********************************
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ZXingBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// ZXing 选项类
|
||||
/// </summary>
|
||||
/// <remarks>https://zxing.github.io/zxing/apidocs/com/google/zxing/DecodeHintType.htm</remarks>
|
||||
public class ZXingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 只解码 Pdf417 格式 / decode only Pdf417 format
|
||||
/// </summary>
|
||||
public bool Pdf417 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 单次|连续解码,默认单次 / Decode Once or Decode Continuously, default is Once
|
||||
/// </summary>
|
||||
public bool Decodeonce { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Time Between Decoding Attempts
|
||||
/// </summary>
|
||||
public int TimeBetweenDecodingAttempts { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 解码所有编码形式,性能较差, 开启后可用 options.formats 指定编码形式.默认为 false | Decodde All Formats, performance is poor, you can set options.formats to customize specify the encoding formats. The default is false
|
||||
/// </summary>
|
||||
public bool DecodeAllFormats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 已知图像是几种可能的格式之一。
|
||||
/// </summary>
|
||||
public List<BarcodeFormat> formats { get; set; } = new List<BarcodeFormat>() {
|
||||
BarcodeFormat.AZTEC ,
|
||||
BarcodeFormat.CODABAR,
|
||||
BarcodeFormat.CODE_39,
|
||||
BarcodeFormat.CODE_93,
|
||||
BarcodeFormat.CODE_128,
|
||||
BarcodeFormat.DATA_MATRIX,
|
||||
BarcodeFormat.EAN_8,
|
||||
BarcodeFormat.EAN_13,
|
||||
BarcodeFormat.ITF,
|
||||
BarcodeFormat.MAXICODE,
|
||||
BarcodeFormat.PDF_417,
|
||||
BarcodeFormat.QR_CODE,
|
||||
BarcodeFormat.RSS_14,
|
||||
BarcodeFormat.RSS_EXPANDED,
|
||||
BarcodeFormat.UPC_A,
|
||||
BarcodeFormat.UPC_E,
|
||||
BarcodeFormat.UPC_EAN_EXTENSION,
|
||||
};
|
||||
|
||||
public bool Debug { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 如果为 true,尝试解码为倒置图像。所有配置的解码器都被简单地用倒置图像第二次调用
|
||||
///// </summary>
|
||||
//[JsonPropertyName("ALSO_INVERTED")]
|
||||
//public bool ALSO_INVERTED { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// EAN 或 UPC 条形码允许的扩展长度, 默认为 2.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ALLOWED_EAN_EXTENSIONS")]
|
||||
public int[]? ALLOWED_EAN_EXTENSIONS { get; set; } //= new int[] { 2 };
|
||||
|
||||
/// <summary>
|
||||
/// 允许的编码数据长度——拒绝任何其他长度
|
||||
/// </summary>
|
||||
[JsonPropertyName("ALLOWED_LENGTHS")]
|
||||
public int[]? ALLOWED_LENGTHS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 假设 Code 39 代码使用校验位。
|
||||
/// </summary>
|
||||
[JsonPropertyName("ASSUME_CODE_39_CHECK_DIGIT")]
|
||||
public bool? ASSUME_CODE_39_CHECK_DIGIT { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 假设条形码正在作为 GS1 条形码进行处理,并根据需要修改行为
|
||||
/// </summary>
|
||||
[JsonPropertyName("ASSUME_GS1")]
|
||||
public bool? ASSUME_GS1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指定解码时使用的字符编码(如果适用)
|
||||
/// </summary>
|
||||
[JsonPropertyName("CHARACTER_SET")]
|
||||
public string? CHARACTER_SET { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// ResultPoint 当发现可能的情况时,需要通过回调通知调用者, 映射到一个ResultPointCallback
|
||||
///// </summary>
|
||||
//public object NEED_RESULT_POINT_CALLBACK { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 未指定的、特定于应用程序的提示。
|
||||
/// </summary>
|
||||
[JsonPropertyName("OTHER")]
|
||||
public object? OTHER { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图像是条形码的纯单色图像。
|
||||
/// </summary>
|
||||
[JsonPropertyName("PURE_BARCODE")]
|
||||
public bool? PURE_BARCODE { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 如果为 true,则返回 Codabar 条形码中的开始和结束数字,而不是剥离它们
|
||||
/// <remark>如果为 true,则返回 Codabar 条形码中的开始和结束数字,而不是剥离它们。它们是字母,而其余的是数字。默认情况下,它们会被剥离,但这会导致它们不会被剥离</remark>
|
||||
/// </summary>
|
||||
[JsonPropertyName("RETURN_CODABAR_START_END")]
|
||||
public bool? RETURN_CODABAR_START_END { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 花更多的时间尝试寻找条形码;优化准确性,而不是速度
|
||||
/// </summary>
|
||||
[JsonPropertyName("TRY_HARDER")]
|
||||
public bool? TRY_HARDER { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enumerates barcode formats known to this package. Please keep alphabetized.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public enum BarcodeFormat
|
||||
{
|
||||
|
||||
/** Aztec 2D barcode format. */
|
||||
AZTEC,
|
||||
|
||||
/** CODABAR 1D format. */
|
||||
CODABAR,
|
||||
|
||||
/** Code 39 1D format. */
|
||||
CODE_39,
|
||||
|
||||
/** Code 93 1D format. */
|
||||
CODE_93,
|
||||
|
||||
/** Code 128 1D format. */
|
||||
CODE_128,
|
||||
|
||||
/** Data Matrix 2D barcode format. */
|
||||
DATA_MATRIX,
|
||||
|
||||
/** EAN-8 1D format. */
|
||||
EAN_8,
|
||||
|
||||
/** EAN-13 1D format. */
|
||||
EAN_13,
|
||||
|
||||
/** ITF (Interleaved Two of Five) 1D format. */
|
||||
ITF,
|
||||
|
||||
/** MaxiCode 2D barcode format. */
|
||||
MAXICODE,
|
||||
|
||||
/** PDF417 format. */
|
||||
PDF_417,
|
||||
|
||||
/** QR Code 2D barcode format. */
|
||||
QR_CODE,
|
||||
|
||||
/** RSS 14 */
|
||||
RSS_14,
|
||||
|
||||
/** RSS EXPANDED */
|
||||
RSS_EXPANDED,
|
||||
|
||||
/** UPC-A 1D format. */
|
||||
UPC_A,
|
||||
|
||||
/** UPC-E 1D format. */
|
||||
UPC_E,
|
||||
|
||||
/** UPC/EAN extension format. Not a stand-alone format. */
|
||||
UPC_EAN_EXTENSION
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user