From 3860b1bd549c98410a6f8254b62d44d1e4c98e85 Mon Sep 17 00:00:00 2001 From: Chenx221 Date: Mon, 26 Aug 2024 17:19:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Comic_Compressor.sln | 31 +++++++++ Comic_Compressor/AvifCompressor.cs | 17 +++++ Comic_Compressor/Comic_Compressor.csproj | 17 +++++ Comic_Compressor/Program.cs | 67 +++++++++++++++++++ Comic_Compressor/WebpCompressor.cs | 82 ++++++++++++++++++++++++ 5 files changed, 214 insertions(+) create mode 100644 Comic_Compressor.sln create mode 100644 Comic_Compressor/AvifCompressor.cs create mode 100644 Comic_Compressor/Comic_Compressor.csproj create mode 100644 Comic_Compressor/Program.cs create mode 100644 Comic_Compressor/WebpCompressor.cs diff --git a/Comic_Compressor.sln b/Comic_Compressor.sln new file mode 100644 index 0000000..8bcfa2c --- /dev/null +++ b/Comic_Compressor.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35219.272 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Comic_Compressor", "Comic_Compressor\Comic_Compressor.csproj", "{B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Debug|x64.ActiveCfg = Debug|x64 + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Debug|x64.Build.0 = Debug|x64 + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Release|Any CPU.Build.0 = Release|Any CPU + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Release|x64.ActiveCfg = Release|x64 + {B6B0E3D8-DE3D-4A7D-AAE5-34953ABFEA2A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FA1DD3CC-0702-404F-9D7F-40EB2736F8AD} + EndGlobalSection +EndGlobal diff --git a/Comic_Compressor/AvifCompressor.cs b/Comic_Compressor/AvifCompressor.cs new file mode 100644 index 0000000..68c4cff --- /dev/null +++ b/Comic_Compressor/AvifCompressor.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Comic_Compressor +{ + internal class AvifCompressor + { + internal static void CompressImages(string sourceImagePath, string targetStoragePath) + { + //尚未实现 + throw new NotImplementedException(); + } + } +} diff --git a/Comic_Compressor/Comic_Compressor.csproj b/Comic_Compressor/Comic_Compressor.csproj new file mode 100644 index 0000000..b3aedb2 --- /dev/null +++ b/Comic_Compressor/Comic_Compressor.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0-windows + enable + enable + AnyCPU;x64 + True + + + + + + + + diff --git a/Comic_Compressor/Program.cs b/Comic_Compressor/Program.cs new file mode 100644 index 0000000..bd039c4 --- /dev/null +++ b/Comic_Compressor/Program.cs @@ -0,0 +1,67 @@ +using System.Text; +using System.Windows.Forms; +namespace Comic_Compressor +{ + internal class Program + { + [STAThread] + static void Main() + { + Console.OutputEncoding = Encoding.UTF8; + + Console.WriteLine("请选择源图像所在位置:"); + string? sourceImagePath = GetFolderPath(); + if (string.IsNullOrEmpty(sourceImagePath)) + { + Console.WriteLine("未选择文件夹,程序将退出。"); + return; + } + + Console.WriteLine("请输入目标存储位置:"); + string? targetStoragePath = GetFolderPath(); + if (string.IsNullOrEmpty(targetStoragePath)) + { + Console.WriteLine("未选择文件夹,程序将退出。"); + return; + } + + Console.WriteLine("请选择压缩模式:0 - 压缩成webp,1 - 压缩成avif"); + string? modeInput = Console.ReadLine(); + if (modeInput == null) + { + Console.WriteLine("无效输入"); + return; + } + + switch (modeInput) + { + case "0": + WebpCompressor.CompressImages(sourceImagePath, targetStoragePath); + break; + case "1": + AvifCompressor.CompressImages(sourceImagePath, targetStoragePath); + break; + default: + Console.WriteLine("不支持的模式"); + break; + } + } + + private static string? GetFolderPath() + { + using var dialog = new FolderBrowserDialog(); + dialog.ShowNewFolderButton = false; + + DialogResult result = dialog.ShowDialog(); + + if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(dialog.SelectedPath)) + { + return dialog.SelectedPath; + } + else + { + return null; + } + } + } +} diff --git a/Comic_Compressor/WebpCompressor.cs b/Comic_Compressor/WebpCompressor.cs new file mode 100644 index 0000000..7eee2c0 --- /dev/null +++ b/Comic_Compressor/WebpCompressor.cs @@ -0,0 +1,82 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Webp; +using SixLabors.ImageSharp.Processing; + +namespace Comic_Compressor +{ + internal class WebpCompressor + { + internal static void CompressImages(string sourceImagePath, string targetStoragePath) + { + // Step 1: Get all subdirectories and store them in a list + List subdirectories = new(Directory.GetDirectories(sourceImagePath, "*", SearchOption.AllDirectories)); + + // Step 2: Iterate through each subdirectory in order + foreach (string subdirectory in subdirectories) + { + // Step 3: Process each directory + ProcessDirectory(subdirectory, sourceImagePath, targetStoragePath); + } + } + + private static void ProcessDirectory(string subdirectory, string sourceImagePath, string targetStoragePath) + { + // 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); + + // Iterate through each image file + foreach (string imageFile in imageFiles) + { + // Set the target file path with the .webp extension + string targetFilePath = Path.Combine(targetSubdirectory, Path.GetFileNameWithoutExtension(imageFile) + ".webp"); + CompressImage(imageFile, targetFilePath); + } + + Console.WriteLine($"{Path.GetFileName(subdirectory)} processed successfully."); + } + + private static string[] GetImageFiles(string directoryPath) + { + // Get all image files supported by ImageSharp + string[] supportedExtensions = ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff"]; + 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 70 (for lossy compression) + var encoder = new WebpEncoder + { + Quality = 70, + FileFormat = WebpFileFormatType.Lossy + }; + + image.Save(targetFilePath, encoder); + } + } +}