在實際環境中測試
在生產環境中測試無浮水印。
在任何需要的地方都能運作。
本文探討了快速反應碼掃描器的整合 (QR碼掃描器) 在使用IronQR(一個 .NET 程式庫)的Blazor應用程式中,QR Code是一種二維條碼,比普通的一維條碼儲存更多的數據。
Blazor 是由 Microsoft 開發的框架,允許開發人員產生單頁應用程式 (使用 Blazor WebAssembly 應用程式) 或者使用 C# 來建立互動式網頁介面, (Blazor Server,本指南將著重於此)將 IronQR 與 Blazor Server 整合以進行 QR 碼掃描是利用這兩種技術優勢的戰略性組合。通過將 IronQR 與 Blazor 應用程式整合,您可以高效地處理 QR 碼的生成和掃描。在各種業務環境中,如庫存管理、票務系統和無接觸信息共享中,QR 碼讀取器的這種功能需求日益增長。
Blazor 伺服器 是一個屬於ASP.NET Core平台的網路應用程式框架。它使開發人員能夠使用C#而不是JavaScript來構建互動的網路UI。這種伺服器端模型通過SignalR連接來處理使用者互動,這是一種即時網路功能。這有助於開發人員創建高效且互動的網路應用程式。
IronQR 是一個.NET庫,以其讀取、解釋和 生成 QR 碼 具有高精確度。它提供了一系列功能,包括處理不同類型二維碼內容的能力。IronQR 的優勢在於其簡單性和便於集成至 .NET 應用程式的特點,使其成為尋求整合和創建二維碼功能的開發人員的首選。
在 Visual Studio Code 中建立 Blazor 伺服器應用程式
使用 NuGet 套件管理器安裝 QR Code 類別庫
使用 HTML 和 CSS 在 index.razor 中建立使用者介面
撰寫上傳檔案處理邏輯
使用 QR 庫撰寫 QR 掃描邏輯
啟動 Visual Studio 並選擇「建立一個新專案」。在專案範本選擇畫面中,找到並選擇「Blazor Server 應用程式」範本。點擊下一步。
選擇模板後,輸入項目名稱和位置 (保持其他所有設為預設值) 然後按下「下一步」按鈕。
現在選擇所需的 .NET Framework,然後點擊建立按鈕。它將創建一個 Blazor 伺服器應用程式。
點擊工具選單。從下拉選單中選擇 NuGet 套件管理器。從上下文菜單中選擇 “管理解決方案的 NuGet 套件”。這將打開 NuGet 套件管理器標籤。
在 NuGet 套件管理器中,在「瀏覽」標籤內搜尋「IronQR」。然後在列表中找到「IronQR」套件。點擊「安裝」按鈕。
現在您已安裝好所有東西,我們可以探討專案結構以及如何將所有內容實現到您的專案中。
QR Code Scanner 的使用者介面主要是在 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>
<title>
標籤和
<h1>
``` 標籤分別定義了頁面的標題和主要標題,為用戶設置了上下文。
圖片上傳控制: 一個 ```
<InputFile>
<component>
```元件用於上傳QR碼圖片。此元素專門用來接受圖像文件,通過篩選無關的文件類型來提升用戶體驗。
圖片顯示:一旦圖片上傳,就會使用```
<image>
``顯示。```
``` tag. This visual feedback is crucial for user assurance that the correct file has been uploaded.
Scan Button: A button tagged with ```
@onclick="ScanQRCode
``` triggers the scanning process. Its availability depends on whether a file is selected, enhancing the interface's intuitiveness.
Result Display: The scanned QR code's text is displayed in a text input field for easy viewing. A separate button allows users to copy this text to the clipboard.
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
e 捕獲文件的詳細信息。然後將 selectedFile
變量分配給此文件,並將布爾值 fileSelected
設置為 true,表示輸入數據/文件已準備好進行處理。
創建文件路徑:該方法準備了一個目錄來存儲上傳的圖像。它使用 Path.Combine
創建一個到'UploadedImages
'目錄的路徑,並使用 Directory.CreateDirectory
確保其存在。這一步對於系統化組織上傳文件至關重要。
生成唯一文件名:為了避免與現有文件發生衝突,使用 GUID 生成一個唯一的文件名。 (全域唯一識別碼) 附加上原始文件的扩展名。這確保每個上傳的文件都是 uniquePathdentified
。
保存文件:文件隨後被保存到伺服器上。該方法創建一個指向新生成文件路徑的文件流,並使用 await selectedFile.OpenReadStream
將上傳文件的內容複製到此流中。().CopyToAsync(文件流)`.
**準備影像顯示**:保存文件後,有必要將影像顯示給用戶進行確認。該方法將文件讀取為位元組陣列,並轉換為 base64 字符串,適合直接嵌入到
```<img>` tag 的 `src` 屬性。這種轉換允許顯示圖像,而不需向伺服器單獨請求圖像文件。
### 掃描 QR 碼
`ScanQRCode` 方法是 Blazor Server 應用程式中 QR 碼掃描功能的核心。此方法採用上傳的圖片並使用 IronQR 提取 QR 碼數據。
```cs
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;
}
}
一開始,該方法會檢查保存上傳圖像路徑的 qrImageSrc
變量是否不為空。此檢查確保在繼續之前有一個有效的圖像可供使用。
一旦確認圖像已準備好進行處理,該方法將進行 QR 碼閱讀的核心功能。這包括幾個關鍵步驟,首先是將圖像從存儲位置加載到適合 QR 碼分析的格式。這種轉換是通過 AnyBitmap.FromFile
實現的。(qrImageSrc)`方法,這方法會將圖像準備好以進行掃描過程。
下一步是創建一個QrReader
對象。這個對象是IronQR庫的核心部分,作為從圖像解碼QR碼的主要工具。準備好QrReader
實例後,應用程序會接著掃描上傳的圖像。`reader.Read(圖像輸入)此功能負責此操作,系統性地搜索圖像中的 QR 碼並提取其數據。
掃描結果存儲在 IEnumerable
中。集合。接著便會審查該集合以找到第一個 QR 碼結果。如果檢測到 QR 碼,且其中包含可讀文本,這些文本會被捕捉並存儲在
scannedText` 變數中。然而,如果在場景中未找到 QR 碼或者 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 碼掃描模組。此模組包含一個上傳 QR 碼圖像文件的按鈕。 (選擇檔案) 並啟動掃描過程 (掃描QR碼)最初,沒有選擇任何文件,掃描區域為空白,等待用戶輸入。
用戶使用“選擇檔案”按鈕選擇並上傳一個QR碼圖片,該按鈕現在會顯示所選檔案的名稱。 (例如,'qrvalue.png'
)上傳的 QR 碼可在介面指定區域中顯示,確認圖像已準備好被掃描。
用戶點擊「掃描 QR 碼」按鈕後,應用程式會處理影像。如果掃描成功,QR 碼中編碼的文本將顯示在影像下方。在這種情況下,掃描的結果 ( '<https://ironsoftware.com/csharp/qr/>'
) 是一个URL,指示QR码被QR读取器扫描时用户会被引导到的位置。复制作业按钮会出现在结果旁边,使用户可以轻松地将扫描到的文本复制到剪贴板以便进一步使用。
總結來說,將 IronQR 整合到 Blazor Server 應用程式中的過程既順暢又有效,最終實現了一個 QR 碼掃描解決方案。從開始設置這個項目到實現掃描功能,這過程既反應迅捷又容易使用,這都要歸功於 IronQR 強大的處理能力與 Blazor 動態 UI 渲染的結合。從設置環境到部署的整個過程,都強調了這種整合在實際應用中的實用性和有效性。雖然 IronQR 擅長處理 QR 碼,如果項目需要掃描條碼功能, IronBarcode 是理想的選擇,提供同樣的易用性和整合性。
IronQR 提供 免費試用 讓開發人員在購買之前探索其功能。要在生產環境中長期使用並訪問所有專業功能,IronQR 授權價格從 $liteLicense 起。