【SkiaSharp绘图15】SKPath属性详解:边界、填充、凹凸、类型判断、坐标、路径类型

news2024/10/6 6:57:36

文章目录

  • SKPath 构造函数
  • SKPath 属性
    • Bounds 边界(宽边界)
    • TightBounds紧边界
    • FillType填充方式
    • IsConcave 是否凹/ IsConvex 是否凸
    • IsEmpty是否为空
    • IsLine是否为线段
    • IsRect是否为矩形
    • IsOval是否为椭圆或圆
    • IsRoundRect是否为圆角矩形
    • Item[] 获取路径的坐标
    • LastPoint最后点的坐标
    • PointCount总共坐标点的个数
    • Points获取所有坐标点
    • SegmentMasks 路径包含的类型
    • VerbCount动词个数
    • 示例

SKPath 构造函数

public class SKPath : SkiaSharp.SKObject

复合的几何路径,封装由直线段、二次曲线、三次组成的复合(多轮廓)几何路径

public SKPath ();//构造一个空路径
public SKPath (SkiaSharp.SKPath path);//深拷贝一个已存在的路径。

可构造一个空路径或深拷贝一个已存在的路径。

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
using (var paint = new SKPaint())
using (var txtPaint = new SKPaint())
{
    paint.Color = SKColors.Red;
    paint.IsStroke = true;
    paint.IsAntialias = true;
    txtPaint.TextSize = 18;
    txtPaint.IsAntialias = true;
    txtPaint.Typeface = SKTypeface.FromFamilyName("宋体");

    var pathA=new SKPath();
    pathA.AddCircle(100, 100, 50);

    var pathB=new SKPath(pathA);//深拷贝

    pathA.AddRect(new SKRect(50, 200, 150, 300));

    canvas.DrawPath(pathA, paint);
    canvas.DrawText($"测试构造一个已存在路径时,深拷贝,还是浅拷贝。", 50, 400, txtPaint);

    canvas.Translate(300, 0);
    paint.Color = SKColors.Green;

    pathB.AddCircle(100,250,50);
    canvas.DrawPath(pathB, paint);

}
  1. 创建一个空路径pathA,并添加一个圆.
  2. 创建另一个复制路径pathB
  3. 在pathA中再加入一个矩形。
  4. 在pathB中加入另一个圆。
  5. pathA与pathB互不影响。
    SKPath构造函数
    克隆源路径有问题时,会抛出异常。

SKPath 属性

Bounds 边界(宽边界)

public SkiaSharp.SKRect Bounds { get; }

获取路径的边界矩形。如果路径为空,则返回空矩形。
注意些边界不是路径的真实边路,可能比实际边界大,因为其包含的是控制点或独立点(MoveTo)。

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
using (var paint = new SKPaint())
using (var txtPaint = new SKPaint())
{
    paint.Color = SKColors.Red;
    paint.IsStroke = true;
    paint.IsAntialias = true;
    paint.TextSize = 36;

    var path = new SKPath();
    var pts = new SKPoint[]
    {
        new SKPoint(100,100),
        new SKPoint(200,200),
        new SKPoint(300,50),
        new SKPoint(400,250),
        new SKPoint(500,150)
    };
    //绘制一段贝赛尔曲线
    path.MoveTo(pts[0]);
    path.CubicTo(pts[1], pts[2], pts[3]);
    //构造一个独立点
    path.MoveTo(pts[4]);

    canvas.DrawPath(path, paint);

    var bounds = path.Bounds;
    if (bounds != SKRect.Empty)
    {
        paint.StrokeWidth = 5;
        paint.Color = SKColors.Green;
        canvas.DrawRect(bounds, paint);
        canvas.DrawText($"Bounds",bounds.Right,bounds.Top, paint);
    }

    var tightBounds = path.TightBounds;
    if (tightBounds != SKRect.Empty)
    {
        paint.StrokeWidth = 3;
        paint.Color = SKColors.Purple;
        canvas.DrawRect(tightBounds, paint);
        canvas.DrawText($"TightBounds", tightBounds.Right, tightBounds.Bottom, paint);
    }

    paint.StrokeWidth = 10;
    paint.StrokeCap = SKStrokeCap.Round;
    paint.Color = SKColors.Blue;
    canvas.DrawPoints(SKPointMode.Points, pts, paint);
}
  1. 通过四个点构造一段贝赛尔曲线,并构造一个独立点
  2. 验证Bounds的边界情况。
  3. 验证TightBounds的边界情况
  4. 红色为曲线,绿色为Bounds,紫色为TightBounds,蓝色为控制点。
    在这里插入图片描述

TightBounds紧边界

public SkiaSharp.SKRect TightBounds { get; }

路径的实际边界。

FillType填充方式

public SkiaSharp.SKPathFillType FillType { get; set; }//默认是Winding

获取和设置路径的填充类型。
各枚举值的意义

  1. Winding(默认值)

    • 基于“非零缠绕数”规则来确定填充区域。
    • 当路径穿过点的次数(方向考虑在内)不为零时,点在填充区域内。
  2. EvenOdd

    • 基于“奇偶规则”来确定填充区域。
    • 当路径穿过点的次数为奇数时,点在填充区域内;为偶数时,点在填充区域外。
  3. InverseWinding

    • Winding 类似,但填充区域是 Winding 填充区域的反向。
    • 当路径穿过点的次数(方向考虑在内)不为零时,点在填充区域外。
  4. InverseEvenOdd

    • EvenOdd 类似,但填充区域是 EvenOdd 填充区域的反向。
    • 当路径穿过点的次数为奇数时,点在填充区域外;为偶数时,点在填充区域内。
/// <summary>
/// 获取五星路径
/// </summary>
/// <returns></returns>
private SKPath GetStarPath(SKPoint center,float outerRadius)
{
    // 计算五角星的角度
    float angleStep = (float)(2 * Math.PI / 5);

    // 设置五角星的尺寸和位置
    //float outerRadius = 100;
    //SKPoint center = new SKPoint(150, 150); // 五角星中心点的位置

    // 计算五个顶点的坐标
    SKPoint[] starPoints = new SKPoint[5];
    for (int i = 0; i < 5; i++)
    {
        float angle = angleStep * i;
        // 外部顶点
        float x = center.X + outerRadius * (float)Math.Sin(angle);
        float y = center.Y - outerRadius * (float)Math.Cos(angle); // 减号确保顶点在中心上方
        starPoints[i] = new SKPoint(x, y);
    }
    var starPath=new SKPath();
    // 开始定义路径
    starPath.MoveTo(starPoints[0]); // 从第一个顶点开始

    int index2 = 0;
    // 连接相隔的两个顶点
    for (int i = 2; i <= 5; i ++)
    {
        index2 = (index2 + 2) % 5;
        starPath.LineTo(starPoints[index2]);
    }

    // 关闭路径
    starPath.Close();
    return starPath;
}
var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
var info = e.Info;
using (var paint = new SKPaint())
using (var txtPaint = new SKPaint())
{

    paint.IsAntialias = true;
    paint.TextAlign = SKTextAlign.Center;
    paint.StrokeWidth = 3;
    paint.TextSize = 24;

    var path = GetStarPath(new SKPoint(150, 150),100F);
    var fillTypes = Enum.GetValues(typeof(SKPathFillType)) as SKPathFillType[];

    float dx = info.Width / 2;
    float dy = info.Height / 2; ;
    var index = 0;
    //
    foreach (var fillType in fillTypes)
    {
        path.FillType = fillType;
        canvas.Save();
        canvas.Translate(dx * (index % 2), dy * (index / 2));
        canvas.ClipRect(SKRect.Create(dx, dy));
        paint.Color = SKColors.Red;
        canvas.DrawPath(path, paint);
        paint.Color = SKColors.Green;
        canvas.DrawText($"FillType:{fillType}", 150, 280, paint);               
        canvas.Restore();
        index++;
    }
}
  1. 定义一个生成五角星的函数
  2. 将画布分成四块,在每一块用不同的填充方式绘制五角星。

FillType

IsConcave 是否凹/ IsConvex 是否凸

public bool IsConcave { get; }
public bool IsConvex { get; }

判断一个路径的凹凸性。

  • 凹点(Convex Point):如果轮廓上的每个点都在其相邻两个点所形成的线段的同侧(包括线段上的端点),那么这个点就是凸的。
  • 凹点(Concave Point):如果轮廓上的某个点不满足凸点的定义,则称其为凹点。
var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
var info = e.Info;
using (var paint = new SKPaint())
{
    paint.IsAntialias = true;
    paint.StrokeWidth = 3;
    paint.TextSize = 24;
    paint.Color = SKColors.Red;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");

    var pathA = GetStarPath(new SKPoint(150, 150), 100);
    var pathB = new SKPath();
    pathB.AddRect(new SKRect(300, 50, 500, 200));

    canvas.DrawPath(pathA, paint);
    canvas.DrawText($"IsConcave凹:{pathA.IsConcave}", 20, 280, paint);
    canvas.DrawText($"IsConvex 凸:{pathA.IsConvex}", 20, 320, paint);

    canvas.DrawPath(pathB, paint);
    canvas.DrawText($"IsConcave凹:{pathB.IsConcave}", 320, 280, paint);
    canvas.DrawText($"IsConvex 凸:{pathB.IsConvex}", 320, 320, paint);
}

绘制一个五角星和一个矩形,判断其凹凸性。
IsConcave/IsConvex

IsEmpty是否为空

public bool IsEmpty { get; }

判断一个路径是否不包含任何线段或曲线。

IsLine是否为线段

public bool IsLine { get; }

判断一个路径是否为一条线段。

IsRect是否为矩形

public bool IsRect { get; }

判断路径是否为矩形。
注意,不是水平、垂直相交相连的线组成的矩形,这里返回的结果还是false。(是Skia的Bug吗?)

IsOval是否为椭圆或圆

public bool IsOval { get; }

判断路径是否为椭圆或圆。
注意四段贝赛尔曲线构成的圆,这里返回的结果还是false。

IsRoundRect是否为圆角矩形

public bool IsRoundRect { get; }

判断路径是否为圆角矩形。

** 相关示例 **

var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
var info = e.Info;
using (var paint = new SKPaint())
{
    paint.IsAntialias = true;
    paint.StrokeWidth = 3;
    paint.TextSize = 24;
    paint.Color = SKColors.Red;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");

    var pathA = new SKPath();
    var offsetY = 30F;
    var offsetX = 150F;
    canvas.DrawText($"1.new SKPath() IsEmpty:{pathA.IsEmpty}", offsetX, offsetY, paint);                
    offsetY += paint.FontSpacing;
    pathA.MoveTo(50, 50);
    canvas.DrawText($"2.1 MoveTo(50, 50) IsEmpty:{pathA.IsEmpty}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;

    canvas.DrawText($"2.1 MoveTo(50, 50) IsLine: {pathA.IsLine}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;

    pathA.LineTo(100, 50);
    canvas.DrawText($"3 LineTo(100, 50 IsLine: {pathA.IsLine}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;

    pathA.LineTo(100, 100);
    pathA.LineTo(50, 100);
    pathA.Close();
    canvas.DrawText($"4 LineTo(100, 100),LineTo(50, 100),Close() IsRect: {pathA.IsRect}", offsetX, offsetY, paint);

    canvas.DrawPath(pathA, paint);

    var pathB=new SKPath();
    pathB.MoveTo(100, 150);
    pathB.LineTo(150, 200);
    pathB.LineTo(100, 250);
    pathB.LineTo(50, 200);
    pathB.Close();
    paint.IsStroke = true;
    canvas.DrawPath(pathB, paint);

    var width = (float)(Math.Sqrt(2) * 50);

    offsetY += 100;
    canvas.DrawText($"pathB IsRect: {pathB.IsRect}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
    var pathC=new SKPath();

    var rect = new SKRect(0, 0, width, width);
    paint.IsStroke = false;
    pathC.AddRect(rect);
    paint.Color = SKColors.LightGreen.WithAlpha(128);
    canvas.DrawText($"与pathB相同大小的pathC IsRect: {pathC.IsRect}", offsetX, offsetY, paint);

    canvas.Save();
    canvas.Translate(100, 150);
    canvas.RotateDegrees(45F);

    canvas.DrawPath(pathC, paint);
    canvas.Restore();

    var pathD=new SKPath();
    pathD.AddCircle(100, 350, 50);
    paint.IsStroke = true;
    canvas.DrawPath(pathD, paint);
    offsetY += 100;
    canvas.DrawText($"pathD IsOval: {pathD.IsOval}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;

    var pathE = CreateCircleWithBeziers(100, 350, 50);
    paint.Color = SKColors.LightBlue.WithAlpha(128);
    paint.IsStroke = false;
    canvas.DrawPath(pathE, paint);
    canvas.DrawText($"贝赛尔曲线构成的圆 pathE IsOval: {pathE.IsOval}", offsetX, offsetY, paint);
    offsetY += 100;

    paint.Color = SKColors.LightBlue;
    canvas.DrawText($"pathC IsRoundRect: {pathE.IsRoundRect}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
    var pathF = new SKPath();
    pathF.AddRoundRect(new SKRect(30, 450, 150, 500), 10, 20);
    canvas.DrawPath(pathF, paint);
    canvas.DrawText($"pathF IsRoundRect: {pathF.IsRoundRect}", offsetX, offsetY, paint);
}

四条贝赛尔构成的圆

/// <summary>
/// 四条贝赛尔曲线构成的圆
/// </summary>
/// <param name="centerX"></param>
/// <param name="centerY"></param>
/// <param name="radius"></param>
/// <returns></returns>
public SKPath CreateCircleWithBeziers(float centerX, float centerY, float radius)
{
    // 定义路径
    var path = new SKPath();

    // 贝塞尔曲线控制点的系数
    float c = (float)(radius * (4.0f / 3.0f) * (Math.Sqrt(2) - 1));

    // 定义起点
    path.MoveTo(centerX + radius, centerY);

    // 第一段贝塞尔曲线
    path.CubicTo(centerX + radius, centerY + c, centerX + c, centerY + radius, centerX, centerY + radius);

    // 第二段贝塞尔曲线
    path.CubicTo(centerX - c, centerY + radius, centerX - radius, centerY + c, centerX - radius, centerY);

    // 第三段贝塞尔曲线
    path.CubicTo(centerX - radius, centerY - c, centerX - c, centerY - radius, centerX, centerY - radius);

    // 第四段贝塞尔曲线
    path.CubicTo(centerX + c, centerY - radius, centerX + radius, centerY - c, centerX + radius, centerY);

    // 闭合路径
    path.Close();

    return path;
}

路径形状判断

Item[] 获取路径的坐标

public SkiaSharp.SKPoint this[int index] { get; }

获取路径上指定序号的点的坐标。如果序号超出小于0或大于等于PointCount,则返回(0,0)。

LastPoint最后点的坐标

public SkiaSharp.SKPoint LastPoint { get; }

获取路径的最后一个点的坐标。如果路径为空,返回(0,0)。

PointCount总共坐标点的个数

public int PointCount { get; }

获取路径所有坐标点的个数。

Points获取所有坐标点

public SkiaSharp.SKPoint[] Points { get; }

获取路径所有坐标点。注意,这些点包含控制点,即不一定在路径轮廓上。

SegmentMasks 路径包含的类型

public SkiaSharp.SKPathSegmentMask SegmentMasks { get; }

获取一组标志,指示路径是否包含该类型的一个或多个段。

说明
Line =1线段(2个点)
Quad=2二次贝赛尔曲线(3个点)
Cubic=8三次贝赛尔曲线(4个点)
Conic=4圆锥曲线(3个点+权重)

VerbCount动词个数

public int VerbCount { get; }

获取路径中动词的数量(即SKPathVerb,有Move、Line、Quad、Conic、Cubic、Close、Done)
用SKPath对象的CreateRawIterator可获取相关SKPathVerb。

示例

  1. 在路径中添加圆、矩形、椭圆、圆角矩形、画线段、二次/三次贝赛尔曲线
  2. 通过路径动词和坐标集来复制一个路径。
var canvas = e.Surface.Canvas;
canvas.Clear(SKColors.White);
var info = e.Info;
using (var paint = new SKPaint())
{
    paint.IsAntialias = true;
    paint.StrokeWidth = 7;
    paint.IsStroke = true;
    paint.TextSize = 24;
    paint.Color = SKColors.Red;
    paint.Typeface = SKTypeface.FromFamilyName("宋体");

    var path=new SKPath();
    path.AddCircle(200, 200, 100);

    path.AddRect(new SKRect(350, 100, 550, 200));

    path.AddOval(new SKRect(100, 350, 300, 450));

    path.AddRoundRect(new SKRoundRect(new SKRect(400,350,700,500),30));

    path.LineTo(300, 600);

    canvas.DrawPath(path, paint);

    var pts = path.Points;

    var verbCount = path.VerbCount;
    paint.Color = SKColors.Blue;
    canvas.DrawPoints(SKPointMode.Points, pts, paint);

    paint.StrokeWidth = 2;
    var drawPtList=new List<SKPoint>();
    for (int i = 0; i < pts.Length; i++)
    {
        var pt = pts[i];
        var count = drawPtList.Count(z => z.Equals(pt));
        if (count > 0)
        {
            var color = paint.Color;
            paint.Color = SKColors.Green;
            canvas.DrawText($"{i}", new SKPoint(pt.X - paint.TextSize * count, pt.Y), paint);
            paint.Color = color;
        }
        else
        {
            canvas.DrawText($"{i}", pts[i], paint);
        }
        drawPtList.Add(pt);
    }

    paint.Color = SKColors.Green;

    var newPath = ClonePathByVerb(path);

    paint.StrokeWidth = 1;
    canvas.DrawPath(newPath, paint);

    var offsetX = 20F;
    var offsetY = 500F;
    canvas.DrawText($"Path.PointCount:{path.PointCount}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
    canvas.DrawText($"Path.SegmentMasks:{path.SegmentMasks}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
    canvas.DrawText($"Path.VerbCount:{path.VerbCount}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
    canvas.DrawText($"Path.LastPoint:{path.LastPoint}", offsetX, offsetY, paint);
    offsetY += paint.FontSpacing;
}

SKPath属性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1895726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript——while类型

目录 任务描述 相关知识 while类型 编程要求 任务描述 质数的定义如下&#xff1a;大于1的自然数&#xff0c;且除了1和本身外没有别的因数。如2、3、5、7。 本关任务&#xff1a;利用循环结构求质数的和。 相关知识 在选择结构中&#xff0c;条件会被测试一次&#xff…

第一百四十三节 Java数据类型教程 - Java Boolean包装类

Java数据类型教程 - Java Boolean包装类 布尔类的对象包装一个布尔值。 Boolean.TRUE和Boolean.FALSE是布尔类型的两个常量&#xff0c;用于表示布尔值true和false值。 我们可以使用构造函数或valueOf()工厂方法创建一个布尔对象。 当解析字符串时&#xff0c;此类将处理“t…

复现centernet时,报错RuntimeError: CUDA error: out of memory

运行 python test.py ctdet --dataset coco --exp_id coco_dla --load_model /root/CenterNet/exp/ctdet/coco_dla/model_last.pth --gpus 0 --test_scales 1 报错下面&#xff1a; RuntimeError: CUDA error: out of memory明明显存是够用的 解决办法&#xff1a; 找到自己…

RK3568平台(opencv篇)ubuntu18.04上安装opencv环境

一.什么是 OpenCV-Python OpenCV-Python 是一个 Python 绑定库&#xff0c;旨在解决计算机视觉问题。   Python 是一种由 Guido van Rossum 开发的通用编程语言&#xff0c;它很快就变得非常流行&#xff0c;主要是 因为它的简单性和代码可读性。它使程序员能够用更少的代码行…

LVS-DR负载均衡

LVS-DR负载均衡 LVS—DR工作模式 原理 客户端访问调度器的VIP地址&#xff0c;在路由器上应该设置VIP跟调度器的一对一的映射关系&#xff0c;调度器根据调度算法将该请求“调度“到后端真实服务器&#xff0c;真实服务器处理完毕后直接将处理后的应答报文发送给路由器&#xf…

[Redis]哨兵机制

哨兵机制概念 在传统主从复制机制中&#xff0c;会存在一些问题&#xff1a; 1. 主节点发生故障时&#xff0c;进行主备切换的过程是复杂的&#xff0c;需要人工参与&#xff0c;导致故障恢复时间无法保障。 2. 主节点可以将读压力分散出去&#xff0c;但写压力/存储压力是无法…

二、基础—常用数据结构:列表、元祖、集合、字典、函数等(爬虫及数据可视化)

二、基础—常用数据结构&#xff1a;列表、元祖、集合、字典、函数等&#xff08;爬虫及数据可视化&#xff09; 1&#xff0c;字符串2&#xff0c;最常用的是列表&#xff08;重点掌握&#xff09;3&#xff0c;元组4&#xff0c;字典&#xff08;重要&#xff09;5&#xff0…

卫星IoT产品发展前景

卫星IoT产品发展前景 一、概述 卫星IoT产品是指利用卫星通信技术实现物联网设备互联互通的解决方案。随着卫星互联网技术的快速发展&#xff0c;卫星IoT产品正逐渐成为解决偏远地区、海洋、航空等场景下物联网连接问题的重要手段。 二、性能特点 广泛覆盖&#xff1a; 卫星…

搜维尔科技:如何使用 SenseGlove Nova 加速手部运动功能的恢复

District XR 的VR 培训 5 年多来&#xff0c;District XR 一直在为最大的工业公司创建 VR 和 AR 项目。 客户&#xff1a;District XR 客户代表&#xff1a;尼古拉沃尔科夫 他的角色&#xff1a;District XR 首席执行官 面临解决的挑战 该公司正在寻找一种方法来加速身体伤…

k8s离线安装安装skywalking9.4

目录 概述资源下载Skywalking功能介绍成果速览实践rbacoapoap-svcuiui-svc 结束 概述 k8s 离线安装安装 skywalking9.4 版本&#xff0c;环境&#xff1a;k8s版本为&#xff1a;1.27.x 、spring boot 2.7.x spring cloud &#xff1a;2021.0.5 、spring.cloud.alibab&#xff1…

搜维尔科技:【研究】Scalefit人体工程学测量系统为预防肌肉骨骼疾病提供生物力学分析

与工作相关的肌肉骨骼疾病(MSE)是工作生活中的一个持续的伴侣。总部位于科隆的Scaleit公司生产的移动生物力学测量系统Industrial Athlete有助于在工作场所立即发现疾病&#xff0c;伤害和损伤的原因。 Scalefit是一个跨学科网络的一部分&#xff0c;在德国科隆体育大学和职业…

Linux手动安装JDK1.8

1、下载要安装的jdk安装包文件 官网下载地址&#xff1a;https://www.oracle.com/cn/java/technologies/downloads/ 2、上传jdk安装包至要安装服务器 3、在要安装jdk位置使用命令解压安装包 安装路径: /usr/local/java 解压安装包&#xff0c;解压命令 tar -zxvf /install…

2024攻防演练:亚信安全新一代WAF,关键时刻守护先锋

实网攻防 网络安全如同一面坚固的盾牌&#xff0c;保护着我们的信息资产免受无孔不入的威胁。而其中&#xff0c;WAF就像网络安全的守门员&#xff0c;关键时刻挺身而出&#xff0c;为您的企业筑起一道坚实的防线。 攻防不对等 防守方实时应答压力山大 在攻防对抗中&#xf…

字符设备驱动程序

简单做个模板框架 字符设备开发流程 确定设备号dev_t&#xff0c;动态分配 alloc_chrdev_region() 或静态分配 register_chrdev_region()定义file_opeartion 结构体*fops *&#xff0c;在结构体成员中实现对应的 *open()、read()*等函数。cdev_init() 将 fops 与 cdev 绑定&…

如何在 Selenium Python 中解决验证码 | 2024 完整指南

由于在进行网络自动化时遇到验证码是让许多人感到不知所措的问题。这些验证码专为区分人类用户和自动化脚本而设计&#xff0c;对于使用Selenium进行网络爬虫或自动化任务而言&#xff0c;无疑是一个巨大的挑战。2024年的完全指南将为您提供全面的解决方案&#xff0c;帮助您高…

Mac本地部署大模型-单机运行

前些天在一台linux服务器&#xff08;8核&#xff0c;32G内存&#xff0c;无显卡&#xff09;使用ollama运行阿里通义千问Qwen1.5和Qwen2.0低参数版本大模型&#xff0c;Qwen2-1.5B可以运行&#xff0c;但是推理速度有些慢。 一直还没有尝试在macbook上运行测试大模型&#xf…

ARIES,数据恢复算法,万变不离其宗...

今天来聊两个问题&#xff1a; 1. 如果缓冲池&#xff08;buffer pool&#xff09;满了&#xff0c;哪些数据页&#xff08;page&#xff09;要刷盘&#xff0c;哪些数据页不刷盘&#xff1f; 2. 数据库崩了&#xff0c;怎么利用检查点&#xff08;checkpoint&#xff09;与预写…

MATLAB环境下4种噪声生成

生成噪声包括: 1)粉红色(闪烁)噪声-功率谱密度斜率-3 dB/oct。&#xff0c; - 10db /dec 2)红色(布朗)噪声-功率谱密度斜率-6 dB/oct。&#xff0c; - 20db /dec 3)蓝色噪声-功率谱密度斜率3 dB/oct。&#xff0c; 10db /dec 4)紫色(紫色)噪声-功率谱密度斜率 6db /oct。&…

鸿蒙如何打包应用程序

总结鸿蒙应用程序包 之前文章详细讲解了关于三种程序包的内容&#xff0c;现在简单总结一下&#xff1a; 1. 总结 首先需要搞清楚鸿蒙项目的模块Module的分类: Module分为“Ability”和“Library”两种类型 HAP HAP: Harmony Ability Package , 叫做鸿蒙Ability包。 “Abil…