2024-11-22 18:33:46
本文基于透明图片的透明度获取轮廓;如不透明图片获取轮廓需要先把图片转成灰度图片,根据灰度值获取轮廓。
o c o o
o o b o
o a o o
o o o
// 从 a 找到 b,方向为 1 (0 是正上方)
// 那个 b 就在 a 的 1 方向,a 就在 b 的 5方向
// 但 b 的 6 方向已经被 a 找过了, 所以 b 的起始方向就是 7
// 总结 b 在 a 的 n 方向,则 b 的起始方向为 n + 6
/// <summary>
/// 边界算法
/// </summary>
/// <returns></returns>
private static SKPath? TraceContour(SKPixmap pixMap, int beginX, int beginY)
{
var path = new SKPath();
path.MoveTo(beginX, beginY);
var directItems = new int[][] {
[0, -1], [1, -1],
[1, 0],
[1, 1], [0, 1], [-1, 1],
[-1, 0], [-1, -1]
};
var beginDirect = 0;
var isBegin = false;
var curX = beginX;
var curY = beginY;
while (!isBegin)
{
var i = 0;
var direct = beginDirect;
var hasPoint = false;
while (i ++ <= directItems.Length)
{
var x = curX + directItems[direct][0];
var y = curY + directItems[direct][1];
// 判断点是否是透明像素点
if (IsTransparent(pixMap, x, y))
{
direct = (direct + 1) % directItems.Length;
continue;
}
hasPoint = true;
curX = x;
curY = y;
if (curX == beginX && curY == beginY)
{
isBegin = true;
path.Close();
}
else
{
path.LineTo(curX, curY);
}
beginDirect = (direct + 6) % directItems.Length;
break;
}
if (!hasPoint)
{
// 所有方向都没有找到下一个不透明点,表明这就是一个孤点
return null;
}
}
return path;
}
/// <summary>
/// 物体轮廓获取
/// </summary>
public class ImageContourTrace
{
public ImageContourTrace()
{
}
public ImageContourTrace(bool isOutline)
{
IsOutline = isOutline;
}
/// <summary>
/// 外边框,即靠近物体的透明区域
/// </summary>
public bool IsOutline { get; set; }
/// <summary>
/// 是否需要获取一个点
/// </summary>
public bool IsAllowDot { get; set; }
/// <summary>
/// 获取图片上所有物体轮廓
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public async Task<SKPath[]> GetContourAsync(SKBitmap image, CancellationToken token = default)
{
using var imagePixMap = image.PeekPixels();
return await GetContourAsync(imagePixMap, token);
}
/// <summary>
/// 获取图片上所有物体轮廓
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public async Task<SKPath[]> GetContourAsync(SKImage image, CancellationToken token = default)
{
using var imagePixMap = image.PeekPixels();
return await GetContourAsync(imagePixMap, token);
}
/// <summary>
/// 获取图片上所有物体轮廓
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public Task<SKPath[]> GetContourAsync(SKPixmap pixMap, CancellationToken token = default)
{
return Task.Factory.StartNew(() => {
return GetContour(pixMap, token);
}, token);
}
/// <summary>
/// 获取所有物体的轮廓
/// </summary>
/// <param name="pixMap"></param>
/// <returns></returns>
public SKPath[] GetContour(SKPixmap pixMap, CancellationToken token = default)
{
var items = new List<SKPath>();
for (var i = 0; i < pixMap.Height; i++)
{
for (var j = 0; j < pixMap.Width; j++)
{
if (token.IsCancellationRequested)
{
return [..items];
}
if (IsTransparent(pixMap, j, i) || Contains(items, j, i))
{
continue;
}
var path = GetContour(pixMap, j, i);
if (path is null)
{
continue;
}
items.Add(path);
}
}
return [.. items];
}
/// <summary>
/// 根据坐标获取轮廓边界算法
/// </summary>
/// <param name="pixMap"></param>
/// <param name="beginX"></param>
/// <param name="beginY"></param>
/// <returns></returns>
public SKPath? GetContour(SKPixmap pixMap, int beginX, int beginY)
{
var path = new SKPath();
path.MoveTo(beginX, beginY - (IsOutline ? 1 : 0));
var directItems = new int[][] {
[0, -1], [1, -1],
[1, 0],
[1, 1], [0, 1], [-1, 1],
[-1, 0], [-1, -1]
};
var beginDirect = 0;
var isBegin = false;
var curX = beginX;
var curY = beginY;
while (!isBegin)
{
var i = 0;
var direct = beginDirect;
var hasPoint = false;
while (i++ <= directItems.Length)
{
var x = curX + directItems[direct][0];
var y = curY + directItems[direct][1];
if (IsTransparent(pixMap, x, y))
{
direct = (direct + 1) % directItems.Length;
if (IsOutline)
{
path.LineTo(x, y);
}
continue;
}
hasPoint = true;
curX = x;
curY = y;
if (curX == beginX && curY == beginY)
{
isBegin = true;
path.Close();
}
else if (!IsOutline)
{
path.LineTo(curX, curY);
}
beginDirect = (direct + 6) % directItems.Length;
break;
}
if (!hasPoint)
{
if (IsOutline)
{
path.Close();
return path;
}
// 所有方向都没有不透明点,就是一个孤点
return IsAllowDot ? path : null;
}
}
return path;
}
private static bool Contains(IEnumerable<SKPath> items, int x, int y)
{
foreach (var item in items)
{
if (item.Contains(x, y))
{
return true;
}
}
return false;
}
private static bool IsTransparent(SKPixmap pixMap, int x, int y)
{
if (x < 0 || y < 0 || x >= pixMap.Width || y >= pixMap.Height)
{
return true;
}
return pixMap.GetPixelColor(x, y).Alpha == 0;
}
}
2024-08-19 18:54:04
/// <summary>
/// 把像素字节数组转图片
/// </summary>
/// <param name="buffer">像素数组,例如: [r, g, b, a, r, g, b, a ...]</param>
/// <param name="width">图片的宽度,例如: 512</param>
/// <param name="height">图片的高度,例如: 1024</param>
/// <param name="format">指定像素数组的组成方式,例如:SKColorType.Rgba8888</param>
/// <returns></returns>
public static SKBitmap Decode(byte[] buffer, int width, int height, SKColorType format)
{
var data = SKData.CreateCopy(buffer);
var newInfo = new SKImageInfo(width, height, format);
var bitmap = new SKBitmap();
bitmap.InstallPixels(newInfo, data.Data);
return bitmap;
}
public static SKImage Decode(byte[] buffer, int width, int height, SKColorType format)
{
var newInfo = new SKImageInfo(width, height, format);
var data = SKData.CreateCopy(buffer);
return SKImage.FromPixels(newInfo, data);
}
SkiaSharp
默认支持 png
jpg
等文件格式,但是一些不支持的文件格式怎么显示呢?
例如:pvr
格式就不能直接解码。
SkiaSharp
支持,所有支持的颜色编码方式在 SKColorType
中SKColorType.Rgba8888
, 即:每个像素占四个字节,分别为 [Red,Green,Blue,Alpha],总字节为 宽*高*4
, 以逐行横行存储, (行*宽+列)*4
获取像素点的位置Decode(转换后的数据, 宽, 高, SKColorType.Rgba8888)
即可A: SkiaSharp 是线程安全的,两个线程不应访问同一个对象。SKBitmap 只能在UI主线程中操作,SKImage 则可以在所有子线程中操作
2024-08-04 18:43:01
NAS设备:绿联DXP4800 Plus
NAS系统:UGOS PRO
无法直接 DockerHub 可以使用 阿里云的镜像加速
搜索 gogs
下载
配置自动重启
配置文件保存位置
配置端口映射
访问网页进行GOGS配置
图片来源:https://www.cnblogs.com/yuexiaoyun/articles/11946103.html
图片来源:https://www.cnblogs.com/yuexiaoyun/articles/11946103.html
Q: nas重启后网址无法打开
A:可能是gogs安装时,端口配置错误,可以到gogs的文件保存位置下找到 gogs/conf/app.ini
文件修改 [server]HTTP_PORT
为 3000
即可
2024-08-04 18:40:38
使用USB连接电脑
在手机上选择“USB用于传输文件”
android/data
下的文件可能无法获取到并传输,如果再手机上把 android/data
复制到 Download
,可能无法复制目录中的文件例如使用 ES文件浏览器
需要在电脑中安装 adb
使用USB连接电脑
在手机上选择“USB用于传输文件”
再手机 设置
中打开 开发者模式
,开启 USB调试功能
电脑上打开终端命令行
# adb pull <手机中的文件路径> <保存在电脑的位置>
adb pull /storage/emulated/0/Android/data/com.xxx files
注意千万不要使用以下命令
这两种命令的原理就是压缩/storage/emulated/0/Android/data/com.xx
不保存直接输出终端,再保存终端输出的内容到 aaa.tar
文件,但是会导致文件出现0xFF 0xFE
和 很多 0x0
字节,导致解压缩软件无法读取
adb exec-out tar chf - -C /storage/emulated/0/Android/data/com.xx files > aaa.tar
adb shell 'tar -cf - /storage/emulated/0/Android/data/xx 2>/dev/null' > backup.tar.gz
可以使用先压缩到手机,再下载出来
# 压缩 /storage/emulated/0/Android/data/com.xx 到 /storage/emulated/0/Download/files.tar 文件中
adb exec-out tar chf /storage/emulated/0/Download/files.tar /storage/emulated/0/Android/data/com.xx
# 下载
adb pull /storage/emulated/0/Download/files.tar files.tar
-c: 建立压缩档案
-x:解压
-t:查看内容
-r:向压缩归档文件末尾追加文件
-u:更新原压缩包中的文件
-f: 文件
-h: 解除软链接
所以 tar chf <保存的文件> <要压缩的目录>
就是 tar -c <保存的文件> -h -f <要压缩的目录>
的意思
2024-06-14 04:34:40
将每个字归类为: 词首(B)、词中(M)、词尾(E)、单子词(S)
输入前一个字,输出后一个字;训练时就是将n个字符的内容 [0, n-1] 作为输入,将 [1, n] 做为预测值。
2024-05-07 18:54:50
以前使用 SiteServer CMS 6.8 在 Windows server 12 的服务器上部署了两个企业站,现在需要换到 Linux 服务器上。
SiteServer CMS 6.8 使用的是 Asp.net 不支持Linux 系统,所以需要升级到 SiteServer CMS 7
SiteServer CMS 7 使用的是 .NET Core 支持跨平台。
这里干脆升级到最新的 SiteServer CMS 7.30 (.NET 8)
Windows 服务器未过期或拥有Windows电脑并安装了 IIS + MySQL + Asp net core 运行时
SSCMS 的模板语法不需要变动;
主要是数据表的变动;
假设旧版本的数据已经在MySQL数据库中
从 官网 直接下最新的 windows 版本即可
解压放到一个文件里,例如 D:/sscms
根据 “SSCMS老版本升级” 升级文档进行操作即可
新建一个文件 D:/sscms/old.json
{
"Database": {
"Type": "MySql",
"ConnectionString": "Server=127.0.0.1;Uid=root;Pwd=root;Database=sqldb_old;SslMode=none;CharSet=utf8"
}
}
在 D:/sscms
文件夹中打开终端 PowerShell
,运行命令更新数据
.\sscms data backup -d backup -c old.json
.\sscms data update -d backup
新建一个文件 D:/sscms/sscms.json
,
注意:sqldb_new
数据库必须为空
{
"Database": {
"Type": "MySql",
"ConnectionString": "Server=127.0.0.1;Uid=root;Pwd=root;Database=sqldb_new;SslMode=none;CharSet=utf8"
}
}
运行命令恢复数据
sscms data restore -d update
完成数据恢复后,需要在浏览器中进入 http://<域名>/ss-admin/syncDatabase/
数据库升级界面,点击升级按钮,完成数据库升级。
注意: D:/sscms/sscms.json
需要增加 SecurityKey
字段,不然后台登录验证码无法显示
{
"IsProtectData": false,
"IsSafeMode": false,
"SecurityKey": "2cf8fcc7150b6f839784231b8b959217cc0840f20623813b",
"Database": {
"Type": "MySql",
"ConnectionString": "Server=127.0.0.1;Uid=root;Pwd=root;Database=sqldb_new;SslMode=none;CharSet=utf8"
},
"Redis": {
"ConnectionString": ""
},
"IsDisablePlugins": false,
"AdminRestriction": {
"Host": "",
"AllowList": [],
"BlockList": []
},
"Cors": {
"IsOrigins": false,
"Origins": []
}
}
D:/sscms/sscms.json
需要增加 SecurityKey
字段,具体值需要新安装一个SSCMS系统(删除D:/sscms/sscms.json
文件即可),复制新的 sscms.json
文件更改 Database.ConnectionString
值即可
新安装一个SSCMS系统(删除D:/sscms/sscms.json
文件即可),设置管理员密码,然后到数据库中 找到表 siteserver_administrator
复制 Password
、 PasswordSalt
两个字段值即可。
需要手动复制新系统的数据表结构。因为SSCMS版本变动表结构也发生了变动。
需要修改数据表 siteserver_site
的字段 SiteType
值为 web
需要到后台的栏目管理
->编辑栏目
手动勾选 栏目组
导航
即可
需要到后台的显示管理
-> 包含文件管理
添加即可
这里使用的是阿里云ECS服务器
使用命令 lsb_release -a
查询的系统信息为
LSB Version: :core-4.1-amd64:core-4.1-noarch
Distributor ID: AlibabaCloud
Description: Alibaba Cloud Linux release 3 (Soaring Falcon)
Release: 3
Codename: SoaringFalcon
所以安装 netcore 的方法参考:在RHEL和CentOS Stream中运行SSCMS
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
sudo dnf install aspnetcore-runtime-8.0
# 验证dotnet core runtime是否安装成功
dotnet --info
假设已安装过 Nginx
nginx 配置
server {
listen 80;
server_name a.com;
root /data/a; # 设置站点根目录
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
}
a 站点的 /data/a/sscms.json
{
"IsProtectData": false,
"IsSafeMode": false,
"SecurityKey": "2cf8fcc7150b6f839784231b8b959217cc0840f20623813b",
"Database": {
"Type": "MySql",
"ConnectionString": "Server=127.0.0.1;Uid=root;Pwd=root;Database=sqldb_a;SslMode=none;CharSet=utf8"
},
"Redis": {
"ConnectionString": ""
},
"IsDisablePlugins": false,
"AdminRestriction": {
"Host": "",
"AllowList": [],
"BlockList": []
},
"Cors": {
"IsOrigins": false,
"Origins": []
}
}
创建 a 站点的服务文件 /etc/systemd/system/a.service
[Unit]
Description=a
[Service]
WorkingDirectory=/data/a
ExecStart=/usr/bin/dotnet /data/a/SSCMS.Web.dll
Restart=always
# Restart service after 10 seconds if the sscms service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=sscms
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
nginx 配置
server {
listen 80;
server_name b.com;
root /data/b; # 设置站点根目录
location / {
proxy_pass http://localhost:5001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
}
b 站点的 /data/b/sscms.json
{
"Urls": "http://localhost:5001",
"IsProtectData": false,
"IsSafeMode": false,
"SecurityKey": "2cf8fcc7150b6f839784231b8b959217cc0840f20623813b",
"Database": {
"Type": "MySql",
"ConnectionString": "Server=127.0.0.1;Uid=root;Pwd=root;Database=sqldb_b;SslMode=none;CharSet=utf8"
},
"Redis": {
"ConnectionString": ""
},
"IsDisablePlugins": false,
"AdminRestriction": {
"Host": "",
"AllowList": [],
"BlockList": []
},
"Cors": {
"IsOrigins": false,
"Origins": []
}
}
创建 b 站点的服务文件 /etc/systemd/system/b.service
[Unit]
Description=b
[Service]
WorkingDirectory=/data/b
ExecStart=/usr/bin/dotnet /data/b/SSCMS.Web.dll
Restart=always
# Restart service after 10 seconds if the sscms service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=sscms
User=root
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
sudo systemctl enable a.service
sudo systemctl start a.service
sudo systemctl status a.service # 验证服务是否启动
没有报错即配置正确,
b站点服务同理
这里需要注意
在 Windows 中数据表表名都是小写,但是在Linux 环境下是区分大小写的,所以需要手动更改 sql
文件中的数据库表名,再导入
例如 siteserver_administratorsinroles
需要改为 siteserver_AdministratorsInRoles
具体对应表需要重新再 linux 下安装即可
升级过程还是比较繁琐的,需要有耐心。