How to draw in. NET 6?

How to draw in. NET 6?

Looking at Microsoft's information, I found that starting from. NET 6, it can only be used on Windows, but fortunately, the official also gave several solutions.

最后更新 5/28/2023 9:31 PM
VleaStwo
预计阅读 8 分钟
分类
.NET
标签
.NET C#

This article was submitted by netizens, and more friends are welcome to share.

Author: VleaStwo

1. linguistic backgrounds

  1. .NET 6/7/8
  2. ASP.NET Core Blazor

2. Demand background

  1. Generate URLs or other information into QR codes
  • Used for terminal scanning code to view information
  1. Place certain text information near the QR code
  • Used for users to directly view information (partial)

3. solution route

  1. QR code generation tool

There are many versions of QR codes generated. Here, the Net.Codecrete.QrCodeGenerator v2.0.3

  • Link:

GitHub Link: https://github.com/manuelbl/QrCodeGenerator

NuGet Link: https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/2.0.3

There were no problems here, so I didn't try other solutions, it was much the same.

  1. drawing tools
  • According to the plan given by the big shots in the group, using "Graphics" failed

  • Looking at Microsoft's information, I found that starting from. NET 6, it can only be used on Windows, but fortunately, the official also gave several solutions:

  • I chose SkiaSharp v2.88.3
  • Link:

GitHub Link: https://github.com/mono/SkiaSharp

Nutget Link: https://www.nuget.org/packages/SkiaSharp/2.88.3

  1. layout

The positional relationship between QR codes and text must be basically fixed. It doesn't matter whether you choose to draw the layout on paper or computer. The purpose of drawing in advance is to facilitate the calculation of positioning points. In fact, you still have to design the layout according to your own business.(* If you have strong brain power, you can not rely on brain caching *).

Practical code

  1. QR generation

If there is nothing to explain, just solve it with one line of code:

// 调用语句
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);
}
  1. drawing
  • Qr needs to be converted to a class similar to bitmap to continue secondary drawing

https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/2.0.3

It has already explained that different platforms require different solutions

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

** The general meaning above is to choose the corresponding conversion method according to your needs. The corresponding demo extension class has been written in github and can be copied directly. **

  • What I use here is SkiaSharp. I need to first convert the qr above into a usable SKBitmap. If I use this method, I can directly download the corresponding extension class from the project's github. I can directly put the corresponding source code link here and download it yourself: 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);
  • After getting the bmp, according to my layout settings, I used the size of the picture as the base, and 1/10 is the character height
int h = bmp.Height / 10;
  • When creating a brush, parameters are common and will not be explained
var paint = new SKPaint
{
    Color = SKColors.Black,
    IsAntialias = true,
    IsLinearText = true,
    TextEncoding = SKTextEncoding.Utf8,
    Typeface = SKTypeface.FromFamilyName("微软雅黑"),
    TextSize = h,
    TextAlign = SKTextAlign.Left,
};
  • Create a double font brush for the top area
var tempPaint = paint.Clone();
tempPaint.TextSize = 2 * h;
  • Create a painting table (board)
SKSurface sKSurface = SKSurface.Create(
    new SKImageInfo(bmp.Width * 3, bmp.Height * 2));
  • Create a canvas and fill it with white
var canvas = sKSurface.Canvas;
canvas.DrawColor(SKColors.White);
  • Draw the top area (normally, it should be a pre-drawn top pattern)
// 左边缩进一个单位 然后向下偏移四个单位
canvas.DrawText(top,
    new SKPoint(01 * h, 04 * h),
    tempPaint);
// top是string类型 内容是顶部区域的文字内容
// SKPoint就一个常规的x,y组成的point
// 记住是左上角为(0,0)右下角是(∞,∞)就对了
  • Draw the title area
// 首先根据自己写的算法把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);
}
  • The source code of the line feed algorithm used is as follows
/// <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;
}

** Note: This was found online with partial modifications, not written from 0 **

  • QR code in the lower left corner
// 因为二维码自身就对周围做了缩进处理 所以不需要再缩进
canvas.DrawBitmap(bmp, new SKPoint(00 * h, 10 * h));
  • Text remarks in the lower right corner
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++;
    }
}
  • Final drawing
// filename 要保存的文件名 记得是png文件
using (var image = sKSurface.Snapshot())
{
    using (var writeStream = File.OpenWrite(filename))
    {
        // 80是品质 够了
        image.Encode(
            SKEncodedImageFormat.Png,
            80)
            .SaveTo(writeStream);
    }
}

actual effect

  • test code
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();
}
  • test results

** Note: The picture is on a white background. If the current page also has a white background, it is easy to see the edge of the picture, it is recommended to download the picture and watch it yourself **

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读