209 lines
6.4 KiB
C#
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];
|
|
}
|
|
} |