diff --git a/Comic_Compressor/Comic_Compressor.csproj b/Comic_Compressor/Comic_Compressor.csproj
index 0ddd65d..53a091a 100644
--- a/Comic_Compressor/Comic_Compressor.csproj
+++ b/Comic_Compressor/Comic_Compressor.csproj
@@ -11,21 +11,14 @@
-
+
-
-
- PreserveNewest
-
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
@@ -44,9 +37,6 @@
Never
-
- PreserveNewest
-
diff --git a/Comic_Compressor/JxlCompressor.cs b/Comic_Compressor/JxlCompressor.cs
new file mode 100644
index 0000000..1d275ac
--- /dev/null
+++ b/Comic_Compressor/JxlCompressor.cs
@@ -0,0 +1,116 @@
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.Processing;
+using ShellProgressBar;
+
+namespace Comic_Compressor
+{
+ internal class JxlCompressor
+ {
+ internal static void CompressImages(string sourceImagePath, string targetStoragePath, int threadCount)
+ {
+ // Step 1: Get all subdirectories and store them in a list
+ List subdirectories = new(Directory.GetDirectories(sourceImagePath, "*", SearchOption.AllDirectories));
+
+ int totalFiles = 0;
+ foreach (string subdirectory in subdirectories)
+ {
+ totalFiles += GetImageFiles(subdirectory).Length;
+ }
+
+ using var progressBar = new ShellProgressBar.ProgressBar(totalFiles, "Compressing images", new ProgressBarOptions
+ {
+ ProgressCharacter = '─',
+ ProgressBarOnBottom = true
+ });
+
+ // Step 2: Iterate through each subdirectory in order
+ foreach (string subdirectory in subdirectories)
+ {
+ // Step 3: Process each directory
+ ProcessDirectory(subdirectory, sourceImagePath, targetStoragePath, progressBar, threadCount);
+ }
+
+ Console.WriteLine("All directories processed successfully.");
+ }
+
+ private static void ProcessDirectory(string subdirectory, string sourceImagePath, string targetStoragePath, ShellProgressBar.ProgressBar progressBar, int threadCount)
+ {
+ // Get the relative path of the subdirectory
+ string relativePath = Path.GetRelativePath(sourceImagePath, subdirectory);
+
+ // Create the corresponding subdirectory in the target storage path
+ string targetSubdirectory = Path.Combine(targetStoragePath, relativePath);
+ Directory.CreateDirectory(targetSubdirectory);
+
+ // Get all image files in the subdirectory (jpg and png)
+ string[] imageFiles = GetImageFiles(subdirectory);
+
+ // Set up ParallelOptions to limit the number of concurrent threads
+ ParallelOptions options = new()
+ {
+ MaxDegreeOfParallelism = threadCount // Adjust this value to set the number of concurrent threads
+ };
+
+ // Process each image file in parallel
+ Parallel.ForEach(imageFiles, options, imageFile =>
+ {
+ // Set the target file path with the .webp extension
+ string targetFilePath = Path.Combine(targetSubdirectory, Path.GetFileNameWithoutExtension(imageFile) + ".webp");
+
+ // Check if the target file already exists
+ if (!File.Exists(targetFilePath))
+ {
+ CompressImage(imageFile, targetFilePath);
+
+ // Update progress bar safely
+ lock (progressBar)
+ {
+ progressBar.Tick($"Processed {Path.GetFileName(imageFile)}");
+ }
+ }
+ else
+ {
+ lock (progressBar) { progressBar.Tick($"Skipped {Path.GetFileName(imageFile)}"); }
+ }
+ });
+ }
+
+ private static string[] GetImageFiles(string directoryPath)
+ {
+ // Get all image files supported by ImageSharp
+ string[] supportedExtensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff", "*.gif"];
+ List allFiles = [];
+
+ foreach (string extension in supportedExtensions)
+ {
+ allFiles.AddRange(Directory.GetFiles(directoryPath, extension, SearchOption.TopDirectoryOnly));
+ }
+
+ return [.. allFiles];
+ }
+
+ private static void CompressImage(string sourceFilePath, string targetFilePath)
+ {
+ using SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(sourceFilePath);
+ // Check the longest side of the image and resize if necessary
+ int maxDimension = Math.Max(image.Width, image.Height);
+ if (maxDimension > 1200)
+ {
+ double scaleFactor = 1200.0 / maxDimension;
+ int newWidth = (int)(image.Width * scaleFactor);
+ int newHeight = (int)(image.Height * scaleFactor);
+ image.Mutate(x => x.Resize(newWidth, newHeight));
+ }
+
+ // Save the image as WebP with a quality level of 85 (for lossy compression)
+ var encoder = new WebpEncoder
+ {
+ Quality = 90,
+ FileFormat = WebpFileFormatType.Lossy
+ };
+
+ image.Save(targetFilePath, encoder);
+ }
+ }
+}
diff --git a/Comic_Compressor/LegacyFormatCompressor.cs b/Comic_Compressor/LegacyFormatCompressor.cs
new file mode 100644
index 0000000..e8e3e52
--- /dev/null
+++ b/Comic_Compressor/LegacyFormatCompressor.cs
@@ -0,0 +1,116 @@
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Webp;
+using SixLabors.ImageSharp.Processing;
+using ShellProgressBar;
+
+namespace Comic_Compressor
+{
+ internal class LegacyFormatCompressor
+ {
+ internal static void CompressImages(string sourceImagePath, string targetStoragePath, int threadCount, int targetFormat)
+ {
+ // Step 1: Get all subdirectories and store them in a list
+ List subdirectories = new(Directory.GetDirectories(sourceImagePath, "*", SearchOption.AllDirectories));
+
+ int totalFiles = 0;
+ foreach (string subdirectory in subdirectories)
+ {
+ totalFiles += GetImageFiles(subdirectory).Length;
+ }
+
+ using var progressBar = new ShellProgressBar.ProgressBar(totalFiles, "Compressing images", new ProgressBarOptions
+ {
+ ProgressCharacter = '─',
+ ProgressBarOnBottom = true
+ });
+
+ // Step 2: Iterate through each subdirectory in order
+ foreach (string subdirectory in subdirectories)
+ {
+ // Step 3: Process each directory
+ ProcessDirectory(subdirectory, sourceImagePath, targetStoragePath, progressBar, threadCount);
+ }
+
+ Console.WriteLine("All directories processed successfully.");
+ }
+
+ private static void ProcessDirectory(string subdirectory, string sourceImagePath, string targetStoragePath, ShellProgressBar.ProgressBar progressBar, int threadCount)
+ {
+ // Get the relative path of the subdirectory
+ string relativePath = Path.GetRelativePath(sourceImagePath, subdirectory);
+
+ // Create the corresponding subdirectory in the target storage path
+ string targetSubdirectory = Path.Combine(targetStoragePath, relativePath);
+ Directory.CreateDirectory(targetSubdirectory);
+
+ // Get all image files in the subdirectory (jpg and png)
+ string[] imageFiles = GetImageFiles(subdirectory);
+
+ // Set up ParallelOptions to limit the number of concurrent threads
+ ParallelOptions options = new()
+ {
+ MaxDegreeOfParallelism = threadCount // Adjust this value to set the number of concurrent threads
+ };
+
+ // Process each image file in parallel
+ Parallel.ForEach(imageFiles, options, imageFile =>
+ {
+ // Set the target file path with the .webp extension
+ string targetFilePath = Path.Combine(targetSubdirectory, Path.GetFileNameWithoutExtension(imageFile) + ".webp");
+
+ // Check if the target file already exists
+ if (!File.Exists(targetFilePath))
+ {
+ CompressImage(imageFile, targetFilePath);
+
+ // Update progress bar safely
+ lock (progressBar)
+ {
+ progressBar.Tick($"Processed {Path.GetFileName(imageFile)}");
+ }
+ }
+ else
+ {
+ lock (progressBar) { progressBar.Tick($"Skipped {Path.GetFileName(imageFile)}"); }
+ }
+ });
+ }
+
+ private static string[] GetImageFiles(string directoryPath)
+ {
+ // Get all image files supported by ImageSharp
+ string[] supportedExtensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff", "*.gif"];
+ List allFiles = [];
+
+ foreach (string extension in supportedExtensions)
+ {
+ allFiles.AddRange(Directory.GetFiles(directoryPath, extension, SearchOption.TopDirectoryOnly));
+ }
+
+ return [.. allFiles];
+ }
+
+ private static void CompressImage(string sourceFilePath, string targetFilePath)
+ {
+ using SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(sourceFilePath);
+ // Check the longest side of the image and resize if necessary
+ int maxDimension = Math.Max(image.Width, image.Height);
+ if (maxDimension > 1200)
+ {
+ double scaleFactor = 1200.0 / maxDimension;
+ int newWidth = (int)(image.Width * scaleFactor);
+ int newHeight = (int)(image.Height * scaleFactor);
+ image.Mutate(x => x.Resize(newWidth, newHeight));
+ }
+
+ // Save the image as WebP with a quality level of 85 (for lossy compression)
+ var encoder = new WebpEncoder
+ {
+ Quality = 90,
+ FileFormat = WebpFileFormatType.Lossy
+ };
+
+ image.Save(targetFilePath, encoder);
+ }
+ }
+}
diff --git a/Comic_Compressor/MixProcessor.cs b/Comic_Compressor/MixProcessor.cs
new file mode 100644
index 0000000..fe148fe
--- /dev/null
+++ b/Comic_Compressor/MixProcessor.cs
@@ -0,0 +1,111 @@
+namespace Comic_Compressor
+{
+ internal class MixProcessor
+ {
+ internal static void CompressImages(string sourceImagePath, string targetStoragePath, int threadCount, int targetFormat)
+ {
+ // Step 1: Get all subdirectories and store them in a list
+ List subdirectories = new(Directory.GetDirectories(sourceImagePath, "*", SearchOption.AllDirectories));
+
+ int totalFiles = 0;
+ foreach (string subdirectory in subdirectories)
+ {
+ totalFiles += GetImageFiles(subdirectory).Length;
+ }
+
+ using var progressBar = new ShellProgressBar.ProgressBar(totalFiles, "Compressing images", new ProgressBarOptions
+ {
+ ProgressCharacter = '─',
+ ProgressBarOnBottom = true
+ });
+
+ // Step 2: Iterate through each subdirectory in order
+ foreach (string subdirectory in subdirectories)
+ {
+ // Step 3: Process each directory
+ ProcessDirectory(subdirectory, sourceImagePath, targetStoragePath, progressBar, threadCount);
+ }
+
+ Console.WriteLine("All directories processed successfully.");
+ }
+
+ private static void ProcessDirectory(string subdirectory, string sourceImagePath, string targetStoragePath, ShellProgressBar.ProgressBar progressBar, int threadCount)
+ {
+ // Get the relative path of the subdirectory
+ string relativePath = Path.GetRelativePath(sourceImagePath, subdirectory);
+
+ // Create the corresponding subdirectory in the target storage path
+ string targetSubdirectory = Path.Combine(targetStoragePath, relativePath);
+ Directory.CreateDirectory(targetSubdirectory);
+
+ // Get all image files in the subdirectory (jpg and png)
+ string[] imageFiles = GetImageFiles(subdirectory);
+
+ // Set up ParallelOptions to limit the number of concurrent threads
+ ParallelOptions options = new()
+ {
+ MaxDegreeOfParallelism = threadCount // Adjust this value to set the number of concurrent threads
+ };
+
+ // Process each image file in parallel
+ Parallel.ForEach(imageFiles, options, imageFile =>
+ {
+ // Set the target file path with the .webp extension
+ string targetFilePath = Path.Combine(targetSubdirectory, Path.GetFileNameWithoutExtension(imageFile) + ".webp");
+
+ // Check if the target file already exists
+ if (!File.Exists(targetFilePath))
+ {
+ CompressImage(imageFile, targetFilePath);
+
+ // Update progress bar safely
+ lock (progressBar)
+ {
+ progressBar.Tick($"Processed {Path.GetFileName(imageFile)}");
+ }
+ }
+ else
+ {
+ lock (progressBar) { progressBar.Tick($"Skipped {Path.GetFileName(imageFile)}"); }
+ }
+ });
+ }
+
+ private static string[] GetImageFiles(string directoryPath)
+ {
+ // Get all image files supported by ImageSharp
+ string[] supportedExtensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff", "*.gif"];
+ List allFiles = [];
+
+ foreach (string extension in supportedExtensions)
+ {
+ allFiles.AddRange(Directory.GetFiles(directoryPath, extension, SearchOption.TopDirectoryOnly));
+ }
+
+ return [.. allFiles];
+ }
+
+ private static void CompressImage(string sourceFilePath, string targetFilePath)
+ {
+ using SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(sourceFilePath);
+ // Check the longest side of the image and resize if necessary
+ int maxDimension = Math.Max(image.Width, image.Height);
+ if (maxDimension > 1200)
+ {
+ double scaleFactor = 1200.0 / maxDimension;
+ int newWidth = (int)(image.Width * scaleFactor);
+ int newHeight = (int)(image.Height * scaleFactor);
+ image.Mutate(x => x.Resize(newWidth, newHeight));
+ }
+
+ // Save the image as WebP with a quality level of 85 (for lossy compression)
+ var encoder = new WebpEncoder
+ {
+ Quality = 90,
+ FileFormat = WebpFileFormatType.Lossy
+ };
+
+ image.Save(targetFilePath, encoder);
+ }
+ }
+}
diff --git a/Comic_Compressor/Program.cs b/Comic_Compressor/Program.cs
index d8fcbf4..5f454e6 100644
--- a/Comic_Compressor/Program.cs
+++ b/Comic_Compressor/Program.cs
@@ -17,7 +17,7 @@ namespace Comic_Compressor
return;
}
- Console.WriteLine("请输入目标存储位置:");
+ Console.WriteLine("请选择保存位置:");
string? targetStoragePath = GetFolderPath();
if (string.IsNullOrEmpty(targetStoragePath))
{
@@ -29,7 +29,7 @@ namespace Comic_Compressor
int threadCount = int.Parse(Console.ReadLine() ?? "2");
Console.WriteLine($"处理线程数设定:{threadCount}");
- Console.WriteLine("请选择压缩模式:0 - 压缩成webp,1 - 压缩成avif");
+ Console.WriteLine("目标格式:0 - webp, 1 - avif, 2 - JXL(JPEG-XL), 3 - JPG, 4 - PNG, 5 - 保留原格式(best effort)");
string? modeInput = Console.ReadLine();
if (modeInput == null)
{
@@ -47,12 +47,24 @@ namespace Comic_Compressor
AvifCompressor.CompressImages(sourceImagePath, targetStoragePath, threadCount);
GetCompressorResult(sourceImagePath, targetStoragePath);
break;
+ case "2":
+ JxlCompressor.CompressImages(sourceImagePath, targetStoragePath, threadCount);
+ GetCompressorResult(sourceImagePath, targetStoragePath);
+ break;
+ case "3":
+ case "4":
+ LegacyFormatCompressor.CompressImages(sourceImagePath, targetStoragePath, threadCount,int.Parse(modeInput));
+ GetCompressorResult(sourceImagePath, targetStoragePath);
+ break;
+ case "5":
+ throw new NotImplementedException();
default:
- Console.WriteLine("不支持的模式");
+ Console.WriteLine("不支持的格式");
break;
}
}
+
private static string? GetFolderPath()
{
using var dialog = new FolderBrowserDialog();
@@ -74,10 +86,8 @@ namespace Comic_Compressor
{
long size = 0;
- // 遍历目录中的所有文件
foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories))
{
- // 获取文件的大小并累加到总大小中
FileInfo fileInfo = new(file);
size += fileInfo.Length;
}
@@ -85,15 +95,30 @@ namespace Comic_Compressor
return size;
}
+ private static string GetHumanReadableSize(long size)
+ {
+ string[] sizes = { "B", "KB", "MB", "GB", "TB" };
+ double len = size;
+ int order = 0;
+ while (len >= 1024 && order < sizes.Length - 1)
+ {
+ order++;
+ len = len / 1024;
+ }
+
+ return $"{len:0.##} {sizes[order]}";
+ }
+
+
private static void GetCompressorResult(string source, string target)
{
long sourceSize = GetDirectorySize(source);
long targetSize = GetDirectorySize(target);
double reduced = (sourceSize - targetSize) * 1.0 / sourceSize;
- Console.WriteLine($"源目录大小:{sourceSize} 字节");
- Console.WriteLine($"目标目录大小:{targetSize} 字节");
- Console.WriteLine($"已减少:{reduced:P}的体积");
+ Console.WriteLine($"压缩前大小:{GetHumanReadableSize(sourceSize)}");
+ Console.WriteLine($"压缩后大小:{GetHumanReadableSize(targetSize)}");
+ Console.WriteLine($"体积已减少{reduced:P}");
}
}
diff --git a/Comic_Compressor/aom.dll b/Comic_Compressor/aom.dll
deleted file mode 100644
index e69a1e5..0000000
Binary files a/Comic_Compressor/aom.dll and /dev/null differ
diff --git a/Comic_Compressor/dav1d.dll b/Comic_Compressor/dav1d.dll
deleted file mode 100644
index c313084..0000000
Binary files a/Comic_Compressor/dav1d.dll and /dev/null differ
diff --git a/Comic_Compressor/libde265.dll b/Comic_Compressor/libde265.dll
deleted file mode 100644
index d557151..0000000
Binary files a/Comic_Compressor/libde265.dll and /dev/null differ
diff --git a/Comic_Compressor/libheif.dll b/Comic_Compressor/libheif.dll
deleted file mode 100644
index e8068fe..0000000
Binary files a/Comic_Compressor/libheif.dll and /dev/null differ
diff --git a/Comic_Compressor/libx265.dll b/Comic_Compressor/libx265.dll
deleted file mode 100644
index 6992a31..0000000
Binary files a/Comic_Compressor/libx265.dll and /dev/null differ