Dans le développement .NET MAUI, BlazorWebView et WebView sont utilisés pour afficher du contenu Web, mais ils servent à des fins différentes et sont conçus pour différents scénarios. BlazorWebView est spécialement conçu pour héberger les composants Blazor dans une application .NET MAUI, vous permettant de réutiliser les composants Blazor et de partager du code entre les applications Web et natives. WebView est un contrôle à usage général permettant d'afficher du contenu Web, notamment des pages Web, des chaînes HTML et des fichiers HTML locaux. Dans cet article, nous explorerons comment faire la transition d'une application de numérisation de documents .NET MAUI Blazor vers une application .NET MAUI à l'aide du contrôle WebView, en implémentant la logique d'analyse de documents en JavaScript et HTML et en permettant l'interopérabilité entre C# et JavaScript pour numériser des documents et enregistrer des images.
Ouvrez le fichier MainPage.xaml et remplacez le code existant par le XAML suivant pour ajouter un contrôle WebView :
<?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>
Ouvrez le fichier MainPage.xaml.cs et ajoutez le code suivant pour définir la source de WebView et gérer l'événement Navigating :
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 } } } }
Explication :
Dans un projet .NET MAUI, vous pouvez charger des fichiers statiques HTML, JavaScript et CSS situés dans le dossier Resources/Raw dans WebView. Assurez-vous que l'action de construction MauiAsset est incluse dans le fichier .csproj :
<ItemGroup> <MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" /> </ItemGroup>
Nous créons une présentation d'interface utilisateur similaire à celle de la précédente application de numérisation de documents Blazor dans le fichier 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>
Une fois l'environnement prêt, l'étape suivante consiste à implémenter les fonctions pertinentes en JavaScript.
Énumérez les scanners disponibles.
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 []; }
Explication
Numériser des documents à partir du scanner sélectionné en spécifiant le type de pixel, la résolution et d'autres paramètres.
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; }
Explication
Faites pivoter l'image numérisée de -90 ou 90 degrés.
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(); }
Supprimez toutes les images numérisées, y compris l'image principale et les vignettes, et réinitialisez le tableau de données.
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 = ''; }
L'enregistrement des images directement en JavaScript est limité en raison de problèmes de sécurité. Par conséquent, nous devons interopérer entre C# et JavaScript pour accomplir cette tâche.
Créez une fonction JavaScript pour convertir l'image numérisée en chaîne base64.
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; }
Lorsque vous cliquez sur le bouton Enregistrer, définissez window.location.href pour déclencher le gestionnaire d'événements OnWebViewNavigated du contrôle WebView.
let saveButton = document.getElementById("save-button"); saveButton.onclick = async () => { window.location.href = 'invoke://CallCSharpFunction'; }
Dans le gestionnaire d'événements OnWebViewNavigated, appelez EvaluateJavaScriptAsync pour récupérer les données d'image base64 à partir de JavaScript et enregistrez-les dans un fichier.
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
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!