Compare commits

..

8 Commits

Author SHA1 Message Date
zsyg
5e8de310df 添加图标提取器图标 2025-07-05 14:17:32 +08:00
zsyg
f3cca9b3a1 添加图标提取器代码 2025-07-05 14:16:38 +08:00
zsyg
2154f465b7 Add files via upload 2025-07-05 14:16:00 +08:00
zsyg
99bbda4668 添加版本号 2025-07-05 10:24:08 +08:00
zsyg
d1d69da3e3 Add files via upload 2025-07-05 10:22:19 +08:00
zsyg
4c8cb807d9 添加ollama 2025-07-05 10:20:04 +08:00
zsyg
1ad64feab9 添加ollama 2025-07-05 10:19:19 +08:00
zsyg
ef7c582c50 删除视频压缩工具 2025-07-02 20:14:29 +08:00
17 changed files with 1099 additions and 551 deletions

View File

@@ -57,7 +57,7 @@ namespace AppStore
// 初始化并添加应用信息
infoLabel = new Label();
infoLabel.Text = "kortapp-z\n版本: 1.1.4\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
infoLabel.Text = "kortapp-z\n版本: 1.1.7\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
infoLabel.Font = new Font("Microsoft YaHei", 12);
infoLabel.AutoSize = false;
infoLabel.Width = 300;

File diff suppressed because it is too large Load Diff

View File

@@ -464,44 +464,6 @@ namespace AppStore
};
flowPanel.Controls.Add(systemInfoCard);
// 视频压缩工具卡片
var videoCompressorCard = new ToolCard();
videoCompressorCard.ToolName = "视频压缩工具";
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "video_compressor.png");
if (File.Exists(iconPath))
{
videoCompressorCard.ToolIcon = Image.FromFile(iconPath);
}
else
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
}
catch
{
videoCompressorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
}
videoCompressorCard.UpdateDisplay();
videoCompressorCard.ToolCardClicked += (s, e) => {
try {
string toolPath = Path.Combine(Application.StartupPath, "resource", "video_compressor.exe");
if (File.Exists(toolPath)) {
Process.Start(toolPath);
} else {
MessageBox.Show("视频压缩工具未找到,请确保已正确安装", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
} catch (Exception ex) {
MessageBox.Show($"启动视频压缩工具失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
flowPanel.Controls.Add(videoCompressorCard);
// 计算器工具卡片
var calculatorCard = new CalculatorToolCard();
try
@@ -589,6 +551,23 @@ namespace AppStore
}
flowPanel.Controls.Add(selfStartingManagerCard);
// 图标提取器工具卡片
var iconExtractorCard = new AppStore.Tools.IconExtractor.IconExtractorToolCard();
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "ico_extractor.png");
if (File.Exists(iconPath))
{
iconExtractorCard.ToolIcon = Image.FromFile(iconPath);
}
iconExtractorCard.UpdateDisplay();
}
catch (Exception ex)
{
Logger.LogError("加载图标提取器图标失败", ex);
}
flowPanel.Controls.Add(iconExtractorCard);
}
catch (Exception ex)
{
@@ -1202,6 +1181,11 @@ namespace AppStore
"https://ghproxy.net/https://github.com/cloudreve/cloudreve/releases/download/3.8.3/cloudreve_3.8.3_windows_amd64.zip",
"img/png/cloudreve.png"));
flowPanel.Controls.Add(CreateAppCard(
"ollama",
"https://www.ghproxy.cn/https://github.com/ollama/ollama/releases/download/v0.9.5/OllamaSetup.exe",
"img/png/ollama.png"));
flowPanel.Controls.Add(CreateAppCard(
"SeelenUI",
"https://ghproxy.net/https://github.com/eythaann/Seelen-UI/releases/download/v2.3.8/Seelen.UI_2.3.8_x64-setup.exe",

View File

@@ -209,7 +209,7 @@ namespace AppStore
{
string jsonString = File.ReadAllText(jsonPath);
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;

BIN
img/png/ollama.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 KiB

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z"
#define MyAppVersion "1.1.4"
#define MyAppVersion "1.1.7"
#define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe"

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z"
#define MyAppVersion "1.1.4"
#define MyAppVersion "1.1.7"
#define MyAppPublisher "zsyg"
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
#define MyAppExeName "kortapp-z.exe"

Binary file not shown.

View File

@@ -131,29 +131,39 @@ namespace AppStore
{
foreach (var item in items)
{
Image iconImage = null;
Image? iconImage = null;
try
{
if (!string.IsNullOrEmpty(item.Value) && System.IO.File.Exists(item.Value))
{
using (Icon icon = Icon.ExtractAssociatedIcon(item.Value))
{
iconImage = icon.ToBitmap();
iconImage = icon?.ToBitmap() ?? SystemIcons.Application.ToBitmap();
}
}
else
{
// 使用默认图标
iconImage = SystemIcons.Application.ToBitmap();
iconImage = SystemIcons.Application?.ToBitmap() ?? SystemIcons.WinLogo.ToBitmap();
}
}
catch (Exception ex)
{
Logger.LogWarning($"无法加载程序图标: {item.Value}", ex);
iconImage = SystemIcons.Warning.ToBitmap();
// 确保在任何情况下都有有效的图标
iconImage = SystemIcons.Warning?.ToBitmap()
?? SystemIcons.Error?.ToBitmap()
?? SystemIcons.Application?.ToBitmap()
?? SystemIcons.WinLogo?.ToBitmap()
?? SystemIcons.Shield?.ToBitmap()
?? new Bitmap(16, 16);
if (iconImage == null)
{
iconImage = new Bitmap(16, 16);
}
}
dataGridView.Rows.Add(iconImage, item.Key, item.Value);
dataGridView.Rows.Add(iconImage!, item.Key, item.Value);
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractor
{
/// <summary>
/// 获取ICO文件中的实际尺寸列表
/// </summary>
public static List<int> GetIconDimensions(string filePath)
{
var sizes = new List<int>();
try
{
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var reader = new BinaryReader(fs))
{
// 读取ICO文件头
reader.ReadUInt16(); // 保留字段
ushort type = reader.ReadUInt16(); // 1=ICO, 2=CUR
ushort count = reader.ReadUInt16(); // 图像数量
if (type != 1) return sizes; // 不是ICO文件
// 读取每个图像目录项
for (int i = 0; i < count; i++)
{
byte width = reader.ReadByte();
byte height = reader.ReadByte();
reader.ReadBytes(14); // 跳过其他字段
// 宽度/高度为0表示256像素
int size = width == 0 ? 256 : width;
sizes.Add(size);
}
}
}
catch
{
// 忽略所有错误,返回空列表
}
return sizes;
}
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int ExtractIconEx(
string lpszFile,
int nIconIndex,
[AllowNull] IntPtr[] phiconLarge,
[AllowNull] IntPtr[] phiconSmall,
int nIcons);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool DestroyIcon(IntPtr handle);
/// <summary>
/// 从文件中提取图标
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="iconIndex">图标索引</param>
/// <param name="largeIcon">是否提取大图标</param>
/// <returns>提取的图标</returns>
public static Icon ExtractIconFromFile(string filePath, int iconIndex = 0)
{
IntPtr[] hIcons = new IntPtr[1];
int extractedCount = ExtractIconEx(filePath, iconIndex, hIcons, null, 1);
if (extractedCount <= 0 || hIcons[0] == IntPtr.Zero)
throw new FileNotFoundException("无法从文件中提取图标");
// 直接返回原始图标
Icon icon = (Icon)Icon.FromHandle(hIcons[0]).Clone();
DestroyIcon(hIcons[0]);
return icon;
}
/// <summary>
/// 将图标保存为文件
/// </summary>
/// <param name="icon">图标对象</param>
/// <param name="outputPath">输出路径</param>
public static void SaveIconToFile(Icon icon, string outputPath)
{
using (FileStream fs = new FileStream(outputPath, FileMode.Create))
{
icon.Save(fs);
}
}
/// <summary>
/// 获取文件中的图标数量
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>图标数量</returns>
public static int GetIconCount(string filePath)
{
return ExtractIconEx(filePath, -1, null, null, 0);
}
}
}

View File

@@ -0,0 +1,19 @@
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorConstants
{
public const string FileFilter = "可执行文件|*.exe;*.dll;*.ocx;*.cpl|所有文件|*.*";
public const string SaveFilter = "图标文件|*.ico|位图文件|*.bmp|PNG文件|*.png";
public static readonly int[] SupportedSizes = { 16, 24, 32, 48, 64, 128, 256, 512 };
public static readonly int DefaultExtractSize = 256;
public const string ErrorNoIconsFound = "文件不包含任何图标";
public const string ErrorExtractionFailed = "图标提取失败";
public const string ErrorInvalidIndex = "无效的图标索引";
public const string ErrorFileNotFound = "文件未找到";
public const int MaxRecentFiles = 5;
public const int DefaultPreviewSize = 128;
}
}

View File

@@ -0,0 +1,186 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using AppStore.Tools.IconExtractor;
namespace AppStore.Tools.IconExtractor
{
public class IconExtractorForm : Form
{
private Button btnBrowse = new Button();
private Button btnSave = new Button();
private NumericUpDown numIconIndex = new NumericUpDown();
private PictureBox picIcon = new PictureBox();
private Label lblStatus = new Label();
private TextBox txtFilePath = new TextBox();
private ComboBox cmbIconSize = new ComboBox();
private string currentFilePath = string.Empty;
public IconExtractorForm()
{
this.Text = "图标提取器";
this.Size = new Size(500, 550);
this.StartPosition = FormStartPosition.CenterScreen;
InitializeComponents();
}
private void InitializeComponents()
{
// 文件路径文本框
txtFilePath.Location = new Point(20, 20);
txtFilePath.Size = new Size(300, 25);
txtFilePath.ReadOnly = true;
this.Controls.Add(txtFilePath);
// 浏览按钮
btnBrowse.Text = "浏览...";
btnBrowse.Location = new Point(330, 20);
btnBrowse.Size = new Size(80, 25);
btnBrowse.Click += BtnBrowse_Click;
this.Controls.Add(btnBrowse);
// 图标索引标签
Label lblIndex = new Label();
lblIndex.Text = "图标索引:";
lblIndex.Location = new Point(20, 60);
lblIndex.Size = new Size(80, 20);
this.Controls.Add(lblIndex);
// 图标索引选择器
numIconIndex.Location = new Point(100, 60);
numIconIndex.Size = new Size(80, 20);
numIconIndex.Minimum = 0;
numIconIndex.ValueChanged += NumIconIndex_ValueChanged;
this.Controls.Add(numIconIndex);
// 图标预览区域
picIcon.Location = new Point(20, 100);
picIcon.Size = new Size(256, 256);
picIcon.SizeMode = PictureBoxSizeMode.Zoom;
picIcon.BorderStyle = BorderStyle.FixedSingle;
this.Controls.Add(picIcon);
// 索引说明
Label lblIndexHelp = new Label();
lblIndexHelp.Text = "索引号表示文件中的第几个图标从0开始";
lblIndexHelp.Location = new Point(20, 240);
lblIndexHelp.Size = new Size(300, 20);
this.Controls.Add(lblIndexHelp);
// 保存按钮
btnSave.Text = "保存图标";
btnSave.Location = new Point(20, 450);
btnSave.Size = new Size(100, 30);
btnSave.Click += BtnSave_Click;
this.Controls.Add(btnSave);
// 状态标签
lblStatus.Location = new Point(20, 490);
lblStatus.Size = new Size(400, 20);
lblStatus.Text = "请选择包含图标的文件";
this.Controls.Add(lblStatus);
}
private void BtnBrowse_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Filter = "可执行文件|*.exe;*.dll;*.ocx;*.cpl|所有文件|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
currentFilePath = ofd.FileName;
txtFilePath.Text = currentFilePath;
LoadIconInfo();
}
}
}
private void LoadIconInfo()
{
try
{
int iconCount = IconExtractor.GetIconCount(currentFilePath);
numIconIndex.Maximum = Math.Max(0, iconCount - 1);
// 如果是ICO文件获取实际包含的尺寸
if (currentFilePath.EndsWith(".ico", StringComparison.OrdinalIgnoreCase))
{
var sizes = IconExtractor.GetIconDimensions(currentFilePath);
if (sizes.Count > 0)
{
cmbIconSize.Items.Clear();
foreach (var size in sizes)
{
cmbIconSize.Items.Add($"{size}x{size}");
}
// 默认选择最接近256的尺寸
int closest = sizes.OrderBy(s => Math.Abs(s - 256)).First();
cmbIconSize.SelectedIndex = sizes.IndexOf(closest);
}
}
lblStatus.Text = $"找到 {iconCount} 个图标";
ExtractAndDisplayIcon();
}
catch (Exception ex)
{
lblStatus.Text = $"错误: {ex.Message}";
picIcon.Image = null;
}
}
private void NumIconIndex_ValueChanged(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(currentFilePath))
{
ExtractAndDisplayIcon();
}
}
private void ExtractAndDisplayIcon()
{
try
{
Icon icon = IconExtractor.ExtractIconFromFile(currentFilePath, (int)numIconIndex.Value);
picIcon.Image = icon.ToBitmap();
lblStatus.Text = $"显示原始图标 #{numIconIndex.Value}";
}
catch (Exception ex)
{
lblStatus.Text = $"提取图标失败: {ex.Message}";
picIcon.Image = null;
}
}
private void BtnSave_Click(object sender, EventArgs e)
{
if (picIcon.Image == null)
{
MessageBox.Show("没有可保存的图标", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
using (SaveFileDialog sfd = new SaveFileDialog())
{
sfd.Filter = "图标文件|*.ico|位图文件|*.bmp|PNG文件|*.png";
if (sfd.ShowDialog() == DialogResult.OK)
{
try
{
using (Icon icon = IconExtractor.ExtractIconFromFile(currentFilePath, (int)numIconIndex.Value))
{
IconExtractor.SaveIconToFile(icon, sfd.FileName);
lblStatus.Text = $"已保存原始图标到 {sfd.FileName}";
}
}
catch (Exception ex)
{
MessageBox.Show($"保存图标失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Drawing;
using System.IO;
using System.Collections.Generic;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorHelper
{
/// <summary>
/// 将图标转换为位图
/// </summary>
public static Bitmap ConvertIconToBitmap(Icon icon, Size size)
{
Bitmap bitmap = new Bitmap(size.Width, size.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawIcon(icon, new Rectangle(0, 0, size.Width, size.Height));
}
return bitmap;
}
/// <summary>
/// 批量提取文件中的所有图标
/// </summary>
public static List<Icon> ExtractAllIcons(string filePath)
{
List<Icon> icons = new List<Icon>();
int count = IconExtractor.GetIconCount(filePath);
for (int i = 0; i < count; i++)
{
try
{
Icon icon = IconExtractor.ExtractIconFromFile(filePath, i);
icons.Add(icon);
}
catch
{
// 忽略提取失败的图标
}
}
return icons;
}
/// <summary>
/// 将图标保存为PNG格式
/// </summary>
public static void SaveIconAsPng(Icon icon, string outputPath)
{
using (Bitmap bitmap = icon.ToBitmap())
{
bitmap.Save(outputPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
/// <summary>
/// 检查文件是否包含图标
/// </summary>
public static bool HasIcons(string filePath)
{
try
{
return IconExtractor.GetIconCount(filePath) > 0;
}
catch
{
return false;
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.IO;
using System.Text.Json;
namespace AppStore.Tools.IconExtractor
{
public static class IconExtractorSettings
{
private static readonly string SettingsPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"kortapp-z", "icon_extractor_settings.json");
public static SettingsData CurrentSettings { get; private set; } = new SettingsData();
public class SettingsData
{
public string LastUsedDirectory { get; set; } = string.Empty;
public string DefaultSaveFormat { get; set; } = "ico";
public int DefaultIconSize { get; set; } = 128;
public string[] RecentFiles { get; set; } = Array.Empty<string>();
}
/// <summary>
/// 加载设置
/// </summary>
public static void LoadSettings()
{
try
{
if (File.Exists(SettingsPath))
{
string json = File.ReadAllText(SettingsPath);
if (!string.IsNullOrWhiteSpace(json))
{
try
{
using (JsonDocument doc = JsonDocument.Parse(json))
{
var root = doc.RootElement;
CurrentSettings = new SettingsData
{
LastUsedDirectory = root.TryGetProperty("LastUsedDirectory", out var dir) ? dir.GetString() ?? string.Empty : string.Empty,
DefaultSaveFormat = root.TryGetProperty("DefaultSaveFormat", out var format) ? format.GetString() ?? "ico" : "ico",
DefaultIconSize = root.TryGetProperty("DefaultIconSize", out var size) ? size.GetInt32() : 128,
RecentFiles = root.TryGetProperty("RecentFiles", out var files) ?
JsonSerializer.Deserialize<string[]>(files.GetRawText()) ?? Array.Empty<string>() :
Array.Empty<string>()
};
}
}
catch
{
CurrentSettings = new SettingsData();
}
}
}
}
catch
{
// 加载失败时使用默认设置
CurrentSettings = new SettingsData();
}
}
/// <summary>
/// 保存设置
/// </summary>
public static void SaveSettings()
{
try
{
if (string.IsNullOrEmpty(SettingsPath))
return;
string directory = Path.GetDirectoryName(SettingsPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string json = JsonSerializer.Serialize(CurrentSettings);
File.WriteAllText(SettingsPath, json);
}
catch
{
// 忽略保存错误
}
}
/// <summary>
/// 添加最近使用的文件
/// </summary>
public static void AddRecentFile(string filePath)
{
if (CurrentSettings.RecentFiles.Length >= 5)
{
var list = new List<string>(CurrentSettings.RecentFiles);
list.RemoveAt(0);
CurrentSettings.RecentFiles = list.ToArray();
}
var newList = new List<string>(CurrentSettings.RecentFiles);
if (!newList.Contains(filePath))
{
newList.Add(filePath);
CurrentSettings.RecentFiles = newList.ToArray();
SaveSettings();
}
}
/// <summary>
/// 更新最后使用的目录
/// </summary>
public static void UpdateLastUsedDirectory(string directory)
{
if (Directory.Exists(directory) && CurrentSettings.LastUsedDirectory != directory)
{
CurrentSettings.LastUsedDirectory = directory;
SaveSettings();
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
namespace AppStore.Tools.IconExtractor
{
public class IconExtractorToolCard : ToolCard
{
public IconExtractorToolCard()
{
ToolName = "图标提取器";
try
{
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "QRcode.png");
if (File.Exists(iconPath))
{
ToolIcon = Image.FromFile(iconPath);
}
else
{
ToolIcon = SystemIcons.Application.ToBitmap();
}
}
catch
{
ToolIcon = SystemIcons.Application.ToBitmap();
}
this.ToolCardClicked += OnIconExtractorCardClicked;
UpdateDisplay();
}
private void OnIconExtractorCardClicked(object sender, EventArgs e)
{
var iconExtractorForm = new IconExtractorForm();
iconExtractorForm.ShowDialog();
}
}
}