Compare commits

...

86 Commits

Author SHA1 Message Date
zsyg
70534c06db 修改版本号 2025-07-28 13:02:03 +08:00
zsyg
9e11e66e03 添加应用卡片图标 2025-07-27 11:26:01 +08:00
zsyg
4b8283574a 添加应用卡片 2025-07-27 11:23:50 +08:00
zsyg
de48557786 Update README.md 2025-07-27 08:24:46 +08:00
zsyg
aa739e8d9e Update README.md 2025-07-27 08:23:35 +08:00
zsyg
924684918c Update README.md 2025-07-27 08:22:23 +08:00
zsyg
76bb4d1b50 完善下载机制 2025-07-27 08:16:32 +08:00
zsyg
94fafdb3ed 2025-07-26 16:07:43 +08:00
zsyg
b09175550e 添加luanti软件图标 2025-07-26 08:22:29 +08:00
zsyg
c3b5e3fe66 修改版本号 2025-07-26 08:21:30 +08:00
zsyg
1cad6573e2 添加应用卡片 2025-07-26 08:20:50 +08:00
zsyg
d01b7a4b5a 修改版本号 2025-07-24 08:09:15 +08:00
zsyg
7d393aa817 添加更多应用卡片 2025-07-24 08:08:43 +08:00
zsyg
f28ec55eaf 修改协议漏洞
zsyg改zs-yg
2025-07-23 19:14:15 +08:00
zsyg
cbf4a2bc2d 修改版本号 2025-07-23 08:20:30 +08:00
zsyg
9269032315 修改freemove描述 2025-07-22 17:28:56 +08:00
zsyg
3c6117933c 修改描述 2025-07-22 15:23:29 +08:00
zsyg
59c6ae623e Add files via upload 2025-07-22 13:59:26 +08:00
zsyg
6ff1506bc2 Add files via upload 2025-07-22 13:57:52 +08:00
zsyg
b8b8b03713 修改cmake配置 2025-07-21 20:54:14 +08:00
zsyg
104aba01da Add files via upload 2025-07-20 13:25:35 +08:00
zsyg
a93e4d67f4 Add files via upload 2025-07-20 13:24:20 +08:00
zsyg
d1c62f4488 Add files via upload 2025-07-20 13:22:11 +08:00
zsyg
f4f4d86faa Add files via upload 2025-07-20 13:21:19 +08:00
zsyg
4c13fe0008 修改版本号 2025-07-20 13:16:24 +08:00
zsyg
6a931e9a85 添加部分软件注释 2025-07-20 10:34:37 +08:00
zsyg
916c944a90 Update README.md 2025-07-20 09:08:15 +08:00
zsyg
996d73f9fe 提供部分软件描述 2025-07-20 08:58:28 +08:00
zsyg
d4afc5a5e7 修改版本号 2025-07-19 20:17:29 +08:00
zsyg
a445bbdc2d 提供avif格式转换 2025-07-19 20:13:18 +08:00
zsyg
0e90195f9a 提供更多文本转换模式 2025-07-19 20:13:01 +08:00
zsyg
11df47ff2e 改为cmake构建 2025-07-17 12:03:29 +08:00
zsyg
7d87d9be7e 添加更多格式 2025-07-14 14:05:13 +08:00
zsyg
5530c6413d 修改版本号 2025-07-14 14:01:31 +08:00
zsyg
b79db2e6bd 添加更多格式 2025-07-14 13:59:37 +08:00
zsyg
6056c984c0 改为静态编译 2025-07-14 11:10:15 +08:00
zsyg
2395c13b60 改为静态编译 2025-07-14 11:09:42 +08:00
zsyg
6624cee1a3 添加软件图标 2025-07-11 16:10:24 +08:00
zsyg
165703575b 修改版本号 2025-07-11 16:08:47 +08:00
zsyg
efc1498a25 添加应用卡片 2025-07-11 16:07:43 +08:00
zsyg
481fc24735 修改版本号 2025-07-11 08:17:57 +08:00
zsyg
bebd804b7a 美化ui 2025-07-11 08:17:26 +08:00
zsyg
4202013265 添加依赖 2025-07-11 08:16:11 +08:00
zsyg
d26ac95dd5 添加图片转换器代码 2025-07-10 13:21:27 +08:00
zsyg
0432c5fa42 添加图片转换器工具图标 2025-07-10 13:21:03 +08:00
zsyg
94da204ca9 提交同转换器程序 2025-07-10 13:20:34 +08:00
zsyg
9770c58166 添加应用卡片 2025-07-10 13:19:02 +08:00
zsyg
c006f78693 修改版本号 2025-07-10 13:18:22 +08:00
zsyg
ab6080cdd0 修改版本号 2025-07-09 12:53:17 +08:00
zsyg
4b77884d32 增强调试信息 2025-07-09 11:36:12 +08:00
zsyg
d45e3029b7 支持显示图标 2025-07-09 11:35:36 +08:00
zsyg
41b056c074 支持显示图标 2025-07-09 11:35:08 +08:00
zsyg
6955655e64 支持显示图标 2025-07-09 11:34:21 +08:00
zsyg
4310557659 添加图标 2025-07-08 21:19:34 +08:00
zsyg
510362688a 添加Code::Blocks 2025-07-08 21:19:02 +08:00
zsyg
34962bba3f 添加Dev-cpp 2025-07-08 21:16:09 +08:00
zsyg
0bab6ccaab 添加构建工具 2025-07-08 21:08:34 +08:00
zsyg
973d984c55 废弃的零宽字符隐藏器
2025-07-07 20:37:34 +08:00
zsyg
280a9122b9 废弃的聊天室代码
😭😭😭
2025-07-07 20:34:34 +08:00
zsyg
837aba38ba Add files via upload 2025-07-07 19:15:34 +08:00
zsyg
92c2a57773 添加应用卡片 2025-07-07 19:14:20 +08:00
zsyg
43027d7953 Add files via upload 2025-07-07 18:07:29 +08:00
zsyg
6d2711da08 删除艺术字 2025-07-07 17:52:13 +08:00
zsyg
e47f905a8c Add files via upload 2025-07-07 16:59:18 +08:00
zsyg
6899e4767f 添加文本转换器程序 2025-07-07 16:53:44 +08:00
zsyg
d5a0564847 添加文本转换器代码 2025-07-07 16:52:56 +08:00
zsyg
525c823397 添加应用图标 2025-07-06 13:47:54 +08:00
zsyg
7db2d8813e Add files via upload 2025-07-06 13:47:04 +08:00
zsyg
7216f62cef 添加OCR代码
这是一个废弃代码
2025-07-06 12:51:43 +08:00
zsyg
a777991b8c 添加ClamAV图标 2025-07-05 19:34:02 +08:00
zsyg
e2c6c52b32 Add files via upload 2025-07-05 19:33:25 +08:00
zsyg
33089c39b6 Update features.html 2025-07-05 19:15:03 +08:00
zsyg
45805178cc 修改版本号 2025-07-05 19:09:08 +08:00
zsyg
08a11f025a 修复bug和扩展功能 2025-07-05 19:08:44 +08:00
zsyg
5bb3886bc5 添加乌班图的图标 2025-07-05 17:58:10 +08:00
zsyg
ce5f964776 添加应用卡片 2025-07-05 17:57:27 +08:00
zsyg
f52c7908d7 添加应用卡片图标 2025-07-05 17:32:23 +08:00
zsyg
abcbf06493 添加应用卡片图标 2025-07-05 17:32:04 +08:00
zsyg
f56bcb3627 添加应用卡片图标 2025-07-05 17:31:40 +08:00
zsyg
f789c7904a 修改版本号 2025-07-05 17:30:57 +08:00
zsyg
e04709637c 修改版本号 2025-07-05 17:30:38 +08:00
zsyg
e39f976607 添加更多应用卡片 2025-07-05 17:30:18 +08:00
zsyg
0d9ec0ad44 修改版本号 2025-07-05 16:44:38 +08:00
zsyg
122ada92d9 修改版本号 2025-07-05 16:44:11 +08:00
zsyg
d571729c89 修改版本号 2025-07-05 16:43:38 +08:00
zsyg
351e1e97c3 修改布局 2025-07-05 16:43:14 +08:00
232 changed files with 9526 additions and 2620 deletions

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
@@ -57,7 +51,7 @@ namespace AppStore
// 初始化并添加应用信息 // 初始化并添加应用信息
infoLabel = new Label(); infoLabel = new Label();
infoLabel.Text = "kortapp-z\n版本: 1.1.9\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件"; infoLabel.Text = "kortapp-z\n版本: 1.3.7\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
infoLabel.Font = new Font("Microsoft YaHei", 12); infoLabel.Font = new Font("Microsoft YaHei", 12);
infoLabel.AutoSize = false; infoLabel.AutoSize = false;
infoLabel.Width = 300; infoLabel.Width = 300;
@@ -131,7 +125,7 @@ namespace AppStore
} }
} }
// 保留原AboutForm作为容器(可选) // 保留原AboutForm作为容器
public class AboutForm : Form public class AboutForm : Form
{ {
public AboutForm() public AboutForm()

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
@@ -21,6 +15,7 @@ namespace AppStore
private Label nameLabel; private Label nameLabel;
private Panel namePanel; private Panel namePanel;
private Button downloadBtn; private Button downloadBtn;
private ToolTip? toolTip;
private Color borderColor = SystemColors.ControlDark; private Color borderColor = SystemColors.ControlDark;
private static readonly ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath> PathCache = private static readonly ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath> PathCache =
new ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath>(); new ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath>();
@@ -28,6 +23,7 @@ namespace AppStore
public string AppName { get; set; } = string.Empty; public string AppName { get; set; } = string.Empty;
public Image AppIcon { get; set; } = SystemIcons.Application.ToBitmap(); public Image AppIcon { get; set; } = SystemIcons.Application.ToBitmap();
public string DownloadUrl { get; set; } = string.Empty; public string DownloadUrl { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public bool ShowDownloadButton { get; set; } = true; public bool ShowDownloadButton { get; set; } = true;
public AppCard() public AppCard()
@@ -54,9 +50,23 @@ namespace AppStore
this.Padding = new Padding(10); this.Padding = new Padding(10);
// 异步初始化卡片路径和边框 // 异步初始化卡片路径和边框
// 预加载边框路径
Task.Run(() => { Task.Run(() => {
InitializeCardPath(); InitializeCardPath();
InitializeBorder(); InitializeBorder();
// 确保在主线程注册事件
this.Invoke((MethodInvoker)(() => {
this.Paint += (sender, e) => {
if (BorderCache.IsEmpty)
{
Task.Run(() => {
InitializeBorder();
this.Invoke((MethodInvoker)(() => this.Invalidate()));
});
}
};
}));
}); });
// 应用图标 - 添加null检查 // 应用图标 - 添加null检查
@@ -118,6 +128,13 @@ namespace AppStore
this.Controls.Add(namePanel); this.Controls.Add(namePanel);
} }
// 初始化ToolTip控件
toolTip = new ToolTip();
toolTip.AutoPopDelay = 5000;
toolTip.InitialDelay = 500;
toolTip.ReshowDelay = 500;
toolTip.ShowAlways = true;
// 下载按钮 - 添加null检查 // 下载按钮 - 添加null检查
if (downloadBtn != null) if (downloadBtn != null)
{ {
@@ -136,6 +153,10 @@ namespace AppStore
if (downloadBtn != null) if (downloadBtn != null)
{ {
downloadBtn.BackColor = Color.FromArgb(0, 150, 255); downloadBtn.BackColor = Color.FromArgb(0, 150, 255);
if (!string.IsNullOrEmpty(Description))
{
toolTip.SetToolTip(downloadBtn, Description);
}
} }
}; };
@@ -187,8 +208,12 @@ namespace AppStore
// 使用卡片尺寸作为缓存键 // 使用卡片尺寸作为缓存键
string cacheKey = $"{Width}_{Height}_10"; string cacheKey = $"{Width}_{Height}_10";
// 检查缓存中是否已有路径 // 双重检查锁模式确保线程安全
if (!BorderCache.TryGetValue(cacheKey, out var borderPath)) if (!BorderCache.TryGetValue(cacheKey, out var borderPath))
{
lock (BorderCache)
{
if (!BorderCache.TryGetValue(cacheKey, out borderPath))
{ {
// 创建临时文件存储路径数据 // 创建临时文件存储路径数据
string tempFile = Path.GetTempFileName(); string tempFile = Path.GetTempFileName();
@@ -237,12 +262,20 @@ namespace AppStore
} }
} }
} }
}
}
// 边框和阴影效果 // 边框和阴影效果
protected override void OnPaint(PaintEventArgs e) protected override void OnPaint(PaintEventArgs e)
{ {
base.OnPaint(e); base.OnPaint(e);
// 确保边框已初始化
if (BorderCache.IsEmpty)
{
InitializeBorder();
}
// 绘制背景 // 绘制背景
using (var brush = new SolidBrush(this.BackColor)) { using (var brush = new SolidBrush(this.BackColor)) {
e.Graphics.FillRectangle(brush, this.ClientRectangle); e.Graphics.FillRectangle(brush, this.ClientRectangle);
@@ -353,7 +386,7 @@ namespace AppStore
try try
{ {
var safePath = path ?? CalculatePathFallback(Width, Height, 10); var safePath = path ?? CalculatePathFallback(Width, Height, 10);
// 更严格的null检查包括路径和控件状态 // 更严格的null检查,包括路径和控件状态
if (safePath != null && if (safePath != null &&
safePath.PointCount > 0 && safePath.PointCount > 0 &&
this.IsHandleCreated && this.IsHandleCreated &&
@@ -430,7 +463,7 @@ namespace AppStore
try try
{ {
// 更严格的null检查 // 更严格的null检查
// 更严格的null检查包括DownloadManager.Instance和其方法 // 更严格的null检查,包括DownloadManager.Instance和其方法
// 全面的null和状态检查 // 全面的null和状态检查
var downloadManager = DownloadManager.Instance; var downloadManager = DownloadManager.Instance;
if (sender == null || e == null || if (sender == null || e == null ||

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

View File

@@ -35,6 +35,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SunnyUI" Version="3.8.6" />
<PackageReference Include="ZXing.Net" Version="0.16.9" /> <PackageReference Include="ZXing.Net" Version="0.16.9" />
</ItemGroup> </ItemGroup>

View File

@@ -1,10 +1,5 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
@@ -20,6 +15,7 @@ namespace AppStore
public string FileName { get; set; } = string.Empty; public string FileName { get; set; } = string.Empty;
public int Progress { get; set; } public int Progress { get; set; }
public string Status { get; set; } = string.Empty; public string Status { get; set; } = string.Empty;
public Process? DownloadProcess { get; set; }
public DownloadItem() public DownloadItem()
{ {
@@ -59,10 +55,11 @@ namespace AppStore
this.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light this.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
? Color.White ? Color.White
: Color.Black; : Color.Black;
this.BorderStyle = BorderStyle.FixedSingle; this.BorderStyle = BorderStyle.None; // 禁用默认边框
this.ForeColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light this.ForeColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
? Color.Black ? Color.Black
: Color.White; : Color.White;
this.Paint += DownloadItem_Paint; // 添加自定义绘制
// 文件名标签 // 文件名标签
nameLabel = new Label(); nameLabel = new Label();
@@ -104,6 +101,17 @@ namespace AppStore
nameLabel.Text = FileName; nameLabel.Text = FileName;
progressBar.Value = Progress; progressBar.Value = Progress;
statusLabel.Text = Status; statusLabel.Text = Status;
this.Invalidate(); // 触发重绘
}
private void DownloadItem_Paint(object sender, PaintEventArgs e)
{
// 自定义边框绘制
using (var pen = new Pen(ThemeManager.BorderColor, 1))
{
e.Graphics.DrawRectangle(pen,
new Rectangle(0, 0, this.Width - 1, this.Height - 1));
}
} }
private void CancelBtn_Click(object sender, EventArgs e) private void CancelBtn_Click(object sender, EventArgs e)
@@ -117,9 +125,26 @@ namespace AppStore
try try
{ {
// 1. 先取消下载
DownloadManager.Instance.CancelDownload(this); DownloadManager.Instance.CancelDownload(this);
// 2. 更新状态为已取消
Status = "已取消"; Status = "已取消";
UpdateDisplay(); UpdateDisplay();
// 3. 延迟100ms后移除控件确保UI更新完成
var timer = new System.Windows.Forms.Timer { Interval = 100 };
timer.Tick += (s, args) =>
{
timer.Stop();
timer.Dispose();
if (this.Parent != null)
{
this.Parent.Controls.Remove(this);
this.Dispose();
}
};
timer.Start();
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -30,7 +24,6 @@ namespace AppStore
private static DownloadManager instance = null!; private static DownloadManager instance = null!;
public static DownloadManager Instance => instance ??= new DownloadManager(); public static DownloadManager Instance => instance ??= new DownloadManager();
private Process? currentProcess;
public List<DownloadItem> DownloadItems { get; } = new List<DownloadItem>(); public List<DownloadItem> DownloadItems { get; } = new List<DownloadItem>();
public event Action<DownloadItem> DownloadAdded = delegate { }; public event Action<DownloadItem> DownloadAdded = delegate { };
@@ -65,7 +58,7 @@ namespace AppStore
} }
catch catch
{ {
// 忽略所有异常使用默认值 // 忽略所有异常,使用默认值
} }
return result; return result;
@@ -84,6 +77,8 @@ namespace AppStore
Status = "准备下载" Status = "准备下载"
}; };
// 创建进程并关联到下载项
downloadItem.DownloadProcess = new Process();
DownloadItems.Add(downloadItem); DownloadItems.Add(downloadItem);
DownloadAdded?.Invoke(downloadItem); DownloadAdded?.Invoke(downloadItem);
@@ -121,7 +116,7 @@ namespace AppStore
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Downloads"); "Downloads");
Logger.LogError($"下载路径{downloadsDir}不可用将使用默认路径: {defaultPath}", ex); Logger.LogError($"下载路径{downloadsDir}不可用,将使用默认路径: {defaultPath}", ex);
downloadsDir = defaultPath; downloadsDir = defaultPath;
Directory.CreateDirectory(downloadsDir); Directory.CreateDirectory(downloadsDir);
} }
@@ -143,9 +138,7 @@ namespace AppStore
var arguments = $"--out=\"{originalFileName}\" --dir=\"{downloadsDir}\" --split=16 --max-connection-per-server=16 {url}"; var arguments = $"--out=\"{originalFileName}\" --dir=\"{downloadsDir}\" --split=16 --max-connection-per-server=16 {url}";
currentProcess = new Process downloadItem.DownloadProcess.StartInfo = new ProcessStartInfo
{
StartInfo = new ProcessStartInfo
{ {
FileName = aria2cPath, FileName = aria2cPath,
Arguments = arguments, Arguments = arguments,
@@ -154,7 +147,6 @@ namespace AppStore
CreateNoWindow = true, CreateNoWindow = true,
RedirectStandardOutput = true, RedirectStandardOutput = true,
RedirectStandardError = true RedirectStandardError = true
}
}; };
// 获取目标文件路径 // 获取目标文件路径
@@ -176,7 +168,7 @@ namespace AppStore
} }
}; };
currentProcess.OutputDataReceived += (sender, e) => downloadItem.DownloadProcess.OutputDataReceived += (sender, e) =>
{ {
if (!string.IsNullOrEmpty(e.Data)) if (!string.IsNullOrEmpty(e.Data))
{ {
@@ -217,7 +209,7 @@ namespace AppStore
} }
}; };
currentProcess.ErrorDataReceived += (sender, e) => downloadItem.DownloadProcess.ErrorDataReceived += (sender, e) =>
{ {
if (!string.IsNullOrEmpty(e.Data)) if (!string.IsNullOrEmpty(e.Data))
{ {
@@ -227,9 +219,9 @@ namespace AppStore
} }
}; };
currentProcess.Exited += (sender, e) => downloadItem.DownloadProcess.Exited += (sender, e) =>
{ {
var process = currentProcess; var process = downloadItem.DownloadProcess;
if (process == null) return; if (process == null) return;
var result = GetProcessResult(process); var result = GetProcessResult(process);
@@ -298,10 +290,8 @@ namespace AppStore
} }
finally finally
{ {
if (process != null) // 清理资源
{ downloadItem.DownloadProcess = null;
currentProcess = null;
}
} }
// 强制更新显示 // 强制更新显示
@@ -310,13 +300,13 @@ namespace AppStore
if (!currentProcess.Start()) if (!downloadItem.DownloadProcess.Start())
{ {
throw new Exception("进程启动失败"); throw new Exception("进程启动失败");
} }
currentProcess.BeginOutputReadLine(); downloadItem.DownloadProcess.BeginOutputReadLine();
currentProcess.BeginErrorReadLine(); downloadItem.DownloadProcess.BeginErrorReadLine();
progressTimer.Start(); progressTimer.Start();
} }
catch (Exception ex) catch (Exception ex)
@@ -339,7 +329,7 @@ namespace AppStore
{ {
try try
{ {
var process = currentProcess; var process = item.DownloadProcess;
if (process?.StartInfo == null || process.HasExited) if (process?.StartInfo == null || process.HasExited)
{ {
item.Status = "已取消"; item.Status = "已取消";
@@ -349,7 +339,7 @@ namespace AppStore
process.Kill(); process.Kill();
process.Dispose(); process.Dispose();
currentProcess = null; item.DownloadProcess = null;
item.Status = "已取消"; item.Status = "已取消";
DownloadProgressChanged?.Invoke(item); DownloadProgressChanged?.Invoke(item);

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2025 zsyg Copyright (c) 2025 zs-yg
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;

View File

@@ -1,20 +1,20 @@
# Kortapp-z - Windows应用商店 --主张软件开源、免费拒绝广告 # Kortapp-z - Windows应用商店 --主张软件开源、免费,拒绝广告
小立一个flag从不接受广告不停更新 小立一个flag从不接受广告,不停更新
## 项目开源行为 ## 项目开源行为
1. 项目代码开源允许任何人使用、修改、分发、商用但必须注明原作者。 1. 项目代码开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
2. 项目图标、截图等资源开源允许任何人使用、修改、分发、商用但必须注明原作者。 2. 项目图标、截图等资源开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
3. 项目的任何衍生品包括但不限于网站、APP、插件等必须遵循以上开源协议。 3. 项目的任何衍生品包括但不限于网站、APP、插件等必须遵循以上开源协议。
4. 项目不接受任何形式的广告不得在任何地方投放广告。 4. 项目不接受任何形式的广告,不得在任何地方投放广告。
5. 项目不接受任何形式的捐赠、赞助 5. 项目不接受任何形式的捐赠、赞助
6. 项目可以进行PR欢迎任何形式的PR不提交issue也可以 6. 项目可以进行PR,欢迎任何形式的PR,不提交issue也可以
7. 本项目可以PR一些你自己的项目如果star数量不到1k都会被删除 7. 本项目可以PR一些你自己的项目,如果star数量不到1k,都会被删除
## 项目简介 ## 项目简介
一个简单的Windows应用商店应用提供软件下载和管理功能。 一个简单的Windows应用商店应用,提供软件下载和管理功能。
提供软件管理、下载管理、内置工具使用等功能 提供软件管理、下载管理、内置工具使用等功能
## 功能特点 ## 功能特点
@@ -44,7 +44,7 @@ dotnet publish AppStore.csproj -c Release -r win-x86 --self-contained false /p:O
dotnet publish AppStore.csproj -c Release -r win-x64 --self-contained false /p:Optimize=true /p:DebugType=None dotnet publish AppStore.csproj -c Release -r win-x64 --self-contained false /p:Optimize=true /p:DebugType=None
``` ```
打包后的可执行文件将包含指定的应用程序图标输出路径为: 打包后的可执行文件将包含指定的应用程序图标,输出路径为:
``` ```
bin\Release\net8.0-windows\[platform]\publish bin\Release\net8.0-windows\[platform]\publish
``` ```
@@ -83,13 +83,15 @@ Copyright (c) 2025 zsyg
## 其他网站 ## 其他网站
gitee镜像仓库:https://gitee.com/chr_super/kortapp-z (目前已经停止维护) gitee镜像仓库:https://gitee.com/chr_super/kortapp-z (目前已经停止维护,仅镜像代码)
sourceforge镜像仓库:https://sourceforge.net/projects/kortapp-z/ 提供releases镜像
## 维护 ## 维护
由于gitee我没怎么用而且操作麻烦gitee镜像将不会继续同步有懂得人可以帮我搞下镜像吗qq 3872006562也可以b站直接私信我会在readme中鸣谢的谢谢各位 由于gitee我没怎么用,而且操作麻烦,gitee镜像将不会继续同步,有懂得人可以帮我搞下镜像吗,qq 3872006562,也可以b站直接私信,我会在readme中鸣谢的,谢谢各位
由于和Daye发生了矛盾所以windowscleaner将永远不上架我要自己努力 由于和Daye发生了矛盾,所以windowscleaner将永远不上架,我要自己努力
提示由于github上传文件的限制img/png/NET.png请改名为.NET.png否则程序可能出现无法预料的问题 提示由于github上传文件的限制,img/png/NET.png,请改名为.NET.png,否则程序可能出现无法预料的问题
每一个人都可以通过PR添加属于自己的合法软件 每一个人都可以通过PR添加属于自己的合法软件

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@@ -211,7 +205,7 @@ namespace AppStore
var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString); var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString);
string customPath = jsonData.GetProperty("DownloadPath").GetString() ?? ""; string customPath = jsonData.GetProperty("DownloadPath").GetString() ?? "";
// 如果自定义路径有效则显示否则显示默认路径 // 如果自定义路径有效则显示,否则显示默认路径
txtBox.Text = !string.IsNullOrWhiteSpace(customPath) ? customPath : defaultPath; txtBox.Text = !string.IsNullOrWhiteSpace(customPath) ? customPath : defaultPath;
} }
else else

View File

@@ -1,4 +1,4 @@
首先如果希望编译程序那么必须安装.NET8.0 SDK 首先,如果希望编译程序,那么必须安装.NET8.0 SDK
下载链接https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer 下载链接https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer
使用一下指令编译 使用一下指令编译

View File

@@ -1,4 +1,4 @@
如果希望运行那么必须安装.NET8.0 SDK 如果希望运行,那么必须安装.NET8.0 SDK
下载链接https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer 下载链接https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
@@ -38,7 +32,7 @@ namespace AppStore
} }
catch catch
{ {
// 忽略错误使用默认主题 // 忽略错误,使用默认主题
} }
return ThemeMode.Light; return ThemeMode.Light;
} }
@@ -64,18 +58,26 @@ namespace AppStore
} }
// 浅色主题颜色 // 浅色主题颜色
private static readonly Color LightBackground = Color.FromArgb(255, 255, 255); private static readonly Color LightBackground = Color.FromArgb(250, 250, 250);
private static readonly Color LightControlBackground = Color.FromArgb(240, 240, 240); private static readonly Color LightControlBackground = Color.FromArgb(245, 245, 245);
private static readonly Color LightText = Color.FromArgb(30, 30, 30); private static readonly Color LightText = Color.FromArgb(40, 40, 40);
private static readonly Color LightButtonHover = Color.FromArgb(230, 230, 230); private static readonly Color LightButtonHover = Color.FromArgb(235, 235, 235);
private static readonly Color LightButtonActive = Color.FromArgb(220, 220, 220); private static readonly Color LightButtonActive = Color.FromArgb(225, 225, 225);
private static readonly Color LightAccent = Color.FromArgb(0, 120, 215);
private static readonly Color LightAccentLight = Color.FromArgb(0, 150, 245);
// 深色主题颜色 // 深色主题颜色
private static readonly Color DarkBackground = Color.FromArgb(30, 30, 30); private static readonly Color DarkBackground = Color.FromArgb(25, 25, 25);
private static readonly Color DarkControlBackground = Color.FromArgb(45, 45, 45); private static readonly Color DarkControlBackground = Color.FromArgb(40, 40, 40);
private static readonly Color DarkText = Color.FromArgb(240, 240, 240); private static readonly Color DarkText = Color.FromArgb(245, 245, 245);
private static readonly Color DarkButtonHover = Color.FromArgb(60, 60, 60); private static readonly Color DarkButtonHover = Color.FromArgb(55, 55, 55);
private static readonly Color DarkButtonActive = Color.FromArgb(70, 70, 70); private static readonly Color DarkButtonActive = Color.FromArgb(65, 65, 65);
private static readonly Color DarkBorder = Color.FromArgb(70, 70, 70);
private static readonly Color DarkAccent = Color.FromArgb(0, 150, 245);
private static readonly Color DarkAccentLight = Color.FromArgb(0, 180, 255);
// 浅色主题边框颜色
private static readonly Color LightBorder = Color.FromArgb(200, 200, 200);
public static event Action<ThemeMode> ThemeChanged = delegate {}; public static event Action<ThemeMode> ThemeChanged = delegate {};
@@ -108,6 +110,19 @@ namespace AppStore
public static Color ButtonActiveColor => public static Color ButtonActiveColor =>
_currentTheme == ThemeMode.Light ? LightButtonActive : DarkButtonActive; _currentTheme == ThemeMode.Light ? LightButtonActive : DarkButtonActive;
public static Color BorderColor =>
_currentTheme == ThemeMode.Light ? LightBorder : DarkBorder;
public static Color AccentColor =>
_currentTheme == ThemeMode.Light ? LightAccent : DarkAccent;
public static Color AccentLightColor =>
_currentTheme == ThemeMode.Light ? LightAccentLight : DarkAccentLight;
public static int ControlRadius => 8;
public static int FormRadius => 12;
public static void ApplyTheme(Control control) public static void ApplyTheme(Control control)
{ {
ApplyThemeToControl(control); ApplyThemeToControl(control);
@@ -124,6 +139,9 @@ namespace AppStore
button.FlatAppearance.BorderSize = 0; button.FlatAppearance.BorderSize = 0;
button.FlatAppearance.MouseOverBackColor = ButtonHoverColor; button.FlatAppearance.MouseOverBackColor = ButtonHoverColor;
button.FlatAppearance.MouseDownBackColor = ButtonActiveColor; button.FlatAppearance.MouseDownBackColor = ButtonActiveColor;
button.BackColor = ControlBackgroundColor;
button.Font = new Font(button.Font, FontStyle.Bold);
button.Padding = new Padding(10, 5, 10, 5);
} }
foreach (Control childControl in control.Controls) foreach (Control childControl in control.Controls)

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
#include <windows.h> #include <windows.h>
#include <vector> #include <vector>
#include <fstream> #include <fstream>

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <vector> #include <vector>

View File

@@ -15,13 +15,13 @@
<main> <main>
<section class="about-project"> <section class="about-project">
<h2>项目简介</h2> <h2>项目简介</h2>
<p>kortapp-z是一个专为Windows系统设计的实用工具集合旨在提供一站式的系统优化和管理解决方案。</p> <p>kortapp-z是一个专为Windows系统设计的实用工具集合,旨在提供一站式的系统优化和管理解决方案。</p>
<p>项目始于2025年由热爱效率工具的开发者创建。</p> <p>项目始于2025年,由热爱效率工具的开发者创建。</p>
</section> </section>
<section class="team"> <section class="team">
<h2>开发团队</h2> <h2>开发团队</h2>
<p>我们的团队由经验丰富的开发人员组成专注于创建高质量的系统工具。</p> <p>我们的团队由经验丰富的开发人员组成,专注于创建高质量的系统工具。</p>
<ul> <ul>
<li>核心开发者: 1人</li> <li>核心开发者: 1人</li>
<li>UI设计师: 1人</li> <li>UI设计师: 1人</li>
@@ -31,7 +31,7 @@
<section class="contact"> <section class="contact">
<h2>联系我们</h2> <h2>联系我们</h2>
<p>如有任何问题或建议欢迎通过GitHub提交issue或pull request。</p> <p>如有任何问题或建议,欢迎通过GitHub提交issue或pull request。</p>
<a href="https://github.com/zs-yg/kortapp-z/issues" target="_blank">提交反馈</a> <a href="https://github.com/zs-yg/kortapp-z/issues" target="_blank">提交反馈</a>
</section> </section>
</main> </main>

View File

@@ -18,20 +18,20 @@
<article class="feature"> <article class="feature">
<h3>应用程序管理</h3> <h3>应用程序管理</h3>
<p>批量安装、卸载(目前没有)和更新应用程序(目前没有)管理启动项(目前没有)。</p> <p>批量安装、卸载(目前没有)和更新应用程序(目前没有),管理启动项(目前没有)。</p>
<p>优势:集中管理所有应用节省时间避免系统臃肿。</p> <p>优势:集中管理所有应用,节省时间,避免系统臃肿。</p>
</article> </article>
<article class="feature"> <article class="feature">
<h3>资源监控(之后可能在内置工具里有)</h3> <h3>资源监控(之后可能在内置工具里有)</h3>
<p>实时监控CPU、内存、磁盘和网络使用情况。</p> <p>实时监控CPU、内存、磁盘和网络使用情况。</p>
<p>优势:直观的图表展示及时发现资源瓶颈。</p> <p>优势:直观的图表展示,及时发现资源瓶颈。</p>
</article> </article>
<article class="feature"> <article class="feature">
<h3>文件管理(之后可能在内置工具里有)</h3> <h3>文件管理(之后可能在内置工具里有)</h3>
<p>高级文件搜索、批量重命名和快速文件分类。</p> <p>高级文件搜索、批量重命名和快速文件分类。</p>
<p>优势:提升文件管理效率支持正则表达式搜索。</p> <p>优势:提升文件管理效率,支持正则表达式搜索。</p>
</article> </article>
</section> </section>
</main> </main>

BIN
img/png/Azul_JDKs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
img/png/Cataclysm-DDA.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
img/png/ClamAV.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
img/png/CodeBlocks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
img/png/Dev-C++.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
img/png/Final2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
img/png/FreeMove.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
img/png/Luanti.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
img/png/NoteGen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
img/png/Ubuntu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

BIN
img/png/VideoCaptioner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
img/png/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
img/png/gophish.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
img/png/hashcat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
img/png/keycloak.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
img/png/pixpin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

BIN
img/png/pocketbase.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

BIN
img/png/powershell.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

View File

@@ -1,8 +1,8 @@
; 脚本由 Inno Setup 脚本向导生成。 ; 脚本由 Inno Setup 脚本向导生成。
; 有关创建 Inno Setup 脚本文件的详细信息请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.9" #define MyAppVersion "1.3.7"
#define MyAppPublisher "zsyg" #define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z" #define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe" #define MyAppExeName "kortapp-z.exe"
@@ -12,7 +12,7 @@
[Setup] [Setup]
; 注意AppId 的值唯一标识此应用程序。不要在其他应用程序的安装程序中使用相同的 AppId 值。 ; 注意AppId 的值唯一标识此应用程序。不要在其他应用程序的安装程序中使用相同的 AppId 值。
; (若要生成新的 GUID请在 IDE 中单击 "工具|生成 GUID"。) ; (若要生成新的 GUID,请在 IDE 中单击 "工具|生成 GUID"。)
AppId={{8020EC01-6133-40BB-8B8B-0EB71E49696C} AppId={{8020EC01-6133-40BB-8B8B-0EB71E49696C}
AppName={#MyAppName} AppName={#MyAppName}
AppVersion={#MyAppVersion} AppVersion={#MyAppVersion}
@@ -27,7 +27,7 @@ UninstallDisplayIcon={app}\{#MyAppExeName}
; 除 Arm 上的 x64 和 Windows 11 之外的任何平台上。 ; 除 Arm 上的 x64 和 Windows 11 之外的任何平台上。
ArchitecturesAllowed=x64compatible ArchitecturesAllowed=x64compatible
; "ArchitecturesInstallIn64BitMode=x64compatible" 要求 ; "ArchitecturesInstallIn64BitMode=x64compatible" 要求
; 安装可以在 x64 或 Arm 上的 Windows 11 上以“64 位模式”完成 ; 安装可以在 x64 或 Arm 上的 Windows 11 上以“64 位模式”完成,
; 这意味着它应该使用本机 64 位 Program Files 目录和 ; 这意味着它应该使用本机 64 位 Program Files 目录和
; 注册表的 64 位视图。 ; 注册表的 64 位视图。
ArchitecturesInstallIn64BitMode=x64compatible ArchitecturesInstallIn64BitMode=x64compatible

View File

@@ -1,8 +1,8 @@
; 脚本由 Inno Setup 脚本向导生成。 ; 脚本由 Inno Setup 脚本向导生成。
; 有关创建 Inno Setup 脚本文件的详细信息请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.9" #define MyAppVersion "1.3.7"
#define MyAppPublisher "zsyg" #define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z" #define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe" #define MyAppExeName "kortapp-z.exe"
@@ -12,7 +12,7 @@
[Setup] [Setup]
; 注意AppId 的值唯一标识此应用程序。不要在其他应用程序的安装程序中使用相同的 AppId 值。 ; 注意AppId 的值唯一标识此应用程序。不要在其他应用程序的安装程序中使用相同的 AppId 值。
; (若要生成新的 GUID请在 IDE 中单击 "工具|生成 GUID"。) ; (若要生成新的 GUID,请在 IDE 中单击 "工具|生成 GUID"。)
AppId={{BF1944C3-CD0C-4119-A340-49C54961D48B} AppId={{BF1944C3-CD0C-4119-A340-49C54961D48B}
AppName={#MyAppName} AppName={#MyAppName}
AppVersion={#MyAppVersion} AppVersion={#MyAppVersion}

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
#include <iostream> #include <iostream>
#include <filesystem> #include <filesystem>
#include <chrono> #include <chrono>
@@ -50,7 +44,7 @@ int main() {
} }
} }
} else { } else {
std::cout << "日志目录不存在无需清理" << std::endl; std::cout << "日志目录不存在,无需清理" << std::endl;
return 0; return 0;
} }

View File

@@ -1,9 +1,3 @@
// _ _
//| | _____ _ __| |_ __ _ _ __ _ __ ____
//| |/ / _ \| '__| __/ _` | '_ \| '_ \ ____|_ /
//| | (_) | | | || (_| | |_) | |_) |_____/ /
//|_|\_\___/|_| \__\__,_| .__/| .__/ /___|
// |_| |_|
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
@@ -75,5 +69,25 @@ namespace AppStore
} }
Log(warningMessage); Log(warningMessage);
} }
public static void LogDebug(string message, Exception? ex = null)
{
string debugMessage = $"DEBUG: {message}";
if (ex != null)
{
debugMessage += $"\nException: {ex}\nStackTrace: {ex.StackTrace}";
}
Log(debugMessage);
}
public static void LogTip(string message, Exception? ex = null)
{
string tipMessage = $"TIP: {message}";
if (ex != null)
{
tipMessage += $"\nException: {ex}\nStackTrace: {ex.StackTrace}";
}
Log(tipMessage);
}
} }
} }

View File

@@ -0,0 +1,83 @@
cmake_minimum_required(VERSION 3.10)
project(ImageFormatConverter)
# 设置静态编译
set(CMAKE_EXE_LINKER_FLAGS "-static")
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置MSYS2库搜索路径
set(MSYS2_LIB_DIR "C:/msys64/ucrt64/lib")
# 查找依赖库(静态版本)
find_package(PkgConfig REQUIRED)
pkg_check_modules(TIFF REQUIRED libtiff-4)
find_library(TIFF_STATIC_LIB NAMES libtiff.a PATHS ${TIFF_LIBRARY_DIRS})
pkg_check_modules(WEBP REQUIRED libwebp)
find_library(WEBP_STATIC_LIB NAMES libwebp.a PATHS ${WEBP_LIBRARY_DIRS})
pkg_check_modules(AVIF REQUIRED libavif)
find_library(AVIF_STATIC_LIB NAMES libavif.a PATHS ${AVIF_LIBRARY_DIRS})
# 使用find_package查找FLTK(静态版本)
find_package(FLTK REQUIRED)
find_library(FLTK_STATIC_LIB NAMES libfltk.a PATHS ${FLTK_LIBRARY_DIRS})
# 查找cairo导入库
find_library(CAIRO_IMPORT_LIB NAMES libcairo.dll.a PATHS "C:/msys64/ucrt64/lib")
# 查找其他依赖库
find_library(JPEG_STATIC_LIB NAMES libjpeg.a PATHS ${MSYS2_LIB_DIR})
find_library(ZLIB_STATIC_LIB NAMES libz.a PATHS ${MSYS2_LIB_DIR})
find_library(ZSTD_STATIC_LIB NAMES libzstd.a PATHS ${MSYS2_LIB_DIR})
find_library(SHARPYUV_STATIC_LIB NAMES libsharpyuv.a PATHS ${MSYS2_LIB_DIR})
find_library(JBIG_STATIC_LIB NAMES libjbig.a PATHS ${MSYS2_LIB_DIR})
find_library(LZMA_STATIC_LIB NAMES liblzma.a PATHS ${MSYS2_LIB_DIR})
find_library(LIBDEFLATE_STATIC_LIB NAMES libdeflate.a PATHS ${MSYS2_LIB_DIR})
find_library(LERC_STATIC_LIB NAMES liblerc.a PATHS ${MSYS2_LIB_DIR})
find_library(AOM_STATIC_LIB NAMES libaom.a PATHS ${MSYS2_LIB_DIR})
find_library(YUV_STATIC_LIB NAMES libyuv.a PATHS ${MSYS2_LIB_DIR})
find_library(SVTAV1_ENC_STATIC_LIB NAMES libSvtAv1Enc.a PATHS ${MSYS2_LIB_DIR})
find_library(RAV1E_STATIC_LIB NAMES librav1e.a PATHS ${MSYS2_LIB_DIR})
find_library(DAV1D_STATIC_LIB NAMES libdav1d.a PATHS ${MSYS2_LIB_DIR})
# 包含头文件目录
include_directories(include ${TIFF_INCLUDE_DIRS} ${WEBP_INCLUDE_DIRS} ${FLTK_INCLUDE_DIRS} ${AVIF_INCLUDE_DIRS} "C:/msys64/ucrt64/include/cairo")
# 收集所有源文件
file(GLOB SOURCES "src/*.cpp")
# 创建可执行文件(设置为WIN32应用程序避免控制台窗口)
add_executable(ImageFormatConverter WIN32 ${SOURCES})
# 链接静态库
target_link_libraries(ImageFormatConverter
${TIFF_STATIC_LIB}
${WEBP_STATIC_LIB}
${FLTK_STATIC_LIB}
${JPEG_STATIC_LIB}
${ZLIB_STATIC_LIB}
${ZSTD_STATIC_LIB}
${SHARPYUV_STATIC_LIB}
${JBIG_STATIC_LIB}
${LZMA_STATIC_LIB}
${LIBDEFLATE_STATIC_LIB}
${LERC_STATIC_LIB}
${AVIF_STATIC_LIB}
${AOM_STATIC_LIB}
${YUV_STATIC_LIB}
${SVTAV1_ENC_STATIC_LIB}
${RAV1E_STATIC_LIB}
${DAV1D_STATIC_LIB}
${CAIRO_IMPORT_LIB}
"C:/msys64/ucrt64/lib/libcairo.a"
-lgdi32 -lmsimg32 # 添加Windows图形库
-lstdc++ -lgcc -lwinpthread -lcomctl32 -lole32 -luuid -lws2_32 -lntdll)
# 设置输出目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToBmpConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToJpegConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToJpgConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToPngConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToTiffConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class AvifToWebpConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class BmpToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class BmpToJpegConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class BmpToJpgConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class BmpToPngConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int compression_level = 6);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class BmpToTiffConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class BmpToWebpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,25 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <stb/stb_image.h>
struct ImageData {
int width;
int height;
int channels;
std::unique_ptr<unsigned char, void(*)(void*)> pixels;
ImageData() : pixels(nullptr, stbi_image_free) {}
};
enum class ImageFormat {
PNG,
JPG,
TIFF,
WEBP,
AVIF,
UNKNOWN
};
ImageFormat get_format_from_extension(const std::string& path);

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class ConverterBase {
public:
virtual ~ConverterBase() = default;
virtual bool convert(const std::string& input,
const std::string& output) = 0;
protected:
virtual bool validate(const ImageData& data) = 0;
};

View File

@@ -0,0 +1,23 @@
#pragma once
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Choice.H>
#include <string>
class MainWindow : public Fl_Window {
public:
MainWindow(int w, int h, const char* title);
private:
Fl_Input* input_path;
Fl_Output* output_path;
Fl_Choice* format_choice;
Fl_Button* convert_btn;
static void input_file_cb(Fl_Widget* w, void* data);
static void output_file_cb(Fl_Widget* w, void* data);
static void convert_cb(Fl_Widget* w, void* data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include "common.hpp"
#include <string>
class ImageLoader {
public:
static ImageData load(const std::string& path);
static bool save_png(const std::string& path, const ImageData& data);
static bool save_jpg(const std::string& path, const ImageData& data, int quality = 90);
static void validate_image(const unsigned char* data, int width, int height);
private:
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class JpegToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class JpegToBmpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class JpegToPngConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class JpegToTiffConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class JpegToWebpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class JpgToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class JpgToBmpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class JpgToPngConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int compression_level = 6);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class JpgToTiffConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class JpgToWebpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class PngToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class PngToBmpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class PngToJpegConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class PngToJpgConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class PngToTiffConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class PngToWebpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class TiffToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class TiffToBmpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class TiffToJpegConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class TiffToJpgConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class TiffToPngConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int compression_level = 6);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class TiffToWebpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,11 @@
#pragma once
#include "converter_base.hpp"
#include "common.hpp"
class WebpToAvifConverter : public ConverterBase {
public:
bool convert(const std::string& input, const std::string& output) override;
protected:
bool validate(const ImageData& data) override;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class WebpToBmpConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class WebpToJpegConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include "common.hpp"
class WebpToJpgConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path,
int quality = 90);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class WebpToPngConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include <string>
#include "common.hpp"
class WebpToTiffConverter {
public:
static bool convert(const std::string& input_path,
const std::string& output_path);
private:
static bool validate_input(const ImageData& data);
};

View File

@@ -0,0 +1,31 @@
#include "avif_to_bmp.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <stb/stb_image_write.h>
bool AvifToBmpConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 保存为BMP
return stbi_write_bmp(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get());
}
bool AvifToBmpConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,32 @@
#include "avif_to_jpeg.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <stb/stb_image_write.h>
bool AvifToJpegConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 保存为JPEG(默认质量90)
return stbi_write_jpg(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
90);
}
bool AvifToJpegConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,32 @@
#include "avif_to_jpg.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <stb/stb_image_write.h>
bool AvifToJpgConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 保存为JPG(默认质量90)
return stbi_write_jpg(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
90);
}
bool AvifToJpgConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,33 @@
#include "avif_to_png.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <stb/stb_image_write.h>
bool AvifToPngConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 保存为PNG
return stbi_write_png(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
data.width * data.channels);
}
bool AvifToPngConverter::validate(const ImageData& data) {
// 确保是有效的图像数据
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,65 @@
#include "avif_to_tiff.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <tiffio.h>
bool AvifToTiffConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 创建TIFF文件
TIFF* tif = TIFFOpen(output_path.c_str(), "w");
if (!tif) {
return false;
}
// 设置TIFF标签
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, data.width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, data.height);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, data.channels);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,
(data.channels == 1) ? PHOTOMETRIC_MINISBLACK :
(data.channels == 3) ? PHOTOMETRIC_RGB : PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
// 写入图像数据
tsize_t linebytes = data.width * data.channels;
unsigned char* buf = nullptr;
if (TIFFScanlineSize(tif) == linebytes) {
buf = (unsigned char*)_TIFFmalloc(linebytes);
} else {
buf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(tif));
}
for (uint32_t row = 0; row < data.height; row++) {
memcpy(buf, &data.pixels.get()[row * linebytes], linebytes);
if (TIFFWriteScanline(tif, buf, row, 0) < 0) {
_TIFFfree(buf);
TIFFClose(tif);
return false;
}
}
// 清理资源
_TIFFfree(buf);
TIFFClose(tif);
return true;
}
bool AvifToTiffConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 1 || data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,50 @@
#include "avif_to_webp.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <webp/encode.h>
bool AvifToWebpConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载AVIF图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 保存为WEBP
FILE* f = fopen(output_path.c_str(), "wb");
if (!f) {
return false;
}
uint8_t* output = nullptr;
size_t size = 0;
if (data.channels == 3) {
size = WebPEncodeRGB(data.pixels.get(), data.width, data.height,
data.width * 3, 90, &output);
} else if (data.channels == 4) {
size = WebPEncodeRGBA(data.pixels.get(), data.width, data.height,
data.width * 4, 90, &output);
}
if (size == 0 || !output) {
fclose(f);
return false;
}
fwrite(output, 1, size, f);
fclose(f);
WebPFree(output);
return true;
}
bool AvifToWebpConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,71 @@
#include "bmp_to_avif.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <avif/avif.h>
#include <stb/stb_image.h>
bool BmpToAvifConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate(data)) {
return false;
}
// 创建AVIF编码器
avifEncoder* encoder = avifEncoderCreate();
encoder->maxThreads = 4;
encoder->minQuantizer = 20;
encoder->maxQuantizer = 20;
encoder->speed = 6;
// 创建AVIF图像
avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420);
avifRGBImage rgbImage;
avifRGBImageSetDefaults(&rgbImage, image);
rgbImage.pixels = data.pixels.get();
rgbImage.rowBytes = data.width * data.channels;
rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA;
// 转换RGB到YUV
if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) {
avifEncoderDestroy(encoder);
avifImageDestroy(image);
return false;
}
// 编码AVIF图像
avifRWData output = AVIF_DATA_EMPTY;
if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) {
avifEncoderDestroy(encoder);
avifImageDestroy(image);
return false;
}
// 保存AVIF文件
FILE* f = fopen(output_path.c_str(), "wb");
if (!f) {
avifRWDataFree(&output);
avifEncoderDestroy(encoder);
avifImageDestroy(image);
return false;
}
fwrite(output.data, 1, output.size, f);
fclose(f);
// 清理资源
avifRWDataFree(&output);
avifEncoderDestroy(encoder);
avifImageDestroy(image);
return true;
}
bool BmpToAvifConverter::validate(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,35 @@
#include "bmp_to_jpeg.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
#include <string>
bool BmpToJpegConverter::convert(const std::string& input_path,
const std::string& output_path,
int quality) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate_input(data)) {
return false;
}
// 保存为JPEG
return stbi_write_jpg(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
quality);
}
bool BmpToJpegConverter::validate_input(const ImageData& data) {
// 确保是有效的图像数据
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,35 @@
#include "bmp_to_jpg.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
#include <string>
bool BmpToJpgConverter::convert(const std::string& input_path,
const std::string& output_path,
int quality) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate_input(data)) {
return false;
}
// 保存为JPG
return stbi_write_jpg(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
quality);
}
bool BmpToJpgConverter::validate_input(const ImageData& data) {
// 确保是有效的图像数据
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,35 @@
#include "bmp_to_png.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
#include <string>
bool BmpToPngConverter::convert(const std::string& input_path,
const std::string& output_path,
int compression_level) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate_input(data)) {
return false;
}
// 保存为PNG
return stbi_write_png(output_path.c_str(),
data.width,
data.height,
data.channels,
data.pixels.get(),
data.width * data.channels);
}
bool BmpToPngConverter::validate_input(const ImageData& data) {
// 确保是有效的图像数据
return data.width > 0 && data.height > 0 &&
(data.channels == 1 || data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,61 @@
#include "bmp_to_tiff.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <tiffio.h>
#include <stb/stb_image.h>
#include <string>
bool BmpToTiffConverter::convert(const std::string& input_path,
const std::string& output_path) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入
if (!validate_input(data)) {
return false;
}
// 创建TIFF文件
TIFF* tif = TIFFOpen(output_path.c_str(), "w");
if (!tif) {
return false;
}
// 设置TIFF标签
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, data.width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, data.height);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, data.channels);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
// 根据通道数设置PhotometricInterpretation
if (data.channels == 1) {
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
} else if (data.channels == 3 || data.channels == 4) {
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
} else {
TIFFClose(tif);
return false;
}
// 写入图像数据
tsize_t linebytes = data.width * data.channels;
unsigned char* buf = (unsigned char*)_TIFFmalloc(linebytes);
for (int y = 0; y < data.height; y++) {
memcpy(buf, &data.pixels.get()[y * linebytes], linebytes);
TIFFWriteScanline(tif, buf, y, 0);
}
_TIFFfree(buf);
TIFFClose(tif);
return true;
}
bool BmpToTiffConverter::validate_input(const ImageData& data) {
return data.width > 0 && data.height > 0 &&
(data.channels == 1 || data.channels == 3 || data.channels == 4);
}

View File

@@ -0,0 +1,61 @@
#include "bmp_to_webp.hpp"
#include "common.hpp"
#include "image_loader.hpp"
#include <webp/encode.h>
#include <string>
bool BmpToWebpConverter::convert(const std::string& input_path,
const std::string& output_path,
int quality) {
// 加载BMP图像
ImageData data = ImageLoader::load(input_path);
if (!data.pixels) {
return false;
}
// 验证输入格式
if (!validate_input(data)) {
return false;
}
// 编码为WebP
uint8_t* output = nullptr;
size_t output_size;
if (data.channels == 3) {
output_size = WebPEncodeRGB(data.pixels.get(),
data.width,
data.height,
data.width * data.channels,
quality,
&output);
} else {
output_size = WebPEncodeRGBA(data.pixels.get(),
data.width,
data.height,
data.width * data.channels,
quality,
&output);
}
if (output_size == 0) {
return false;
}
// 保存WebP文件
FILE* file = fopen(output_path.c_str(), "wb");
if (!file) {
WebPFree(output);
return false;
}
fwrite(output, 1, output_size, file);
fclose(file);
WebPFree(output);
return true;
}
bool BmpToWebpConverter::validate_input(const ImageData& data) {
// 确保是有效的图像数据
return data.width > 0 && data.height > 0 &&
(data.channels == 3 || data.channels == 4);
}

Some files were not shown because too many files have changed in this diff Show More