In der .NET MAUI-Entwicklung werden sowohl BlazorWebView als auch WebView zum Anzeigen von Webinhalten verwendet, sie dienen jedoch unterschiedlichen Zwecken und sind für unterschiedliche Szenarien konzipiert. BlazorWebView wurde speziell zum Hosten von Blazor-Komponenten in einer .NET MAUI-Anwendung entwickelt, sodass Sie Blazor-Komponenten wiederverwenden und Code zwischen Web- und nativen Anwendungen teilen können. WebView ist ein allgemeines Steuerelement zum Anzeigen von Webinhalten, einschließlich Webseiten, HTML-Strings und lokalen HTML-Dateien. In diesem Artikel erfahren Sie, wie Sie eine .NET MAUI Blazor-Dokumentenscanneranwendung mithilfe des WebView-Steuerelements in eine .NET MAUI-Anwendung umwandeln, die Dokumentenscanlogik in JavaScript und HTML implementieren und die Zusammenarbeit zwischen C# und JavaScript zum Scannen von Dokumenten und ermöglichen Bilder speichern.
Öffnen Sie die Datei MainPage.xaml und ersetzen Sie den vorhandenen Code durch den folgenden XAML, um ein WebView-Steuerelement hinzuzufügen:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiWebView.MainPage"> <ScrollView> <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"> <WebView x:Name="WebView" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Navigating="OnWebViewNavigated"/> </StackLayout> </ScrollView> </ContentPage>
Öffnen Sie die Datei MainPage.xaml.cs und fügen Sie den folgenden Code hinzu, um die Quelle der WebView festzulegen und das Navigating-Ereignis zu verarbeiten:
namespace MauiWebView { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); LoadHtmlFile(); } private void LoadHtmlFile() { WebView.Source = "index.html"; } private async void OnWebViewNavigated(object sender, WebNavigatingEventArgs e) { if (e.Url.StartsWith("invoke://callcsharpfunction")) { // TODO: Implement interop between C# and JavaScript } } } }
Erklärung:
In einem .NET MAUI-Projekt können Sie statische HTML-, JavaScript- und CSS-Dateien, die sich im Ordner „Resources/Raw“ befinden, in die WebView laden. Stellen Sie sicher, dass die MauiAsset-Build-Aktion in der .csproj-Datei enthalten ist:
<ItemGroup> <MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" /> </ItemGroup>
Wir erstellen ein ähnliches UI-Layout wie die vorherige Blazor-Dokumentenscanneranwendung in der Datei index.html.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dynamsoft RESTful API Example</title> <link rel="stylesheet" href="main.css"> </head> <body> <div id="loading-indicator" class="loading-indicator"> <div class="spinner"></div> </div> <h2>Document Scanner</h2> <div class="row"> <div> <label> Get a License key from <a href="https://www.dynamsoft.com/customer/license/trialLicense?product=dwt" target="_blank">here</a>. </label> <input type="text" placeholder="licenseKey" id="inputText" class="license-input"> <br /> </div> </div> <div class="container"> <div class="image-tool"> <h3>Acquire Image</h3> <button class="btn btn-primary" id="query-devices-button">Get Devices</button> <div> <label for="sourceSelect">Source: </label> <select id="sources" class="form-control"></select> </div> <div> <label for="pixelTypeSelect">Pixel Type: </label> <select id="pixelTypeSelectId" class="form-control"> <option>B & W</option> <option>Gray</option> <option>Color</option> </select> </div> <div> <label for="resolutionSelect">Resolution: </label> <select id="resolutionSelectId" class="form-control"> <option>100</option> <option>150</option> <option>200</option> <option>300</option> </select> </div> <div> <input class="form-check-input" type="checkbox" id="showUICheckId"> <label class="form-check-label" for="showUICheck">Show UI</label> </div> <div> <input class="form-check-input" type="checkbox" id="adfCheckId"> <label class="form-check-label" for="adfCheck">ADF</label> </div> <div> <input class="form-check-input" type="checkbox" id="duplexCheckId"> <label class="form-check-label" for="duplexCheck">Duplex</label> </div> <button class="btn btn-primary mt-3" id="scan-button">Scan Now</button> <button class="btn btn-primary mt-2" id="save-button">Save</button> <h3>Image Tools</h3> <div class="image-tools"> <button id="delete-button" style="border:none; background:none; padding:0;"> <img src="images/delete.png" alt="Click Me" style="width: 64px; height: 64px;" /> </button> <button id="rotate-left-button" style="border:none; background:none; padding:0;"> <img src="images/rotate_left.png" alt="Click Me" style="width: 64px; height: 64px;" /> </button> <button id="rotate-right-button" style="border:none; background:none; padding:0;"> <img src="images/rotate_right.png" alt="Click Me" style="width: 64px; height: 64px;" /> </button> </div> </div> <div class="image-display"> <div class="full-img"> <img id="document-image" src="images/default.png" class="scanned-image"> </div> <div class="row"> <div class="thumb-bar" id="thumb-bar"> <div class="thumb-box" id="thumb-box"> </div> </div> </div> </div> </div> <script src="main.js"></script> </body> </html>
Wenn die Umgebung bereit ist, besteht der nächste Schritt darin, die relevanten Funktionen in JavaScript zu implementieren.
Listen Sie die verfügbaren Scanner auf.
const ScannerType = { // TWAIN scanner type, represented by the value 0x10 TWAINSCANNER: 0x10, // WIA scanner type, represented by the value 0x20 WIASCANNER: 0x20, // 64-bit TWAIN scanner type, represented by the value 0x40 TWAINX64SCANNER: 0x40, // ICA scanner type, represented by the value 0x80 ICASCANNER: 0x80, // SANE scanner type, represented by the value 0x100 SANESCANNER: 0x100, // eSCL scanner type, represented by the value 0x200 ESCLSCANNER: 0x200, // WiFi Direct scanner type, represented by the value 0x400 WIFIDIRECTSCANNER: 0x400, // WIA-TWAIN scanner type, represented by the value 0x800 WIATWAINSCANNER: 0x800 }; let queryDevicesButton = document.getElementById("query-devices-button"); queryDevicesButton.onclick = async () => { let scannerType = ScannerType.TWAINSCANNER | ScannerType.TWAINX64SCANNER; let devices = await getDevices(host, scannerType); let select = document.getElementById("sources"); select.innerHTML = ''; for (let i = 0; i < devices.length; i++) { let device = devices[i]; let option = document.createElement("option"); option.text = device['name']; option.value = JSON.stringify(device); select.add(option); }; } async function getDevices(host, scannerType) { devices = []; let url = host + '/DWTAPI/Scanners' if (scannerType != null) { url += '?type=' + scannerType; } try { let response = await fetch(url); if (response.ok) { let devices = await response.json(); return devices; } } catch (error) { console.log(error); } return []; }
Erklärung
Scannen Sie Dokumente vom ausgewählten Scanner, indem Sie den Pixeltyp, die Auflösung und andere Einstellungen angeben.
let scanButton = document.getElementById("scan-button"); scanButton.onclick = async () => { let select = document.getElementById("sources"); let device = select.value; if (device == null || device.length == 0) { alert('Please select a scanner.'); return; } let inputText = document.getElementById("inputText").value; let license = inputText.trim(); if (license == null || license.length == 0) { alert('Please input a valid license key.'); } let parameters = { license: license, device: JSON.parse(device)['device'], }; let showUICheck = document.getElementById("showUICheckId"); let pixelTypeSelect = document.getElementById("pixelTypeSelectId"); let resolutionSelect = document.getElementById("resolutionSelectId"); let adfCheck = document.getElementById("adfCheckId"); let duplexCheck = document.getElementById("duplexCheckId"); parameters.config = { IfShowUI: showUICheck.checked, PixelType: pixelTypeSelect.selectedIndex, Resolution: parseInt(resolutionSelect.value), IfFeederEnabled: adfCheck.checked, IfDuplexEnabled: duplexCheck.checked, }; let jobId = await scanDocument(host, parameters); let images = await getImages(host, jobId); for (let i = 0; i < images.length; i++) { let url = images[i]; let img = document.getElementById('document-image'); img.src = url; data.unshift(url); let option = document.createElement("option"); option.selected = true; option.text = url; option.value = url; let thumbnails = document.getElementById("thumb-box"); let newImage = document.createElement('img'); newImage.setAttribute('src', url); if (thumbnails != null) { thumbnails.insertBefore(newImage, thumbnails.firstChild); newImage.addEventListener('click', e => { if (e != null && e.target != null) { let target = e.target; img.src = target.src; selectedThumbnail = target; } }); } selectedThumbnail = newImage; } } async function scanDocument(host, parameters, timeout = 30) { let url = host + '/DWTAPI/ScanJobs?timeout=' + timeout; try { let response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(parameters) }); if (response.ok) { let jobId = await response.text(); return jobId; } else { return ''; } } catch (error) { alert(error); return ''; } } async function getImages(host, jobId) { let images = []; let url = host + '/DWTAPI/ScanJobs/' + jobId + '/NextDocument'; while (true) { try { let response = await fetch(url); if (response.status == 200) { const arrayBuffer = await response.arrayBuffer(); const blob = new Blob([arrayBuffer], { type: response.type }); const imageUrl = URL.createObjectURL(blob); images.push(imageUrl); } else { break; } } catch (error) { console.error('No more images.'); break; } } return images; }
Erklärung
Drehen Sie das gescannte Bild um -90 oder 90 Grad.
let rotateLeftButton = document.getElementById("rotate-left-button"); rotateLeftButton.onclick = () => { let img = document.getElementById('document-image'); img.src = rotateImage('document-image', -90); selectedThumbnail.src = img.src; } let rotateRightButton = document.getElementById("rotate-right-button"); rotateRightButton.onclick = () => { let img = document.getElementById('document-image'); img.src = rotateImage('document-image', 90); selectedThumbnail.src = img.src; } function rotateImage (imageId, angle) { const image = document.getElementById(imageId); const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); const imageWidth = image.naturalWidth; const imageHeight = image.naturalHeight; // Calculate the new rotation let rotation = 0; rotation = (rotation + angle) % 360; // Adjust canvas size for rotation if (rotation === 90 || rotation === -270 || rotation === 270) { canvas.width = imageHeight; canvas.height = imageWidth; } else if (rotation === 180 || rotation === -180) { canvas.width = imageWidth; canvas.height = imageHeight; } else if (rotation === 270 || rotation === -90) { canvas.width = imageHeight; canvas.height = imageWidth; } else { canvas.width = imageWidth; canvas.height = imageHeight; } // Clear the canvas context.clearRect(0, 0, canvas.width, canvas.height); // Draw the rotated image on the canvas context.save(); if (rotation === 90 || rotation === -270) { context.translate(canvas.width, 0); context.rotate(90 * Math.PI / 180); } else if (rotation === 180 || rotation === -180) { context.translate(canvas.width, canvas.height); context.rotate(180 * Math.PI / 180); } else if (rotation === 270 || rotation === -90) { context.translate(0, canvas.height); context.rotate(270 * Math.PI / 180); } context.drawImage(image, 0, 0); context.restore(); return canvas.toDataURL(); }
Löschen Sie alle gescannten Bilder, einschließlich des Hauptbilds und der Miniaturansichten, und setzen Sie das Datenarray zurück.
let deleteButton = document.getElementById("delete-button"); deleteButton.onclick = async () => { let img = document.getElementById('document-image'); img.src = 'images/default.png'; data = []; let thumbnails = document.getElementById("thumb-box"); thumbnails.innerHTML = ''; }
Das direkte Speichern von Bildern in JavaScript ist aus Sicherheitsgründen eingeschränkt. Daher müssen wir zwischen C# und JavaScript zusammenarbeiten, um diese Aufgabe zu erfüllen.
Erstellen Sie eine JavaScript-Funktion, um das gescannte Bild in eine Base64-Zeichenfolge umzuwandeln.
function getBase64Image() { var img = document.getElementById('document-image'); var canvas = document.createElement('canvas'); canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; var ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); var dataURL = canvas.toDataURL('image/png'); var base64 = dataURL.split(',')[1]; return base64; }
Wenn Sie auf die Schaltfläche „Speichern“ klicken, legen Sie window.location.href fest, um den OnWebViewNavigated-Ereignishandler des WebView-Steuerelements auszulösen.
let saveButton = document.getElementById("save-button"); saveButton.onclick = async () => { window.location.href = 'invoke://CallCSharpFunction'; }
Rufen Sie im OnWebViewNavigated-Ereignishandler EvaluateJavaScriptAsync auf, um die Base64-Bilddaten aus JavaScript abzurufen und in einer Datei zu speichern.
private async void OnWebViewNavigated(object sender, WebNavigatingEventArgs e) { if (e.Url.StartsWith("invoke://callcsharpfunction")) { var base64String = await WebView.EvaluateJavaScriptAsync("getBase64Image()"); CallCSharpFunction(base64String); } } private void CallCSharpFunction(string base64String) { if (!string.IsNullOrEmpty(base64String)) { try { byte[] imageBytes = Convert.FromBase64String(base64String); var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), GenerateFilename()); File.WriteAllBytes(filePath, imageBytes); DisplayAlert("Success", "Image saved to: " + filePath, "OK"); } catch (Exception ex) { DisplayAlert("Error", ex.Message, "OK"); } } else { DisplayAlert("Failure", "No image data found", "OK"); } } private string GenerateFilename() { DateTime now = DateTime.Now; string timestamp = now.ToString("yyyyMMdd_HHmmss"); return $"image_{timestamp}.png"; }
Note: Do not pass the base64 string directly to the C# function via window.location.href, as the string may be too long and cause an error. Instead, return the base64 string when calling EvaluateJavaScriptAsync from the C# function.
Press F5 in Visual Studio or Visual Studio Code to run the .NET document scanner application on Windows or macOS.
https://github.com/yushulx/dotnet-twain-wia-sane-scanner/tree/main/examples/MauiWebView
Das obige ist der detaillierte Inhalt vonWechsel von .NET MAUI Blazor zu WebView Control für das Scannen von Dokumenten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!