本文由網友投稿,歡迎更多的朋友來分享。
作者:vleastwo
1. 語言背景
- .NET 6/7/8
- ASP.NET Core Blazor
2. 需求背景
- 將url或其他信息生成二維碼
- 用於終端掃碼查看信息
- 在二維碼附近布置一定的文字信息
- 用於用戶直接查看信息 (部分)
3. 解決路線
- 二維碼生成工具
生成二維碼版本非常多這裡選用的是 net.codecrete.qrcodegenerator v2.0.3
- 連結:
github連結: https://github.com/manuelbl/QrCodeGenerator
nuget連結: https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/2.0.3
這裡沒出現什麼問題所以就不嘗試其他方案了, 大同小異。
- 繪圖工具
- 根據群里大佬給的方案, 採用 "graphics" 結果失敗

- 查閱微軟資料發現從.net 6開始只能在只能在windows上使用, 不過好在官方也給了幾條解決方案:

- 我選擇的是 skiasharp v2.88.3
- 連結:
github連結: https://github.com/mono/SkiaSharp
nutget連結: https://www.nuget.org/packages/SkiaSharp/2.88.3
- 布局
二維碼和文字的位置關係肯定是基本固定的,選擇徒手畫紙上還是電腦上畫布置圖都不影響,提前畫圖的目的是為了方便計算定位點,實際還是要根據自己的業務來設計布局的(腦力強大的可以不畫 靠大腦緩存)。
實操代碼
- qr生成
沒什麼需要講解的就一行代碼解決:
// 调用语句
var qr = QrCode.EncodeText(mes, QrCode.Ecc.Quartile);
// 库源码
// 简化备注
// text:要编码的文本
// ecl: 二维码质量等级
public static QrCode EncodeText(string text, Ecc ecl)
{
Objects.RequireNonNull(text);
Objects.RequireNonNull(ecl);
var segments = QrSegment.MakeSegments(text);
return EncodeSegments(segments, ecl);
}
- 繪圖
- qr需要轉換成類似bitmap的類才能繼續二次繪圖
https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/2.0.3
裡面已經說明了不同平台需要不同方案
Raster Images / Bitmaps Starting with .NET 6, System.Drawing is only supported on Windows operating system and thus cannot be used for multi-platform libraries like this one. Therefore, ToBitmap() has been removed and three options are now offered in the form of method extensions. To use it: Select one of the imaging libraries below Add the NuGet dependencies to your project Copy the appropriate QrCodeBitmapExtensions.cs file to your project Imaging library Recommendation NuGet dependencies Extension file System.Drawing For Windows only projects System.Drawing.Common QrCodeBitmapExtensions.cs SkiaSharp For macOS, Linux, iOS, Android and multi-platform projects SkiaSharp and SkiaSharp.NativeAssets.Linux (for Linux only) QrCodeBitmapExtensions.cs ImageSharp Currently in beta state SixLabors.ImageSharp.Drawing QrCodeBitmapExtensions.cs
上文大致意思就是根據自己的需要選擇對應的轉換方法,在github中已經寫好了對應的demo拓展類可以直接複製。
- 我這裡採用的是skiasharp, 需要先把上面的qr轉換成可以使用的skbitmap, 方法的話直接從項目的github上可以直接下載對應的擴展類,我這裡直接放對應源碼連結 可以自行下載: QrCode转SkiaSharp(SKBitmap)源码 。
<param name="scale">The width and height, in pixels, of each module.(翻译: 宽度和高度,以像素为单位,每个模块)</param>
<param name="border">The number of border modules to add to each of the four sides.(翻译: 边界模块的数量增加的四个方面)</param>
var bmp = qr.ToBitmap(10, 2);
- 拿到bmp以後,根據我的布局設定,我以圖片的尺寸作為基底,1/10即為字高
int h = bmp.Height / 10;
- 創建畫筆,參數比較常見就不解釋了
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
IsLinearText = true,
TextEncoding = SKTextEncoding.Utf8,
Typeface = SKTypeface.FromFamilyName("微软雅黑"),
TextSize = h,
TextAlign = SKTextAlign.Left,
};
- 再創建一個兩倍字號的畫筆用於頂部區域
var tempPaint = paint.Clone();
tempPaint.TextSize = 2 * h;
- 創建畫桌(板)
SKSurface sKSurface = SKSurface.Create(
new SKImageInfo(bmp.Width * 3, bmp.Height * 2));
- 創建畫布並填充白色
var canvas = sKSurface.Canvas;
canvas.DrawColor(SKColors.White);
- 畫頂部區域(正常來說應該是預先畫好的一張頂部圖案)
// 左边缩进一个单位 然后向下偏移四个单位
canvas.DrawText(top,
new SKPoint(01 * h, 04 * h),
tempPaint);
// top是string类型 内容是顶部区域的文字内容
// SKPoint就一个常规的x,y组成的point
// 记住是左上角为(0,0)右下角是(∞,∞)就对了
- 畫標題區域
// 首先根据自己写的算法把string转换成 List<string>
// 目的是为了文字过长的时候能够换行
var titles = GetTextLines(title, 28).ToList();
for (int i = 0; i < titles.Count; i++)
{
canvas.DrawText(
titles[i],
new SKPoint(01 * h, (07 + i) * h),
paint);
}
- 用的換行算法源碼如下
/// <summary>
/// 文字换行算法
/// </summary>
/// <param name="text">原文</param>
/// <param name="maxLength">单行最大字数</param>
/// <returns>多行</returns>
private static IEnumerable<string> GetTextLines(
string text, int maxLength)
{
// 注意 maxLength 是字数不是实际宽度
string[] words = text.Select(x => x.ToString()).ToArray(); //text.Split(' ');
List<string> lines = new List<string>();
string line = string.Empty;
foreach (string word in words)
{
//if (!string.IsNullOrEmpty(line))
//{
// line += " ";
//}
if (line.Length + word.Length <= maxLength)
{
line += word;
}
else
{
lines.Add(line);
line = word;
}
}
lines.Add(line);
return lines;
}
注意: 這是在網上找到的有部分修改,不是我從0開始寫的
- 左下角二維碼
// 因为二维码自身就对周围做了缩进处理 所以不需要再缩进
canvas.DrawBitmap(bmp, new SKPoint(00 * h, 10 * h));
- 右下角文字備註
int row = 1;
for (int i = 0; i < notes.Count; i++)
{
var strs = GetTextLines(notes[i], 18);
foreach (var str in strs)
{
// 右下角10h位置 并且左右各缩进1h
// row*h 文字下移位置
canvas.DrawText(str,
new SKPoint(10 * h, (10 + 1) * h + row * h),
paint);
row++;
}
}
- 最後出圖
// filename 要保存的文件名 记得是png文件
using (var image = sKSurface.Snapshot())
{
using (var writeStream = File.OpenWrite(filename))
{
// 80是品质 够了
image.Encode(
SKEncodedImageFormat.Png,
80)
.SaveTo(writeStream);
}
}
實際效果
- 測試代碼
static void Main(string[] args)
{
// 二维码内容
string mes = "https://www.dotnet9.com/";
// 标题
string title = "ThingsGateway 基于net6/7+ ,跨平台边缘采集(物联网)网关";
// 文字备注
List<string> notes = new List<string>()
{
"Blazor Server架构,开发部署更简单",
"采集/上传配置完全支持Excel导入导出",
"插件式驱动,方便驱动二次开发",
"时序数据库存储",
"实时/历史报警(Sql转储),支持布尔/高低限值",
};
string filename =
Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".png");
// 顶部区域内容
string top = "开源.NET 7和Blazor组合开发";
// 封装的方法
QrCreate.HorizontalDraw(mes, title, notes, filename, top);
Console.WriteLine(filename);
Console.ReadLine();
}
- 測試結果

備註:圖片是白底的,如果當前頁面也是白底容易看不到圖片的邊緣建議自行下載圖片觀看