在實際環境中測試
在生產環境中測試無浮水印。
在任何需要的地方都能運作。
本文探討快速響應碼掃描器的整合(QR碼掃描器)在使用IronQR的Blazor應用程式中,這是一個.NET程式庫。 QR 碼是二維條碼,能夠儲存比一般一維條碼更多的數據。
Blazor 是一個由微軟推出的框架,允許開發者製作單頁應用程式(使用 Blazor WebAssembly 應用程式)或者使用 C# 來建立互動式網頁介面,(Blazor Server,本指南將著重於此).
將IronQR與Blazor Server整合以進行QR碼掃描是一種戰略性的組合,能夠發揮兩項技術的優勢。 通過將 IronQR 與 Blazor 應用程式整合,您可以高效處理 QR 碼的生成和掃描。 在庫存管理、票務系統和無接觸信息共享等各種商業環境中,QR 碼閱讀器的此功能需求日益增長。
Blazor 伺服器是 ASP.NET Core 平台的一部分的網頁應用程式框架。 它使開發人員能夠使用C#而不是JavaScript來構建互動式網頁用戶介面。 此伺服器端模型通過處理用戶在 SignalR 連接上的互動來運行,這是一種即時網頁功能。 這有助於開發人員創建有效且互動的網絡應用程式。
IronQR是一個.NET庫,以其讀取、解釋和生成 QR 碼具有高準確性。 它提供了一系列功能,包括處理不同類型的QR碼內容的能力。 IronQR的優勢在於其簡單性及易於整合到.NET應用程式中,使其成為開發人員在尋求融入和創建QR碼功能時的首選。
在 Visual Studio Code 中創建 Blazor 伺服器應用程式
使用 NuGet 套件管理器安裝 QR Code 類別庫
在 index.razor 中使用 HTML 和 CSS 創建用戶介面。
編寫上傳文件處理邏輯
使用QR庫編寫QR掃描邏輯。
啟動 Visual Studio,然後選擇「建立新專案」。在專案範本選擇畫面中,找到並選擇「Blazor Server App」範本。 點擊下一步。
選擇模板後,輸入專案名稱和位置。(保持其他所有設為預設值)然後點擊下一步按鈕。
現在選擇所需的 .NET Framework 並點擊創建按鈕。 它將創建一個Blazor Server應用程式。
從選單列中點擊工具。 從下拉選單中選擇 NuGet 套件管理員。 從內容選單中,選擇「管理解決方案的 NuGet 套件」。 這將開啟 NuGet 套件管理器標籤。
在 NuGet 套件管理器中,在「瀏覽」選項卡中搜尋「IronQR」。 然後在列表中找到「IronQR」套件。點擊「安裝」按鈕。
現在您已安裝好所有內容,我們可以探討項目結構以及如何將所有東西整合到您的項目中。
QR碼掃描器的使用者介面主要是在 Index.razor 文件內建構的。這個文件是Blazor Server專案的一部分,利用HTML和Razor語法相結合來創建一個動態和互動式的網頁。 結構包括:
@page "/"
@using System.IO
@using Microsoft.AspNetCore.Components.Forms
@using IronQr
@using IronSoftware.Drawing
@inject IJSRuntime JSRuntime
<PageTitle>QR Code Scanner</PageTitle>
<div>
<h1>QR Code Scanner</h1>
<InputFile OnChange="HandleSelectedFile" accept="image/*" class="file-input" />
@if (!string.IsNullOrEmpty(qrImageSrc))
{
<img src="@qrImageSrcForDisplay" alt="QR Code Image" class="qr-image" />
}
<button @onclick="ScanQRCode" disabled="@(!fileSelected)" class="button scan-button">Scan QR Code</button>
@if (!string.IsNullOrEmpty(scannedText))
{
<div class="result-section">
<button @onclick="CopyToClipboard" class="button copy-button">Copy</button>
</div>
}
</div>
@page "/"
@using System.IO
@using Microsoft.AspNetCore.Components.Forms
@using IronQr
@using IronSoftware.Drawing
@inject IJSRuntime JSRuntime
<PageTitle>QR Code Scanner</PageTitle>
<div>
<h1>QR Code Scanner</h1>
<InputFile OnChange="HandleSelectedFile" accept="image/*" class="file-input" />
@if (!string.IsNullOrEmpty(qrImageSrc))
{
<img src="@qrImageSrcForDisplay" alt="QR Code Image" class="qr-image" />
}
<button @onclick="ScanQRCode" disabled="@(!fileSelected)" class="button scan-button">Scan QR Code</button>
@if (!string.IsNullOrEmpty(scannedText))
{
<div class="result-section">
<button @onclick="CopyToClipboard" class="button copy-button">Copy</button>
</div>
}
</div>
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: @page "/" using System.IO using Microsoft.AspNetCore.Components.Forms using IronQr using IronSoftware.Drawing inject IJSRuntime JSRuntime <PageTitle> QR Code Scanner</PageTitle> <div> <h1> QR Code Scanner</h1> <InputFile OnChange="HandleSelectedFile" accept="image/*" class="file-input" /> if(!string.IsNullOrEmpty(qrImageSrc))
"image/*" Class="file-input" /> [if](Not String.IsNullOrEmpty(qrImageSrc))
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: Friend @page "/" using System.IO using Microsoft.AspNetCore.Components.Forms using IronQr using IronSoftware.Drawing inject IJSRuntime JSRuntime <PageTitle> QR Code Scanner</PageTitle> <div> <h1> QR Code Scanner</h1> <InputFile OnChange="HandleSelectedFile" accept="image/*" Class
"HandleSelectedFile" accept="image/*" Class
Friend page "/" [using] System.IO [using] Microsoft.AspNetCore.Components.Forms [using] IronQr [using] IronSoftware.Drawing inject IJSRuntime JSRuntime (Of PageTitle) QR Code Scanner</PageTitle> (Of div) (Of h1) QR Code Scanner</h1> <InputFile OnChange="HandleSelectedFile" accept
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <img src="@qrImageSrcForDisplay" alt="QR Code Image" class="qr-image" />
"QR Code Image" class="qr-image" />
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <img src="@qrImageSrcForDisplay" alt="QR Code Image" class
"@qrImageSrcForDisplay" alt="QR Code Image" class
<img src="@qrImageSrcForDisplay" alt
End Class
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <button onclick="ScanQRCode" disabled="@(!fileSelected)" class="button scan-button"> Scan QR Code</button> if(!string.IsNullOrEmpty(scannedText))
"@(!fileSelected)" class="button scan-button"> Scan QR Code</button> [if](Not String.IsNullOrEmpty(scannedText))
If True Then
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <button onclick="ScanQRCode" disabled="@(!fileSelected)" class
"ScanQRCode" disabled="@(!fileSelected)" class
<button onclick="ScanQRCode" disabled
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <div class="result-section"> <button onclick="CopyToClipboard" class="button copy-button"> Copy</button> </div>
"CopyToClipboard" class="button copy-button"> Copy</button> </div>
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <div class="result-section"> <button onclick="CopyToClipboard" class
"result-section"> <button onclick="CopyToClipboard" class
<div class="result-section"> <button onclick
End If
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'</div>
標題和標題: The <PageTitle>和<h1>
標籤定義了頁面的標題,
圖片上傳控件: An <InputFile>
component 用於上傳 QR 碼圖像。 此元件專門設計用於僅接受圖像文件,通過過濾不相關的文件類型來提升使用者體驗。
圖像顯示:圖像上傳後,將使用<img>
標籤。 這種視覺反饋對於用戶確認正確的文件已上傳是至關重要的。
掃描按鈕:標記為 @onclick="ScanQRCode
的按鈕觸發掃描過程。 其可用性取決於是否選擇了文件,從而增強了介面的直觀性。
結果顯示:掃描的 QR 碼文本顯示在文字輸入框中,便於查看。 另一個按鈕允許用戶將此文本複製到剪貼板。
QR Code Scanner 的視覺美學和佈局在 site.css
文件中定義。
.content {
padding: 20px;
margin: 10px auto; /* Centers the content */
max-width: 500px; /* Sets a max width for the content */
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
text-align: center;
}
.file-input, .result-input {
margin: 10px 0;
padding: 10px;
border-radius: 5px;
border: 1px solid #ddd;
width: 100%;
}
.button {
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
width: auto; /* Adjusts button width */
display: inline-block; /* Allows the width to adjust to content */
}
.button:hover {
background-color: #45a049;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.qr-image {
max-width: 300px;
max-height: 300px;
display: block;
margin: 10px auto;
border-radius: 10px;
}
.result-section {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.result-input {
width: 100%;
box-sizing: border-box;
}
.copy-button {
margin-top: 10px;
white-space: nowrap;
}
.content
:此類別樣式化主要內容區域,賦予其固定寬度、居中對齊和細微陰影以增強深度。
.file-input, .result-input
:這些類別為檔案輸入和結果顯示元素設置樣式,確保它們在視覺上一致並完全佔據容器的寬度。
.button
:按鈕採用獨特的綠色背景設計,圓角和懸停效果,以增強用戶互動性。
.qr-image
:QR 代碼圖像的樣式包括大小限制和自動邊距以居中,使圖像顯著而不至於過於突出。
.result-section
:這個類別確保結果部分內的元素居中對齊並適當地間隔。
HandleSelectedFile
方法是 QR 碼掃描過程中的關鍵部分,負責處理使用者的文件上傳並準備進行掃描。 當使用者通過`選擇文件時,此方法會被觸發
private async Task HandleSelectedFile(InputFileChangeEventArgs e)
{
selectedFile = e.File;
fileSelected = true;
var imagesDirectory = Path.Combine(Directory.GetCurrentDirectory(), "UploadedImages");
Directory.CreateDirectory(imagesDirectory); // Ensure the directory exists
// Use a GUID as the unique file name
var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(selectedFile.Name);
var fullPath = Path.Combine(imagesDirectory, uniqueFileName);
await using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await selectedFile.OpenReadStream().CopyToAsync(fileStream);
}
// Store the full path in qrImageSrc for scanning
qrImageSrc = fullPath;
// Optionally, create a base64 string for displaying the image (if needed)
byte [] imageBytes = await File.ReadAllBytesAsync(fullPath);
var base64String = Convert.ToBase64String(imageBytes);
qrImageSrcForDisplay = $"data:image/{Path.GetExtension(selectedFile.Name).TrimStart('.')};base64,{base64String}";
}
private async Task HandleSelectedFile(InputFileChangeEventArgs e)
{
selectedFile = e.File;
fileSelected = true;
var imagesDirectory = Path.Combine(Directory.GetCurrentDirectory(), "UploadedImages");
Directory.CreateDirectory(imagesDirectory); // Ensure the directory exists
// Use a GUID as the unique file name
var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(selectedFile.Name);
var fullPath = Path.Combine(imagesDirectory, uniqueFileName);
await using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await selectedFile.OpenReadStream().CopyToAsync(fileStream);
}
// Store the full path in qrImageSrc for scanning
qrImageSrc = fullPath;
// Optionally, create a base64 string for displaying the image (if needed)
byte [] imageBytes = await File.ReadAllBytesAsync(fullPath);
var base64String = Convert.ToBase64String(imageBytes);
qrImageSrcForDisplay = $"data:image/{Path.GetExtension(selectedFile.Name).TrimStart('.')};base64,{base64String}";
}
Private Async Function HandleSelectedFile(ByVal e As InputFileChangeEventArgs) As Task
selectedFile = e.File
fileSelected = True
Dim imagesDirectory = Path.Combine(Directory.GetCurrentDirectory(), "UploadedImages")
Directory.CreateDirectory(imagesDirectory) ' Ensure the directory exists
' Use a GUID as the unique file name
Dim uniqueFileName = Guid.NewGuid().ToString() & Path.GetExtension(selectedFile.Name)
Dim fullPath = Path.Combine(imagesDirectory, uniqueFileName)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
' await using(var fileStream = New FileStream(fullPath, FileMode.Create))
' {
' await selectedFile.OpenReadStream().CopyToAsync(fileStream);
' }
' Store the full path in qrImageSrc for scanning
qrImageSrc = fullPath
' Optionally, create a base64 string for displaying the image (if needed)
Dim imageBytes() As Byte = Await File.ReadAllBytesAsync(fullPath)
Dim base64String = Convert.ToBase64String(imageBytes)
qrImageSrcForDisplay = $"data:image/{Path.GetExtension(selectedFile.Name).TrimStart("."c)};base64,{base64String}"
End Function
以下是其功能的詳細說明:
文件選擇和驗證:當用戶上傳文件時,該方法使用 InputFileChangeEventArgs
捕獲文件的詳細信息。 接著將此檔案賦值給 selectedFile
變數,並將布林值 fileSelected
設為 true,表示輸入的數據/文件已準備好進行處理。
建立檔案路徑:該方法準備一個目錄來存儲上傳的圖片。 它使用 Path.Combine
建立到 'UploadedImages
' 目錄的路徑,並通過 Directory.CreateDirectory
確保其存在。 這一步對於系統化地整理上傳的檔案至關重要。
生成唯一檔名:為避免與現有檔案發生衝突,將使用 GUID 生成唯一檔名(全域唯一識別碼)附加上原始檔案的擴展名。 這確保每個上傳的檔案都是 uniquePathdentified
。
存檔:然後檔案會儲存到伺服器上。 該方法創建一個文件流,指向新生成的文件路徑,並使用 await selectedFile.OpenReadStream
將上傳文件的內容複製到此流中。().CopyToAsync(文件流)`. 此步驟完成上傳過程。
準備顯示圖像:檔案儲存後,必須將圖像顯示給用戶以進行確認。 該方法將檔案讀取為位元組陣列,並將其轉換為 base64 字串,適合直接嵌入到一個 <img>
tag的
src` 屬性。 此轉換允許顯示圖像而無需對伺服器發出單獨的圖像文件請求。
ScanQRCode
方法是 Blazor Server 應用程式中 QR 碼掃描功能的核心。 此方法將取得上傳的圖像,並使用IronQR來提取QR碼數據。
private async Task ScanQRCode()
{
// Check if there is a valid image to work with
if (string.IsNullOrEmpty(qrImageSrc)) return;
try
{
var inputBmp = AnyBitmap.FromFile(qrImageSrc);
QrImageInput imageInput = new QrImageInput(inputBmp);
QrReader reader = new QrReader();
IEnumerable<QrResult> results = reader.Read(imageInput);
// Check if there are any results and if the first result contains text
var firstResult = results.FirstOrDefault();
if (firstResult != null && !string.IsNullOrWhiteSpace(firstResult.Value.ToString()))
{
scannedText = firstResult.Value.ToString();
}
else
{
scannedText = "QR value not found!";
}
}
catch (Exception ex)
{
scannedText = "Error scanning QR code: " + ex.Message;
}
}
private async Task ScanQRCode()
{
// Check if there is a valid image to work with
if (string.IsNullOrEmpty(qrImageSrc)) return;
try
{
var inputBmp = AnyBitmap.FromFile(qrImageSrc);
QrImageInput imageInput = new QrImageInput(inputBmp);
QrReader reader = new QrReader();
IEnumerable<QrResult> results = reader.Read(imageInput);
// Check if there are any results and if the first result contains text
var firstResult = results.FirstOrDefault();
if (firstResult != null && !string.IsNullOrWhiteSpace(firstResult.Value.ToString()))
{
scannedText = firstResult.Value.ToString();
}
else
{
scannedText = "QR value not found!";
}
}
catch (Exception ex)
{
scannedText = "Error scanning QR code: " + ex.Message;
}
}
Private Async Function ScanQRCode() As Task
' Check if there is a valid image to work with
If String.IsNullOrEmpty(qrImageSrc) Then
Return
End If
Try
Dim inputBmp = AnyBitmap.FromFile(qrImageSrc)
Dim imageInput As New QrImageInput(inputBmp)
Dim reader As New QrReader()
Dim results As IEnumerable(Of QrResult) = reader.Read(imageInput)
' Check if there are any results and if the first result contains text
Dim firstResult = results.FirstOrDefault()
If firstResult IsNot Nothing AndAlso Not String.IsNullOrWhiteSpace(firstResult.Value.ToString()) Then
scannedText = firstResult.Value.ToString()
Else
scannedText = "QR value not found!"
End If
Catch ex As Exception
scannedText = "Error scanning QR code: " & ex.Message
End Try
End Function
最初,該方法會檢查用來保存上傳圖片路徑的 qrImageSrc
變量是否不為空。 此檢查可確保在繼續執行之前有一個有效的圖像可以使用。
一旦確認圖像已準備好進行處理,該方法將進行 QR 碼讀取的核心功能。 這涉及幾個關鍵步驟,首先是將圖像從其存儲位置加載到適合 QR 代碼分析的格式中。 此轉換由 AnyBitmap.FromFile
實現(qrImageSrc)` 方法,該方法準備圖像以進行掃描過程。
下一步涉及創建一個 QrReader
對象。 此物件是IronQR庫不可或缺的一部分,作為從圖像解碼QR碼的主要工具。 在 QrReader
實例準備就緒後,應用程式隨即進行掃描上傳的圖像。 reader.Read(圖像輸入)負責此操作的
function 方法地搜索圖像中的QR碼並提取其數據。
掃描結果存儲在 IEnumerable
中集合。 然後對此集合進行檢查以找出第一個 QR code 結果。 如果檢測到 QR 碼,並且它包含可讀取的文字,該文字將被捕獲並存儲在
scannedText` 變數中。 然而,在找不到 QR 碼或不包含文本的情況下,應用程式會設定一條預設訊息來告知使用者未檢測到 QR 值。
成功掃描 QR 碼後,文字字串會顯示在文字輸入欄位中,這要歸功於 Blazor 的雙向數據綁定功能。 這是通過將 scannedText
變數綁定到文字輸入元素來實現的。 輸入欄位設置為禁用,變為只讀。 此設計選擇的重點在於將使用者的互動集中於查看結果並進行複製,而非編輯內容。
整個掃描過程封裝在 try-catch 區塊中,以防在掃描操作期間發生任何意外錯誤。 這可能包括與圖像文件格式相關的問題或在讀取過程中發生的意外錯誤。 如果發生異常,將會被捕獲,生成錯誤訊息並顯示給用戶。 此方法不僅有助於識別問題,還保持與用戶的透明度,從而提高應用程序的可靠性。
要啟用複製到剪貼板的功能,需要在 _Host.cshtml
檔案中定義一個名為 copyTextToClipboard
的 JavaScript 函式。這個腳本是一種既簡單又有效的方式來與剪貼板互動:
<script>
function copyTextToClipboard(text) {
navigator.clipboard.writeText(text).then(function () {
console.log('Copying to clipboard was successful!');
}, function (err) {
console.error('Could not copy text: ', err);
});
}
</script>
此功能接受一個文字參數,即要複製的文字。 它使用了 navigator.clipboard.writeText
方法,一種與剪貼簿互動的現代方法。 此方法因其簡單性和符合網路標準而受到青睞。 它被設計為在成功複製後在控制台記錄成功消息,有助於偵錯並確保功能順利運行。 如果發生錯誤,錯誤訊息將記錄到控制台,提供有關操作過程中遇到的任何問題的見解。
CopyToClipboard
方法位於 index.razor 的 @code
部分,作為 Blazor 應用程式和 JavaScript 函數之間的橋樑。 按鈕在使用者介面中觸發此方法的點擊。 啟動後,它會使用 Blazor 的 JavaScript InterOp 功能調用 copyTextToClipboard
JavaScript 函數。 scannedText
作為參數傳遞給此函數,從而有效地將文本複製到用戶的剪貼簿。
private async Task CopyToClipboard()
{
await JSRuntime.InvokeVoidAsync("copyTextToClipboard", scannedText);
}
private async Task CopyToClipboard()
{
await JSRuntime.InvokeVoidAsync("copyTextToClipboard", scannedText);
}
Private Async Function CopyToClipboard() As Task
Await JSRuntime.InvokeVoidAsync("copyTextToClipboard", scannedText)
End Function
運行項目後,用戶將看到以下清晰簡單的介面。 初始畫面顯著顯示了QR Code掃描器模組。 此模組包含一個按鈕,用於上傳 QR 碼圖像文件。(選擇檔案)並啟動掃描過程(掃描QR碼). 最初,未選擇任何檔案,掃描區域是空白的,等待使用者輸入。
使用者透過「選擇檔案」按鈕選擇並上傳 QR 碼圖片,現在此按鈕會顯示所選檔案的名稱。(例如,'qrvalue.png'
). 上傳的 QR 碼顯示在介面上的指定區域,確認圖像已準備好進行掃描。
當使用者點擊「掃描 QR Code」按鈕後,應用程式會處理該圖片。 如果掃描成功,QR碼中的文本會顯示在圖像下方。 在這種情況下,掃描結果('<https://ironsoftware.com/csharp/qr/>'
)是一個 URL,表示當用 QR 讀碼器掃描時,QR 碼將用戶引導至的位置。 結果旁邊會顯示複製按鈕,允許使用者輕鬆地將掃描的文字複製到剪貼簿以便進一步使用。
總結來說,將 IronQR 整合到 Blazor Server 應用程式的過程既順暢又有效,從而提供了一個 QR 碼掃描解決方案。 自專案設立之初到實現掃描功能為止,得益於 IronQR 強大的處理能力與 Blazor 動態 UI 呈現的結合,操作上回應快速且易於使用。 從設置環境到部署的過程,強調了此整合在實際應用中的實用性和有效性。 雖然 IronQR 擅長 QR 碼,但對於需要掃描條碼功能的專案,IronBarcode是一個理想的選擇,提供類似的便利性和整合水平。
IronQR 提供一個免費試用讓開發人員在購買前探索其功能。 如需在生產中擴展使用及存取其所有專業功能,IronQR 的授權價格起始於 $749。