Heim > Web-Frontend > js-Tutorial > Wechsel von .NET MAUI Blazor zu WebView Control für das Scannen von Dokumenten

Wechsel von .NET MAUI Blazor zu WebView Control für das Scannen von Dokumenten

PHPz
Freigeben: 2024-07-29 18:37:22
Original
890 Leute haben es durchsucht

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.

Voraussetzungen

  1. Dynamsoft-Dienst installieren: Dieser Dienst ist für die Kommunikation mit TWAIN-, SANE-, ICA-, ESCL- und WIA-Scannern unter Windows und macOS erforderlich.
    • Windows: Dynamsoft-Service-Setup.msi
    • macOS: Dynamsoft-Service-Setup.pkg
  2. Kostenlose Testlizenz anfordern: Erhalten Sie eine 30-tägige kostenlose Testlizenz für Dynamic Web TWAIN, um loszulegen.

Schritt 1: Erstellen Sie ein neues .NET MAUI-Projekt mit WebView Control

  1. Erstellen Sie in Visual Studio oder Visual Studio Code ein neues .NET MAUI-Projekt.
  2. Ö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>
    
    Nach dem Login kopieren
  3. Ö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
                }
            }
        }
    
    }
    
    
    Nach dem Login kopieren

    Erklärung:

    • Die LoadHtmlFile-Methode legt die Source-Eigenschaft des WebView-Steuerelements fest, um die Datei index.html zu laden.
    • Die OnWebViewNavigated-Methode wird ausgelöst, wenn WebView zu einer neuen URL navigiert. Es prüft, ob die URL mit invoke://callcsharpfunction beginnt und ermöglicht in diesem Fall die C#- und JavaScript-Interop.

Schritt 2: Laden Sie statische HTML-, JavaScript- und CSS-Dateien in das WebView-Steuerelement

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>
Nach dem Login kopieren

Switching from .NET MAUI Blazor to WebView Control for Document Scanning

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 &amp; 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>
Nach dem Login kopieren

Schritt 3: Implementieren Sie das Scannen von Dokumenten in JavaScript

Wenn die Umgebung bereit ist, besteht der nächste Schritt darin, die relevanten Funktionen in JavaScript zu implementieren.

Holen Sie sich Geräte

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 [];
}
Nach dem Login kopieren

Erklärung

  • Die getDevices-Funktion sendet eine GET-Anfrage an den RESTful-API-Endpunkt /DWTAPI/Scanners, um die verfügbaren Scanner abzurufen. Der Scannertyp wird durch den Parameter scannerType angegeben.

Bild erwerben

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;
}
Nach dem Login kopieren

Erklärung

  • Die scanDocument-Funktion sendet eine POST-Anfrage an den RESTful-API-Endpunkt /DWTAPI/ScanJobs, um einen Scanauftrag zu starten. Zu den Parametern gehören der Lizenzschlüssel, der Gerätename und die Scaneinstellungen.
  • Die getImages-Funktion sendet eine GET-Anfrage an den RESTful-API-Endpunkt /DWTAPI/ScanJobs/{jobId}/NextDocument, um gescannte Bilder abzurufen. Die Bilder werden in einem Blob-Objekt gespeichert und im Bildanzeigebereich angezeigt.

Bild drehen

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();
}
Nach dem Login kopieren

Bild löschen

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 = '';
}
Nach dem Login kopieren

Schritt 4: Interop zwischen C# und JavaScript zum Speichern von Bildern

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.

  1. 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;
    }
    
    Nach dem Login kopieren
  2. 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';    
    }
    
    Nach dem Login kopieren
  3. 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";
    }
    
    Nach dem Login kopieren

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.

Step 5: Run the .NET MAUI Document Scanner Application

Press F5 in Visual Studio or Visual Studio Code to run the .NET document scanner application on Windows or macOS.

Switching from .NET MAUI Blazor to WebView Control for Document Scanning

Source Code

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!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage