livia-test/Livia/Utility/LiviaUtility.cs
2025-03-28 14:31:53 +08:00

209 lines
6.4 KiB
C#

using Livia.Properties;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Livia.Utility;
public static class LiviaUtility
{
public static void CreateFromDirectory(string fromPath, string outputFileName, CancellationToken token)
{
using FileStream zipToOpen = new(outputFileName, FileMode.Create);
using ZipArchive archive = new(zipToOpen, ZipArchiveMode.Create);
RecursiveAddToZip(fromPath, fromPath, archive, token);
}
private static void RecursiveAddToZip(string root, string folder, ZipArchive zipArchive, CancellationToken token)
{
DirectoryInfo directoryInfo = new(folder);
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
{
if (token.IsCancellationRequested)
{
return;
}
string relativePath = Path.GetRelativePath(root, fileInfo.FullName);
zipArchive.CreateEntryFromFile(fileInfo.FullName, relativePath);
}
foreach (DirectoryInfo directory in directoryInfo.GetDirectories())
{
if (token.IsCancellationRequested)
{
return;
}
RecursiveAddToZip(root, directory.FullName, zipArchive, token);
}
}
public static Dictionary<string, string> ParseArgs(string[] args)
{
Dictionary<string, string> result = new();
for (int i = 0; i < args.Length; i++)
{
string arg = args[i];
//First item in list is not argument
if (!arg.StartsWith('-'))
continue;
arg = Regex.Replace(arg, "^-{1,2}", "");
if (result.ContainsKey(arg))
throw new ArgumentException(arg);
//forward to next arg
string argValue = string.Empty;
for (int j = i + 1; j < args.Length; j++)
{
if (args[i + 1].StartsWith("-"))
{
break;
}
if (!string.IsNullOrEmpty(argValue))
argValue += " ";
argValue += args[j];
i++;
}
result.Add(arg, argValue);
}
return result;
}
public static IEnumerable<string> ReadFilesFromDir(string dir)
{
string[] files = Directory.GetFiles(dir);
Array.Sort(files);
return files;
}
public static async Task<BitmapImage> LoadBitmapAsync(string file)
{
await using FileStream fileStream = new(file, FileMode.Open, FileAccess.Read);
await using MemoryStream memoryStream = new();
await fileStream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
BitmapImage image = new();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.DecodePixelWidth = 1024;
image.StreamSource = memoryStream;
image.EndInit();
image.Freeze();
return image;
}
public static BitmapSource CreateTransparency(BitmapSource source, bool showBoundary)
{
FormatConvertedBitmap rgbaBitmap = new();
rgbaBitmap.BeginInit();
rgbaBitmap.Source = source;
rgbaBitmap.DestinationFormat = PixelFormats.Bgra32;
rgbaBitmap.EndInit();
rgbaBitmap.Freeze();
int bytesPerPixel = (rgbaBitmap.Format.BitsPerPixel + 7) / 8;
int stride = bytesPerPixel * rgbaBitmap.PixelWidth;
byte[] buffer = new byte[stride * rgbaBitmap.PixelHeight];
rgbaBitmap.CopyPixels(buffer, stride, 0);
for (int y = 0; y < rgbaBitmap.PixelHeight; y++)
{
for (int x = 0; x < rgbaBitmap.PixelWidth; x++)
{
int i = stride * y + bytesPerPixel * x;
byte b = buffer[i];
byte g = buffer[i + 1];
byte r = buffer[i + 2];
if (b + g + r == 0)
{
buffer[i + 3] = 0; // set transparent
continue;
}
if (showBoundary)
{
bool isBoundary = false;
//check all neighboring pixels
for (int dx = -1; dx < 2; dx++)
{
for (int dy = -1; dy < 2; dy++)
{
if (dx == 0 && dy == 0)
continue;
if (!PixelIsEmpty(buffer, stride, bytesPerPixel, x + dx, y + dy, rgbaBitmap.PixelHeight, rgbaBitmap.PixelWidth))
continue;
isBoundary = true;
break;
}
if (isBoundary)
break;
}
buffer[i + 3] = (byte)(isBoundary ? 200 : 128);
}
else
{
buffer[i + 3] = 128;
}
}
}
BitmapSource result = BitmapSource.Create(rgbaBitmap.PixelWidth, rgbaBitmap.PixelHeight, rgbaBitmap.DpiX, rgbaBitmap.DpiY, rgbaBitmap.Format, null, buffer, stride);
result.Freeze();
return result;
}
private static bool PixelIsEmpty(IReadOnlyList<byte> buffer, int stride, int bytesPerPixel, int x, int y, int pixelHeight, int pixelWidth)
{
if (x < 0 || x >= pixelWidth)
return true;
if (y < 0 || y >= pixelHeight)
return true;
int i = stride * y + bytesPerPixel * x;
byte b = buffer[i];
byte g = buffer[i + 1];
byte r = buffer[i + 2];
return b + g + r == 0;
}
public static string ParseServerString(string input)
{
string result = input;
foreach (Match match in Regex.Matches(input, "{{[^{}]+}}"))
{
string key = match.Value[2..^2];
object dictValue = Application.Current.TryFindResource($"ServerString##{key}");
if (dictValue is string str)
{
result = result.Replace(match.Value, str);
}
}
return result;
}
public static string GetLanguageOnlyString(string? language = null)
{
language ??= Settings.Default.Language;
string[] splits = language.Split("-");
return splits.Length == 0 ? "zh" : splits[0];
}
}