From 320550399d491fe5136248eb858fb81b79976779 Mon Sep 17 00:00:00 2001 From: wucl12 Date: Mon, 2 Feb 2026 21:56:45 +0800 Subject: [PATCH] Init --- .gitattributes | 63 ++ .gitignore | 363 +++++++++ App.config | 6 + Compressor/CountProgress.cs | 88 +++ Compressor/FilesManager.cs | 424 ++++++++++ Compressor/ImgPaths.cs | 29 + Compressor/ImgsProcess.cs | 239 ++++++ Compressor/JPGCompressor.cs | 366 +++++++++ ImageCompressor.csproj | 131 ++++ ImageCompressor.sln | 25 + MainForm/ImageCompressorForm.Designer.cs | 492 ++++++++++++ MainForm/ImageCompressorForm.cs | 867 +++++++++++++++++++++ MainForm/ImageCompressorForm.resx | 941 +++++++++++++++++++++++ MainForm/NewPictureBox.cs | 23 + MainForm/NewProgressPanel.cs | 71 ++ MainForm/Program.cs | 22 + MainForm/ZoomFactor.cs | 87 +++ Properties/AssemblyInfo.cs | 36 + Properties/Resources.Designer.cs | 63 ++ Properties/Resources.resx | 120 +++ Properties/Settings.Designer.cs | 26 + Properties/Settings.settings | 7 + Resources/Icon.ico | Bin 0 -> 48903 bytes Utils/Localize.cs | 62 ++ 24 files changed, 4551 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 App.config create mode 100644 Compressor/CountProgress.cs create mode 100644 Compressor/FilesManager.cs create mode 100644 Compressor/ImgPaths.cs create mode 100644 Compressor/ImgsProcess.cs create mode 100644 Compressor/JPGCompressor.cs create mode 100644 ImageCompressor.csproj create mode 100644 ImageCompressor.sln create mode 100644 MainForm/ImageCompressorForm.Designer.cs create mode 100644 MainForm/ImageCompressorForm.cs create mode 100644 MainForm/ImageCompressorForm.resx create mode 100644 MainForm/NewPictureBox.cs create mode 100644 MainForm/NewProgressPanel.cs create mode 100644 MainForm/Program.cs create mode 100644 MainForm/ZoomFactor.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 Properties/Resources.Designer.cs create mode 100644 Properties/Resources.resx create mode 100644 Properties/Settings.Designer.cs create mode 100644 Properties/Settings.settings create mode 100644 Resources/Icon.ico create mode 100644 Utils/Localize.cs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/App.config b/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Compressor/CountProgress.cs b/Compressor/CountProgress.cs new file mode 100644 index 0000000..d3c6b1b --- /dev/null +++ b/Compressor/CountProgress.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + /// + /// 用来总的记录各个线程处理照片的进度,以及标记线程运行结果 + /// + class CountProgress + { + ImageCompressorForm owner; + public CountProgress(int totalCount, ImageCompressorForm owner) + { + this.TotalCount = totalCount; + this.owner = owner; + FailedInfos = new List(); + } + + + public ReaderWriterLock RWLock = new ReaderWriterLock(); + + /// + /// 总的处理了的照片数量 + /// + public int ProcessedCount => SuccessCount + FailedCount + SkipCount; + + /// + /// 处理过成功的照片数量 + /// + public int SuccessCount { get; set; } = 0; + + /// + /// 处理过失败的照片数量 + /// + public int FailedCount { get; set; } = 0; + + /// + /// 已经跳过的照片数量 + /// + public int SkipCount { get; set; } = 0; + + /// + /// 处理失败的信息 + /// + public List FailedInfos { get; set; } + /// + /// 需要处理的照片总数 + /// + public int TotalCount { get; private set; } + + /// + /// 是否已经处理完所有照片 + /// + public bool Finished => ProcessedCount == TotalCount; + + /// + /// 处理前照片的大小总和 + /// + public long PreSizeKBSum { get; set; } = 0; + /// + /// 压缩后照片的大小总和 + /// + public long PostSizeKBSum { get; set; } = 0; + /// + /// 计时器 + /// + public Stopwatch stopwatch { get; set; } = new Stopwatch(); + + /// + /// Update Data To Winform + /// + public void Update() + { + owner.SetProgressValue(ProcessedCount); + if (Finished) + { + stopwatch.Stop(); + owner.ShowReport(); + } + } + + } +} diff --git a/Compressor/FilesManager.cs b/Compressor/FilesManager.cs new file mode 100644 index 0000000..2009f73 --- /dev/null +++ b/Compressor/FilesManager.cs @@ -0,0 +1,424 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + /// + /// 后台线程运行状态 + /// + enum RunningState + { + NoFile, + Ready, + Running, + WaitStop, + AllThreadStoped, + Finished, + } + + /// + /// 管理读取IMG文件,并且负责Invoke压缩多线程 + /// + class FilesManager + { + + public bool IncludeSubFolders { get; set; } = true; + + + ImageCompressorForm owner { get; set; } + + + + public FilesManager(ImageCompressorForm owner) + { + this.owner = owner; + } + + #region Files + + /// + /// 储存读取的所有照片的Size + /// + public long PreAllImageSizeinKB { get; private set; } + + + /// + /// 所有的照片的路径(打开路径和储存路径) + /// + List ImgPathList { get; set; } = new List(); + /// + /// 总共有多少张照片 + /// + public int FilesCount => ImgPathList.Count; + + /// + /// 开始读取照片 + /// 从输入的文件夹里,提取出所有的照片路径 + /// + /// + public void ReadAllFilePaths(IEnumerable folders) + { + ImgPathList.Clear(); + processList = null; + PreAllImageSizeinKB = 0; + foreach (string folderPath in folders) + { + string[] files; + if (IncludeSubFolders) + files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories).Where(x => IsImg(x)).ToArray(); + else + files = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly).Where(x => IsImg(x)).ToArray(); + foreach (string file in files) { PreAllImageSizeinKB += new FileInfo(file).Length / 1024; } + DirectoryInfo info = new DirectoryInfo(folderPath); + string newFolder = Path.Combine(info.Parent.FullName, info.Name + Localize.Get("_Compressed")); + ImgPathList.AddRange(files.Select(x => new ImgPaths(x, x.Replace(folderPath, newFolder)))); + + } + progress = new CountProgress(ImgPathList.Count, owner); + } + + + + + static long skipFileSize = 900 * 1024; + bool IsImg(string fileName) + { + string extension = Path.GetExtension(fileName); + if (Path.GetFileName(fileName).StartsWith("._")) return false; + switch (extension.ToLower()) + { + case ".jpg": + case ".png": + case ".jpeg": + case ".bmp": + return true; + } + return false; + } + /// + /// 设定跳过的文件大小 + /// + /// + public void SetSkipFileSizeInKB(string textInKB) + { + if (int.TryParse(textInKB, out int result)) + skipFileSize = result * 1024; + } + + public int CurrentSkipFileSizeInKB => (int)(skipFileSize / 1024); + + /// + /// 判断是否需要跳过该文件 + /// + /// + /// + public static bool IsSkip(FileInfo fileInfo) + { + return fileInfo == null || fileInfo.Length < skipFileSize; + } + /// + /// 格式化显示大小 + /// + /// + /// + public string GetFileSizeString(long sizeInKB) + { + if (sizeInKB > 1048576) + return string.Format("{0:f2}GB", sizeInKB / 1048576.0); + else if (sizeInKB > 1024) + return string.Format("{0:f2}MB", sizeInKB / 1024.0); + else return string.Format("{0:f2}KB", sizeInKB); + } + + + #endregion + + #region Preview + + /// + /// 用于储存临时保存的预览压缩图片 + /// + string TempImgPath = Path.Combine(Path.GetTempPath(), "temp.jpg"); + + /// + /// 返回当前所有路径的随机序号,如果没有路径,return false + /// + /// + /// + /// + public bool GetRandomIndex(int seed, out int index) + { + if (FilesCount > 0) + { + Random random = new Random(seed); + index = random.Next(0, FilesCount); + return true; + } + + index = -1; + return false; + } + + public Image GetImageAtIndex(int index, out string fileSize) + { + FileInfo rawFile = ImgPathList[index].OriginalFileInfo; + if (rawFile.Exists) + { + try + { + using (FileStream stream = rawFile.OpenRead()) + { + Image raw = Image.FromStream(stream); + + fileSize = GetFileSizeString(stream.Length / 1024); + stream.Close(); + return raw; + } + } + catch (Exception ex) + { + fileSize = $"Cannot preview Image {rawFile.FullName}, {ex.Message}"; + return null; + } + } + else + { + fileSize = Localize.Get("Missing"); + return null; + } + } + + /// + /// 将列表中Index序号的图像进行压缩 + /// 储存到临时文件里去 + /// 然后读取该临时图片作为输出 + /// 失败返回null + /// skip时返回null,fileSize = null; + /// + /// + /// + /// + /// + public Image GetCompressedImgAtIndex(int index, out string fileSize, out bool skip, out string errorMessage) + { + + fileSize = null; + FileInfo rawFile = ImgPathList[index].OriginalFileInfo; + skip = IsSkip(rawFile); + if (skip) + { + + errorMessage = null; + return null; + } + JPGCompressor compressor = new JPGCompressor(this.CompressLevel, this.MaxWidth, this.MaxHeight); + + if (!compressor.ReadFileToImage(rawFile, out Bitmap image, out _, out errorMessage)) + { + return null; + } + Bitmap bitmap = compressor.CompressImgToBitmap(image); + //image.Dispose(); + if (compressor.SaveCompressBitmap(bitmap, new FileInfo(TempImgPath), out long saveSizeInKB, out errorMessage)) + { + fileSize = GetFileSizeString(saveSizeInKB); + } + else fileSize = Localize.Get("Estimate Fail"); + return bitmap; + + } + + #endregion + + #region MultiThread + /// + /// 储存照片时是否保留源文件 + /// + public bool KeepOriginal { get; set; } = true; + int compressLevel = 8; + /// + /// 当前的压缩级数 + /// + public int CompressLevel + { + get + { + return compressLevel; + } + set + { + compressLevel = value; + MaxWidth = JPGCompressor.CompressionLevelToMaxWidth(compressLevel); + MaxHeight = JPGCompressor.CompressionLevelToMaxHeight(compressLevel); + } + } + /// + /// 当前的最大宽度 + /// + public int MaxWidth { get; set; } + /// + /// 当前的最大高度 + /// + public int MaxHeight { get; set; } + + + /// + /// 向Winform标记运行状态 + /// + public RunningState State + { + get + { + if(FilesCount == 0) + { + return RunningState.NoFile; + } + else if (processList == null) + { + return RunningState.Ready; + } + else if (progress.Finished) return RunningState.Finished; + else + { + foreach (ImgsProcess process in processList) + { + if (!process.Stoped) + { + if(process.ToStop)return RunningState.WaitStop; + return RunningState.Running; + } + } + return RunningState.AllThreadStoped; + } + } + } + + /// + /// 用来储存多线程运行过程数据和结果 + /// + internal CountProgress progress; + + /// + /// 所有线程运行数据 + /// + ImgsProcess[] processList; + + /// + /// 多线程常量,增加貌似并没有加速很多,猜测卡在JPG的IO读取上。 + /// + public const int ThreadCount = 16; + + /// + /// 正式压缩所有图片 + /// 返回线程数 + /// + public void RunAllCompress() + { + //运行后不能修改KeepOriginal,CompressLevel + foreach (ImgPaths path in ImgPathList) path.KeepOriginal = KeepOriginal; + + + + //将所有的图片Path,平均分配到【线程数】个ProcessImgs里 + + if (State == RunningState.Ready) + { + progress.stopwatch.Restart(); + processList = DivideIntoMultiProcess(); + } + else progress.stopwatch.Start(); + //另一种情况是Stoped,就继续上次计算 + + foreach(ImgsProcess process in processList) + { + //一旦开始了运行,再修改的参数就不影响了 + process.SetCompressLevel(this.CompressLevel, this.MaxWidth, this.MaxHeight); + } + + + Thread[] threads = processList.Select(x => new Thread(x.Start)).ToArray(); + foreach (Thread thread in threads) + { + thread.Start(); + + } + } + + /// + /// 等待所有线程结束之后再弹出Report + /// + void StopAsync() + { + while (true) + { + int stopCount = 0; + foreach (ImgsProcess process in processList) + { + if (process.Stoped) stopCount++; + else Thread.Sleep(100); + } + if (stopCount == processList.Length) break; + } + progress.stopwatch.Stop(); + owner.ShowReport(); + } + /// + /// 停止所有计算。 + /// 先设定ToStop状态 + /// 然后等所有线程计算结束后再停止弹出Report + /// + public void Stop() + { + foreach (ImgsProcess process in processList) + { + if (process.ToStop) return; + process.ToStop = true; + } + owner.UpdateRunButtonText(); + // 等待所有线程结束之后再弹出Report + new Thread(StopAsync).Start(); + } + /// + /// 多线程分工方法 + /// + /// + private ImgsProcess[] DivideIntoMultiProcess() + { + List imgsProcess = new List(); + List> splitImgPath = new List>(); + for (int t = 0; t < ThreadCount; t++) + { + splitImgPath.Add(new List()); + } + int count = ImgPathList.Count; + + for (int i = 0; i < count; i++) + { + int threadIndex = i % ThreadCount; + splitImgPath[threadIndex].Add(ImgPathList[i]); + } + + int index = 0; + for (int t = 0; t < ThreadCount; t++) + { + if (splitImgPath[t].Count > 0) + { + imgsProcess.Add(new ImgsProcess(index++, splitImgPath[t], progress)); + } + } + + return imgsProcess.ToArray(); + } + + #endregion + } +} diff --git a/Compressor/ImgPaths.cs b/Compressor/ImgPaths.cs new file mode 100644 index 0000000..f30b900 --- /dev/null +++ b/Compressor/ImgPaths.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + /// + /// 一张照片的打开路径和储存路径 + /// + class ImgPaths + { + public bool KeepOriginal { get; set; } = true; + public FileInfo OriginalFileInfo { get; private set; } + public FileInfo DuplicatedFileInfo { get; private set; } + public ImgPaths(string readPath, string writePath) + { + OriginalFileInfo = new FileInfo(readPath); + string extension = Path.GetExtension(writePath).ToLower(); + if(extension != ".jpg" || extension !=".jpeg") + { + Path.ChangeExtension(writePath, ".jpg"); + } + this.DuplicatedFileInfo = new FileInfo(writePath); + } + } +} diff --git a/Compressor/ImgsProcess.cs b/Compressor/ImgsProcess.cs new file mode 100644 index 0000000..d9f9f2e --- /dev/null +++ b/Compressor/ImgsProcess.cs @@ -0,0 +1,239 @@ +//#define NoOutput +using System; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics; +using System.Dynamic; + +namespace ImageCompressor +{ + + /// + /// 一个单独的线程,来批量压缩图片 + /// + class ImgsProcess + { + + /// + /// 这个压缩进程内的所有压缩图片的路径 + /// + ImgPaths[] ImgPaths { get; set; } + + /// + /// 计数当前线程编号,用于Debug + /// + public int threadIndex=-1; + + /// + /// 引用的进度总控 + /// + readonly CountProgress progress; + + int currentIndex = 0; + + /// + /// 设定是否要在过程中停止计算,标记为停止后,等待计算停止 + /// + public bool ToStop { get; set; } = false; + + /// + /// 判断是否所有计算已经停止 + /// + public bool Stoped { get; private set; } = false; + /// + /// 该线程处理的所有图片数量 + /// + public int AllCount { get; private set; } + + public ImgsProcess(int index, List imgPaths, CountProgress countProgress) + { + threadIndex = index; + ImgPaths = imgPaths.ToArray(); + AllCount = ImgPaths.Length; + this.progress = countProgress; + } + /// + /// 开始时设定所有的压缩参数 + /// + /// + /// + /// + public void SetCompressLevel(int compressLevel,int maxWidth, int maxHeight) + { + this.compressLevel = compressLevel; + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + } + + int compressLevel; + int maxWidth; + int maxHeight; + + /// + /// 用来传递每个Img压缩时候的数据 + /// + class DataPack + { + public DataPack(ImgPaths paths, JPGCompressor compressor) + { + this.compressor = compressor; + this.imgPaths = paths; + } + public JPGCompressor compressor; + public ImgPaths imgPaths; + public byte[] readBytes = null; + public byte[] saveBytes = null; + } +#if DEBUG + + double Tick => Math.Round(DateTime.Now.TimeOfDay.TotalSeconds % 1000, 3); +#endif + public void Start() + { + Stoped = false; + ToStop = false; + ResetCountData(); + while (currentIndex < AllCount) + { +#if DEBUG + long t1 = progress.stopwatch.ElapsedMilliseconds; +#endif + DataPack dataPack = new DataPack(ImgPaths[currentIndex],new JPGCompressor(compressLevel,maxWidth,maxHeight)); + ReadOneImage(dataPack); + CompressCurrent(dataPack); + WriteOneImage(dataPack); +#if DEBUG + long t2 = progress.stopwatch.ElapsedMilliseconds; +#endif + progress.RWLock.AcquireWriterLock(-1); + UpdateCountProgress(); + ResetCountData(); + Thread.Sleep(25); + progress.RWLock.ReleaseWriterLock(); +#if DEBUG + + Debug.WriteLine($"thread {threadIndex} count {currentIndex}, from {t1}, used {t2 - t1}"); +#endif + currentIndex++; + if (ToStop) + { + Stoped = true; + return; + } + } + Stoped = true; + } + + //当前线程运行的结果变量 + int successCount = 0; + int failedCount = 0; + List failedPaths = new List(); + int skipCount = 0; + long preSizeKB = 0; + long saveSizeKB = 0; + + /// + /// 重置当前线程运行的结果变量 + /// + void ResetCountData() + { + successCount = 0; + failedCount = 0; + failedPaths.Clear(); + skipCount = 0; + preSizeKB = 0; + saveSizeKB = 0; + } + /// + /// 读照片到DataPack + /// + /// + void ReadOneImage(DataPack dataPack) + { + ImgPaths imgPaths = dataPack.imgPaths; + if(!imgPaths.OriginalFileInfo.Exists) + { + failedCount++; + failedPaths.Add(Localize.Get("Read file missing") + imgPaths.OriginalFileInfo.FullName); + return; + } + preSizeKB += imgPaths.OriginalFileInfo.Length / 1024; + if (FilesManager.IsSkip(imgPaths.OriginalFileInfo)) + { + skipCount++; + return; + } + dataPack.readBytes = dataPack.compressor.ReadFileToBytes(imgPaths.OriginalFileInfo, out string error); + if (dataPack.readBytes == null) + { + failedCount++; + failedPaths.Add(error + imgPaths.OriginalFileInfo.FullName); + } + } + + /// + /// 压缩得到文件的Bytes + /// + /// + void CompressCurrent(DataPack dataPack) + { + if (dataPack.readBytes != null) + { + dataPack.saveBytes = dataPack.compressor.CompressBytes(dataPack.readBytes,out string error); + if(dataPack.saveBytes == null) + { + failedCount++; + failedPaths.Add(error + dataPack.imgPaths.OriginalFileInfo.FullName); + } + } + } + + /// + /// 写Bytes到文件 + /// + /// + void WriteOneImage(DataPack dataPack) + { + if (dataPack.saveBytes != null) + { + bool keepOriginal = dataPack.imgPaths.KeepOriginal; + FileInfo saveFile = keepOriginal ? dataPack.imgPaths.DuplicatedFileInfo : dataPack.imgPaths.OriginalFileInfo; + + bool re = dataPack.compressor.SaveCompressBytes(dataPack.saveBytes, saveFile, out string error); + if (re) + { + saveSizeKB += dataPack.saveBytes.LongLength / 1024; + successCount++; + } + else + { + failedCount++; + failedPaths.Add(error + dataPack.imgPaths.DuplicatedFileInfo.FullName); + } + } + } + + /// + /// 将本线程结果更新到progress的结果 + /// + void UpdateCountProgress() + { + if (progress.Finished) return; + progress.SuccessCount += successCount; + progress.FailedCount+= failedCount; + progress.SkipCount += skipCount; + progress.FailedInfos.AddRange(failedPaths); + progress.PreSizeKBSum+= preSizeKB; + progress.PostSizeKBSum += saveSizeKB; + progress.Update(); + } + + + } +} diff --git a/Compressor/JPGCompressor.cs b/Compressor/JPGCompressor.cs new file mode 100644 index 0000000..cdb588b --- /dev/null +++ b/Compressor/JPGCompressor.cs @@ -0,0 +1,366 @@ + +using System; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Diagnostics; + +namespace ImageCompressor +{ + /// + /// 单张JPG的压缩运算 + /// + class JPGCompressor + { + int compressLevel; + int MaxWidth; + int MaxHeight; + long Quality; + + ImageCodecInfo jpegEncoder; + EncoderParameters jpeParameters; + + public JPGCompressor(int compressLevel, int maxWidth,int maxHeight) + { + CompressLevel= compressLevel; + MaxWidth = maxWidth; + MaxHeight = maxHeight; + + } + /// + /// 设定压缩质量 + /// + public int CompressLevel + { + get { return compressLevel; } + private set + { + compressLevel = value; + Quality = compressLevel * 5 + 50; //(50-100) + if (!SetJpegCompressor()) throw new Exception("Cannot Create JPG Comporessor"); + } + } + + public static int CompressionLevelToMaxWidth(int level) + { + return Math.Max((int)(1920 * (level * 0.2)), 480);//480-3840 + } + public static int CompressionLevelToMaxHeight(int level) + { + return Math.Max((int)(1080 * (level * 0.2)), 360);//360-2160 + } + + + + + #region CompressBytes + + /// + /// 储存Bitmap到JPG文件。 + /// 之后释放 writeBitmap + /// + public bool SaveCompressBytes(byte[] saveBytes, FileInfo saveFile, out string errorMessage) + { + errorMessage = null; + if (saveFile.Exists) + { + if (saveFile.IsReadOnly) + { + errorMessage = Localize.Get("Save file is ReadOnly. "); + return false; + } + } + else + { + DirectoryInfo directory = saveFile.Directory; + if (!directory.Exists) + { + try + { + directory.Create(); + } + catch + { + errorMessage = Localize.Get("Cannot create save folder. "); + return false; + } + } + } + try + { + File.WriteAllBytes(saveFile.FullName, saveBytes); + return true; + + } + catch (Exception ex) + { + if (ex is IOException) + { + errorMessage = Localize.Get("Save file is occupied. "); + return false; + } + errorMessage = Localize.Get("Save file error at ")+$"{ex.Message}"; + return false; + } + } + + /// + /// 打开一个Image文件,返回Bytes + /// + /// + public byte[] ReadFileToBytes(FileInfo readFile, out string errorMessage) + { + errorMessage = null; + if (!readFile.Exists) + { + errorMessage = Localize.Get("Read file not exist. "); + return null; + } + if(readFile.Length > 1024 * 1024 * 256) + { + errorMessage = Localize.Get("Read image larger than 256 MB"); + return null; + } + try + { + return File.ReadAllBytes(readFile.FullName); + } + catch (Exception ex) + { + errorMessage = Localize.Get("Read file error at ") + $"{ex.Message}"; + return null; + } + } + + + public byte[] CompressBytes(byte[] readBytes, out string errorMessage) + { + MemoryStream memoryStream = null; + MemoryStream saveMemoryStream = null; + Bitmap rawBit = null; + Graphics graphics = null; + Bitmap newBit = null; + + errorMessage = null; + try + { + memoryStream = new MemoryStream(readBytes, false); + saveMemoryStream = new MemoryStream(); + rawBit = new Bitmap(memoryStream); + memoryStream.Close(); + memoryStream.Dispose(); + double percentW = (double)MaxWidth / rawBit.Width; + double percentH = (double)MaxHeight / rawBit.Height; + double percent = Math.Min(percentW, percentH); + percent = Math.Min(1, percent); + if (percent < 1 || compressLevel < 10) + { + int newW = (int)(percent * rawBit.Width); + int newH = (int)(percent * rawBit.Height); + newBit = new Bitmap(newW, newH); + graphics = Graphics.FromImage(newBit); + + graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; + graphics.DrawImage(rawBit, 0, 0, newW, newH); + graphics.Dispose(); + rawBit.Dispose(); + newBit.Save(saveMemoryStream, jpegEncoder, jpeParameters); + newBit.Dispose(); + } + else + { + //Level为10则直接储存JPG + rawBit.Save(saveMemoryStream, jpegEncoder, jpeParameters); + } + int length = (int)saveMemoryStream.Length; + saveMemoryStream.Position = 0; + byte[] savedBytes = new byte[length]; + saveMemoryStream.Read(savedBytes, 0, length); + saveMemoryStream.Close(); + saveMemoryStream.Dispose(); + return savedBytes; + } + catch (Exception ex) + { + errorMessage = Localize.Get("Save file error at ")+$"{ex.Message}"; + return null; + } + finally + { + memoryStream?.Close(); + memoryStream?.Dispose(); + saveMemoryStream?.Close(); + saveMemoryStream?.Dispose(); + rawBit?.Dispose(); + newBit?.Dispose(); + graphics?.Dispose(); + } + } + + #endregion + + + + #region CompressBitmap + /// + /// 储存Bitmap到JPG文件。 + /// + /// + /// + /// + public bool SaveCompressBitmap(Bitmap bitmap, FileInfo saveFile, out long savedSizeInKB, out string errorMessage) + { + + savedSizeInKB = 0; + errorMessage = null; + if (saveFile.Exists) + { + if (saveFile.IsReadOnly) + { + errorMessage = Localize.Get("Save file is ReadOnly. "); + return false; + } + } + else + { + DirectoryInfo directory = saveFile.Directory; + if (!directory.Exists) + { + try + { + directory.Create(); + } + catch + { + errorMessage = Localize.Get("Cannot create save folder. "); + return false; + } + } + } + + FileStream stream = null; + try + { + stream = saveFile.Open(FileMode.Create, FileAccess.Write, FileShare.None); + + bitmap.Save(stream, jpegEncoder, jpeParameters); + savedSizeInKB = stream.Length / 1024; + + return true; + } + catch (Exception ex) + { + if (ex is IOException) + { + errorMessage = Localize.Get("Save file is occupied. "); + return false; + } + errorMessage = Localize.Get("Save file error at ") + $"{ex.Message}"; + return false; + } + finally + { + stream?.Close(); + stream?.Dispose(); + } + } + + /// + /// 打开一个Image文件 + /// + /// + /// + /// + /// + /// + public bool ReadFileToImage(FileInfo readFile, out Bitmap image, out long readSizeInKB, out string errorMessage) + { + image = null; + readSizeInKB = 0; + errorMessage = null; + + if (!readFile.Exists) + { + errorMessage = Localize.Get("Read file not exist. "); + return false; + } + FileStream stream = null; + try + { + stream = readFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read); + + Image im = Image.FromStream(stream); + image = new Bitmap(im); + im.Dispose(); + readSizeInKB = stream.Length / 1024; + + + return true; + + } + catch (Exception ex) + { + readSizeInKB = readFile.Length / 1024; + errorMessage = Localize.Get("Save file error at ") + $"{ex.Message}"; + return false; + } + finally + { + stream?.Close(); + stream?.Dispose(); + } + } + + + /// + /// 将图片压缩,不释放Image + /// + /// + /// + public Bitmap CompressImgToBitmap(Bitmap raw) + { + + double percentW = (double)MaxWidth / raw.Width; + double percentH = (double)MaxHeight / raw.Height; + double percent = Math.Min(percentW, percentH); + percent = Math.Min(1, percent); + if (percent < 1 || compressLevel < 10) + { + int newW = (int)(percent * raw.Width); + int newH = (int)(percent * raw.Height); + Bitmap newBit = new Bitmap(newW, newH); + using (Graphics g = Graphics.FromImage(newBit)) + { + + //g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; + g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + g.DrawImage(raw, 0, 0, newW, newH); + return newBit; + } + } + else + { + Bitmap bitmap = new Bitmap(raw); + return bitmap; + } + + } + #endregion + bool SetJpegCompressor() + { + var temp = ImageCodecInfo.GetImageDecoders(); + jpegEncoder = temp.FirstOrDefault(x => x.MimeType == "image/jpeg"); + if (jpegEncoder == null) return false; + + System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.Quality; + jpeParameters = new EncoderParameters(1); + EncoderParameter parameter = new EncoderParameter(encoder, Quality); + jpeParameters.Param[0] = parameter; + return true; + } + } +} diff --git a/ImageCompressor.csproj b/ImageCompressor.csproj new file mode 100644 index 0000000..a22b4cd --- /dev/null +++ b/ImageCompressor.csproj @@ -0,0 +1,131 @@ + + + + + Debug + AnyCPU + {8DB25786-04B5-4D20-AE2F-A3DB997E0DF0} + WinExe + ImageCompressor + ImageCompressor + v4.8 + 512 + true + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Resources\Icon.ico + + + + + + + + + + + + + + + + + + + + Form + + + ImageCompressorForm.cs + + + + + + Component + + + Component + + + + + + ImageCompressorForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + False + Microsoft .NET Framework 4.8 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/ImageCompressor.sln b/ImageCompressor.sln new file mode 100644 index 0000000..e4dfa37 --- /dev/null +++ b/ImageCompressor.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32319.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageCompressor", "ImageCompressor.csproj", "{8DB25786-04B5-4D20-AE2F-A3DB997E0DF0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8DB25786-04B5-4D20-AE2F-A3DB997E0DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DB25786-04B5-4D20-AE2F-A3DB997E0DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DB25786-04B5-4D20-AE2F-A3DB997E0DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DB25786-04B5-4D20-AE2F-A3DB997E0DF0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D7BB7D20-838B-4464-999D-3F536B7F2291} + EndGlobalSection +EndGlobal diff --git a/MainForm/ImageCompressorForm.Designer.cs b/MainForm/ImageCompressorForm.Designer.cs new file mode 100644 index 0000000..1a0dc09 --- /dev/null +++ b/MainForm/ImageCompressorForm.Designer.cs @@ -0,0 +1,492 @@ +namespace ImageCompressor +{ + partial class ImageCompressorForm + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageCompressorForm)); + this.PathTextBox = new System.Windows.Forms.TextBox(); + this.PreviousPictureBox = new System.Windows.Forms.PictureBox(); + this.PostPictureBox = new System.Windows.Forms.PictureBox(); + this.SizeEstimateLabel = new System.Windows.Forms.Label(); + this.CompressLevelLabel = new System.Windows.Forms.Label(); + this.SkipFileSizeLabel = new System.Windows.Forms.Label(); + this.SkipFileSizeTextBox = new System.Windows.Forms.TextBox(); + this.SubFolderCheckBox = new System.Windows.Forms.CheckBox(); + this.RunButton = new System.Windows.Forms.Button(); + this.InfoLabel = new System.Windows.Forms.Label(); + this.CloseButton = new System.Windows.Forms.Button(); + this.CompressLevelDownButton = new System.Windows.Forms.Button(); + this.CompressLevelUpButton = new System.Windows.Forms.Button(); + this.TitleTextLabel = new System.Windows.Forms.Label(); + this.MaxmizeButton = new System.Windows.Forms.Button(); + this.MinimizeButton = new System.Windows.Forms.Button(); + this.ProgressPanel = new System.Windows.Forms.Panel(); + this.CompressLevelTextLabel = new System.Windows.Forms.Label(); + this.ZoomInPictureBox = new System.Windows.Forms.PictureBox(); + this.MaxWidthPixelTextBox = new System.Windows.Forms.TextBox(); + this.MaxPixelLimitLabel = new System.Windows.Forms.Label(); + this.MaxPixelMultiplyLabel = new System.Windows.Forms.Label(); + this.MaxHeightPixelTextBox = new System.Windows.Forms.TextBox(); + this.KeepOriginalCheckBox = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.PreviousPictureBox)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.PostPictureBox)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.ZoomInPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // PathTextBox + // + this.PathTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.PathTextBox.BackColor = System.Drawing.SystemColors.ControlText; + this.PathTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.PathTextBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.PathTextBox.ForeColor = System.Drawing.Color.White; + this.PathTextBox.Location = new System.Drawing.Point(12, 55); + this.PathTextBox.Multiline = true; + this.PathTextBox.Name = "PathTextBox"; + this.PathTextBox.ReadOnly = true; + this.PathTextBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.PathTextBox.Size = new System.Drawing.Size(962, 121); + this.PathTextBox.TabIndex = 1; + this.PathTextBox.Text = "Drag and Drop Folders Here To Start"; + this.PathTextBox.WordWrap = false; + // + // PreviousPictureBox + // + this.PreviousPictureBox.BackColor = System.Drawing.SystemColors.ControlText; + this.PreviousPictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.PreviousPictureBox.Location = new System.Drawing.Point(12, 189); + this.PreviousPictureBox.Name = "PreviousPictureBox"; + this.PreviousPictureBox.Size = new System.Drawing.Size(475, 423); + this.PreviousPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.PreviousPictureBox.TabIndex = 2; + this.PreviousPictureBox.TabStop = false; + this.PreviousPictureBox.Click += new System.EventHandler(this.PreviousPictureBox_Click); + // + // PostPictureBox + // + this.PostPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.PostPictureBox.BackColor = System.Drawing.SystemColors.ControlText; + this.PostPictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.PostPictureBox.Location = new System.Drawing.Point(501, 189); + this.PostPictureBox.Name = "PostPictureBox"; + this.PostPictureBox.Size = new System.Drawing.Size(473, 423); + this.PostPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.PostPictureBox.TabIndex = 3; + this.PostPictureBox.TabStop = false; + this.PostPictureBox.Click += new System.EventHandler(this.AfterPictureBox_Click); + // + // SizeEstimateLabel + // + this.SizeEstimateLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.SizeEstimateLabel.AutoSize = true; + this.SizeEstimateLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.SizeEstimateLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.SizeEstimateLabel.Location = new System.Drawing.Point(498, 625); + this.SizeEstimateLabel.Name = "SizeEstimateLabel"; + this.SizeEstimateLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.SizeEstimateLabel.Size = new System.Drawing.Size(188, 19); + this.SizeEstimateLabel.TabIndex = 4; + this.SizeEstimateLabel.Text = "New File Size Estimate: 0KB / 0KB"; + // + // CompressLevelLabel + // + this.CompressLevelLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CompressLevelLabel.AutoSize = true; + this.CompressLevelLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.CompressLevelLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.CompressLevelLabel.Location = new System.Drawing.Point(12, 629); + this.CompressLevelLabel.Name = "CompressLevelLabel"; + this.CompressLevelLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.CompressLevelLabel.Size = new System.Drawing.Size(124, 19); + this.CompressLevelLabel.TabIndex = 4; + this.CompressLevelLabel.Text = "Compress Level (1-10)"; + // + // SkipFileSizeLabel + // + this.SkipFileSizeLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.SkipFileSizeLabel.AutoSize = true; + this.SkipFileSizeLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.SkipFileSizeLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.SkipFileSizeLabel.Location = new System.Drawing.Point(12, 675); + this.SkipFileSizeLabel.Name = "SkipFileSizeLabel"; + this.SkipFileSizeLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.SkipFileSizeLabel.Size = new System.Drawing.Size(103, 19); + this.SkipFileSizeLabel.TabIndex = 4; + this.SkipFileSizeLabel.Text = "Skip File Size (KB)"; + // + // SkipFileSizeTextBox + // + this.SkipFileSizeTextBox.AcceptsReturn = true; + this.SkipFileSizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.SkipFileSizeTextBox.BackColor = System.Drawing.Color.Black; + this.SkipFileSizeTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.SkipFileSizeTextBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 15F); + this.SkipFileSizeTextBox.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.SkipFileSizeTextBox.Location = new System.Drawing.Point(142, 667); + this.SkipFileSizeTextBox.Name = "SkipFileSizeTextBox"; + this.SkipFileSizeTextBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.SkipFileSizeTextBox.Size = new System.Drawing.Size(101, 32); + this.SkipFileSizeTextBox.TabIndex = 5; + this.SkipFileSizeTextBox.Text = "900"; + this.SkipFileSizeTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // SubFolderCheckBox + // + this.SubFolderCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.SubFolderCheckBox.AutoSize = true; + this.SubFolderCheckBox.Checked = true; + this.SubFolderCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.SubFolderCheckBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.SubFolderCheckBox.ForeColor = System.Drawing.SystemColors.HighlightText; + this.SubFolderCheckBox.Location = new System.Drawing.Point(16, 717); + this.SubFolderCheckBox.Name = "SubFolderCheckBox"; + this.SubFolderCheckBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.SubFolderCheckBox.Size = new System.Drawing.Size(129, 23); + this.SubFolderCheckBox.TabIndex = 6; + this.SubFolderCheckBox.Text = "Include SubFolders"; + this.SubFolderCheckBox.UseVisualStyleBackColor = true; + this.SubFolderCheckBox.CheckedChanged += new System.EventHandler(this.SubFolderCheckBox_CheckedChanged); + // + // RunButton + // + this.RunButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.RunButton.BackColor = System.Drawing.Color.Black; + this.RunButton.CausesValidation = false; + this.RunButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.RunButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.RunButton.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F, System.Drawing.FontStyle.Bold); + this.RunButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.RunButton.Location = new System.Drawing.Point(502, 702); + this.RunButton.Name = "RunButton"; + this.RunButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.RunButton.Size = new System.Drawing.Size(474, 33); + this.RunButton.TabIndex = 0; + this.RunButton.Text = "Waiting for image folders"; + this.RunButton.UseVisualStyleBackColor = false; + this.RunButton.Click += new System.EventHandler(this.RunButton_Click); + // + // InfoLabel + // + this.InfoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.InfoLabel.AutoSize = true; + this.InfoLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.InfoLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.InfoLabel.Location = new System.Drawing.Point(498, 660); + this.InfoLabel.Name = "InfoLabel"; + this.InfoLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.InfoLabel.Size = new System.Drawing.Size(35, 19); + this.InfoLabel.TabIndex = 4; + this.InfoLabel.Text = "Info :"; + // + // CloseButton + // + this.CloseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.CloseButton.BackColor = System.Drawing.Color.Black; + this.CloseButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.CloseButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.CloseButton.Font = new System.Drawing.Font("Arial Rounded MT Bold", 16F); + this.CloseButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.CloseButton.Location = new System.Drawing.Point(905, 10); + this.CloseButton.Name = "CloseButton"; + this.CloseButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.CloseButton.Size = new System.Drawing.Size(70, 35); + this.CloseButton.TabIndex = 10; + this.CloseButton.Text = "×"; + this.CloseButton.UseVisualStyleBackColor = false; + this.CloseButton.Click += new System.EventHandler(this.CloseButton_Click); + // + // CompressLevelDownButton + // + this.CompressLevelDownButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CompressLevelDownButton.BackColor = System.Drawing.Color.Black; + this.CompressLevelDownButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.CompressLevelDownButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.CompressLevelDownButton.Font = new System.Drawing.Font("Arial", 11F, System.Drawing.FontStyle.Bold); + this.CompressLevelDownButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.CompressLevelDownButton.Location = new System.Drawing.Point(142, 623); + this.CompressLevelDownButton.Margin = new System.Windows.Forms.Padding(0); + this.CompressLevelDownButton.Name = "CompressLevelDownButton"; + this.CompressLevelDownButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.CompressLevelDownButton.Size = new System.Drawing.Size(28, 35); + this.CompressLevelDownButton.TabIndex = 11; + this.CompressLevelDownButton.Text = "-"; + this.CompressLevelDownButton.UseVisualStyleBackColor = false; + this.CompressLevelDownButton.Click += new System.EventHandler(this.CompressLevelDownButton_Click); + // + // CompressLevelUpButton + // + this.CompressLevelUpButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CompressLevelUpButton.BackColor = System.Drawing.Color.Black; + this.CompressLevelUpButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.CompressLevelUpButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.CompressLevelUpButton.Font = new System.Drawing.Font("Arial", 11F, System.Drawing.FontStyle.Bold); + this.CompressLevelUpButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.CompressLevelUpButton.Location = new System.Drawing.Point(215, 623); + this.CompressLevelUpButton.Name = "CompressLevelUpButton"; + this.CompressLevelUpButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.CompressLevelUpButton.Size = new System.Drawing.Size(28, 35); + this.CompressLevelUpButton.TabIndex = 12; + this.CompressLevelUpButton.Text = "+"; + this.CompressLevelUpButton.UseVisualStyleBackColor = false; + this.CompressLevelUpButton.Click += new System.EventHandler(this.CompressLevelUpButton_Click); + // + // TitleTextLabel + // + this.TitleTextLabel.AutoSize = true; + this.TitleTextLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.TitleTextLabel.ForeColor = System.Drawing.SystemColors.ControlDark; + this.TitleTextLabel.Location = new System.Drawing.Point(13, 18); + this.TitleTextLabel.Name = "TitleTextLabel"; + this.TitleTextLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.TitleTextLabel.Size = new System.Drawing.Size(201, 19); + this.TitleTextLabel.TabIndex = 14; + this.TitleTextLabel.Text = "Image Compressor 2023.03.25 by WR"; + // + // MaxmizeButton + // + this.MaxmizeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.MaxmizeButton.BackColor = System.Drawing.Color.Black; + this.MaxmizeButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.MaxmizeButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.MaxmizeButton.Font = new System.Drawing.Font("Arial Rounded MT Bold", 16F); + this.MaxmizeButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.MaxmizeButton.Location = new System.Drawing.Point(825, 10); + this.MaxmizeButton.Name = "MaxmizeButton"; + this.MaxmizeButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MaxmizeButton.Size = new System.Drawing.Size(70, 35); + this.MaxmizeButton.TabIndex = 15; + this.MaxmizeButton.Text = "◻"; + this.MaxmizeButton.UseVisualStyleBackColor = false; + this.MaxmizeButton.Click += new System.EventHandler(this.MaxmizeButton_Click); + // + // MinimizeButton + // + this.MinimizeButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.MinimizeButton.BackColor = System.Drawing.Color.Black; + this.MinimizeButton.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.MinimizeButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.MinimizeButton.Font = new System.Drawing.Font("Arial Rounded MT Bold", 16F); + this.MinimizeButton.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.MinimizeButton.Location = new System.Drawing.Point(745, 10); + this.MinimizeButton.Name = "MinimizeButton"; + this.MinimizeButton.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MinimizeButton.Size = new System.Drawing.Size(70, 35); + this.MinimizeButton.TabIndex = 16; + this.MinimizeButton.Text = "-"; + this.MinimizeButton.UseVisualStyleBackColor = false; + this.MinimizeButton.Click += new System.EventHandler(this.MinimizeButton_Click); + // + // ProgressPanel + // + this.ProgressPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.ProgressPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.ProgressPanel.ForeColor = System.Drawing.SystemColors.ControlDark; + this.ProgressPanel.Location = new System.Drawing.Point(502, 746); + this.ProgressPanel.Name = "ProgressPanel"; + this.ProgressPanel.Size = new System.Drawing.Size(474, 29); + this.ProgressPanel.TabIndex = 17; + // + // CompressLevelTextLabel + // + this.CompressLevelTextLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CompressLevelTextLabel.AutoSize = true; + this.CompressLevelTextLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 15F); + this.CompressLevelTextLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.CompressLevelTextLabel.Location = new System.Drawing.Point(185, 629); + this.CompressLevelTextLabel.Name = "CompressLevelTextLabel"; + this.CompressLevelTextLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.CompressLevelTextLabel.Size = new System.Drawing.Size(18, 24); + this.CompressLevelTextLabel.TabIndex = 4; + this.CompressLevelTextLabel.Text = "8"; + // + // ZoomInPictureBox + // + this.ZoomInPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.ZoomInPictureBox.Location = new System.Drawing.Point(298, 313); + this.ZoomInPictureBox.Name = "ZoomInPictureBox"; + this.ZoomInPictureBox.Size = new System.Drawing.Size(300, 150); + this.ZoomInPictureBox.TabIndex = 18; + this.ZoomInPictureBox.TabStop = false; + this.ZoomInPictureBox.Visible = false; + // + // MaxWidthPixelTextBox + // + this.MaxWidthPixelTextBox.AcceptsReturn = true; + this.MaxWidthPixelTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.MaxWidthPixelTextBox.BackColor = System.Drawing.Color.Black; + this.MaxWidthPixelTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.MaxWidthPixelTextBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 15F); + this.MaxWidthPixelTextBox.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.MaxWidthPixelTextBox.Location = new System.Drawing.Point(355, 623); + this.MaxWidthPixelTextBox.Name = "MaxWidthPixelTextBox"; + this.MaxWidthPixelTextBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MaxWidthPixelTextBox.Size = new System.Drawing.Size(52, 32); + this.MaxWidthPixelTextBox.TabIndex = 19; + this.MaxWidthPixelTextBox.Text = "1920"; + this.MaxWidthPixelTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // MaxPixelLimitLabel + // + this.MaxPixelLimitLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.MaxPixelLimitLabel.AutoSize = true; + this.MaxPixelLimitLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.MaxPixelLimitLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.MaxPixelLimitLabel.Location = new System.Drawing.Point(264, 629); + this.MaxPixelLimitLabel.Name = "MaxPixelLimitLabel"; + this.MaxPixelLimitLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MaxPixelLimitLabel.Size = new System.Drawing.Size(89, 19); + this.MaxPixelLimitLabel.TabIndex = 4; + this.MaxPixelLimitLabel.Text = "Max Pixel Limit"; + // + // MaxPixelMultiplyLabel + // + this.MaxPixelMultiplyLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.MaxPixelMultiplyLabel.AutoSize = true; + this.MaxPixelMultiplyLabel.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.MaxPixelMultiplyLabel.ForeColor = System.Drawing.SystemColors.HighlightText; + this.MaxPixelMultiplyLabel.Location = new System.Drawing.Point(409, 629); + this.MaxPixelMultiplyLabel.Name = "MaxPixelMultiplyLabel"; + this.MaxPixelMultiplyLabel.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MaxPixelMultiplyLabel.Size = new System.Drawing.Size(15, 19); + this.MaxPixelMultiplyLabel.TabIndex = 4; + this.MaxPixelMultiplyLabel.Text = "×"; + // + // MaxHeightPixelTextBox + // + this.MaxHeightPixelTextBox.AcceptsReturn = true; + this.MaxHeightPixelTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.MaxHeightPixelTextBox.BackColor = System.Drawing.Color.Black; + this.MaxHeightPixelTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.MaxHeightPixelTextBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 15F); + this.MaxHeightPixelTextBox.ForeColor = System.Drawing.SystemColors.ButtonFace; + this.MaxHeightPixelTextBox.Location = new System.Drawing.Point(425, 623); + this.MaxHeightPixelTextBox.Name = "MaxHeightPixelTextBox"; + this.MaxHeightPixelTextBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.MaxHeightPixelTextBox.Size = new System.Drawing.Size(52, 32); + this.MaxHeightPixelTextBox.TabIndex = 19; + this.MaxHeightPixelTextBox.Text = "1080"; + this.MaxHeightPixelTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // KeepOriginalCheckBox + // + this.KeepOriginalCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.KeepOriginalCheckBox.AutoSize = true; + this.KeepOriginalCheckBox.Checked = true; + this.KeepOriginalCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.KeepOriginalCheckBox.Font = new System.Drawing.Font("Bahnschrift Condensed", 12F); + this.KeepOriginalCheckBox.ForeColor = System.Drawing.SystemColors.HighlightText; + this.KeepOriginalCheckBox.Location = new System.Drawing.Point(16, 752); + this.KeepOriginalCheckBox.Name = "KeepOriginalCheckBox"; + this.KeepOriginalCheckBox.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.KeepOriginalCheckBox.Size = new System.Drawing.Size(233, 23); + this.KeepOriginalCheckBox.TabIndex = 6; + this.KeepOriginalCheckBox.Text = "Keep Original (Compress in new folder)"; + this.KeepOriginalCheckBox.UseVisualStyleBackColor = true; + this.KeepOriginalCheckBox.CheckedChanged += new System.EventHandler(this.KeepOriginalCheckBox_CheckedChanged); + // + // ImageCompressorForm + // + this.AllowDrop = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20))))); + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.ClientSize = new System.Drawing.Size(990, 800); + this.ControlBox = false; + this.Controls.Add(this.ZoomInPictureBox); + this.Controls.Add(this.MaxHeightPixelTextBox); + this.Controls.Add(this.MaxWidthPixelTextBox); + this.Controls.Add(this.MinimizeButton); + this.Controls.Add(this.MaxmizeButton); + this.Controls.Add(this.TitleTextLabel); + this.Controls.Add(this.CompressLevelUpButton); + this.Controls.Add(this.CompressLevelDownButton); + this.Controls.Add(this.CloseButton); + this.Controls.Add(this.SubFolderCheckBox); + this.Controls.Add(this.KeepOriginalCheckBox); + this.Controls.Add(this.SkipFileSizeTextBox); + this.Controls.Add(this.SkipFileSizeLabel); + this.Controls.Add(this.MaxPixelMultiplyLabel); + this.Controls.Add(this.CompressLevelTextLabel); + this.Controls.Add(this.MaxPixelLimitLabel); + this.Controls.Add(this.CompressLevelLabel); + this.Controls.Add(this.InfoLabel); + this.Controls.Add(this.SizeEstimateLabel); + this.Controls.Add(this.PostPictureBox); + this.Controls.Add(this.PreviousPictureBox); + this.Controls.Add(this.PathTextBox); + this.Controls.Add(this.RunButton); + this.Controls.Add(this.ProgressPanel); + this.Font = new System.Drawing.Font("等线", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Margin = new System.Windows.Forms.Padding(4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(990, 800); + this.Name = "ImageCompressorForm"; + this.RightToLeft = System.Windows.Forms.RightToLeft.Yes; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Image Compressor 1.0 by WR "; + ((System.ComponentModel.ISupportInitialize)(this.PreviousPictureBox)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.PostPictureBox)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.ZoomInPictureBox)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.TextBox PathTextBox; + private System.Windows.Forms.PictureBox PreviousPictureBox; + private System.Windows.Forms.PictureBox PostPictureBox; + private System.Windows.Forms.Label SizeEstimateLabel; + private System.Windows.Forms.Label CompressLevelLabel; + private System.Windows.Forms.Label SkipFileSizeLabel; + private System.Windows.Forms.TextBox SkipFileSizeTextBox; + private System.Windows.Forms.CheckBox SubFolderCheckBox; + private System.Windows.Forms.Button RunButton; + private System.Windows.Forms.Label InfoLabel; + private System.Windows.Forms.Button CloseButton; + private System.Windows.Forms.Button CompressLevelDownButton; + private System.Windows.Forms.Button CompressLevelUpButton; + private System.Windows.Forms.Label TitleTextLabel; + private System.Windows.Forms.Button MaxmizeButton; + private System.Windows.Forms.Button MinimizeButton; + private System.Windows.Forms.Panel ProgressPanel; + private System.Windows.Forms.Label CompressLevelTextLabel; + private System.Windows.Forms.PictureBox ZoomInPictureBox; + private System.Windows.Forms.TextBox MaxWidthPixelTextBox; + private System.Windows.Forms.Label MaxPixelLimitLabel; + private System.Windows.Forms.Label MaxPixelMultiplyLabel; + private System.Windows.Forms.TextBox MaxHeightPixelTextBox; + private System.Windows.Forms.CheckBox KeepOriginalCheckBox; + } +} + diff --git a/MainForm/ImageCompressorForm.cs b/MainForm/ImageCompressorForm.cs new file mode 100644 index 0000000..e3f3063 --- /dev/null +++ b/MainForm/ImageCompressorForm.cs @@ -0,0 +1,867 @@ +//#define InitialPath +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading; +using System.Windows.Forms; +using System.IO; +using System.Diagnostics; + +namespace ImageCompressor +{ + public partial class ImageCompressorForm : Form + { + public ImageCompressorForm() + { + manager = new FilesManager(this); + } + /// + /// 后台读取图片,并且负责运行 + /// + FilesManager manager; + /// + /// 替换原有的Panel作为进度条 + /// + NewProgressPanel newProgressPanel; + protected override void OnLoad(EventArgs e) + { + this.newProgressPanel = new NewProgressPanel(new Font("Bahnschrift Condensed", 12F), SystemColors.ControlDark); + + InitializeComponent(); + SetLanguage(); + + newProgressPanel.Clone(ProgressPanel); + + ProgressPanel.Visible = false; + this.Controls.Add(this.newProgressPanel); + + OnSizeChanged(null); + + ZoomInPictureBox.Visible = false; + + PostPictureBox.MouseMove += OnPictureMouseMovePost; + PreviousPictureBox.MouseMove += OnPictureMouseMovePrevious; + ZoomInPictureBox.MouseMove += OnZoomMouseMove; + PostPictureBox.MouseWheel += OnZoomMouseWheelPost; + PreviousPictureBox.MouseWheel += OnZoomMouseWheelPre; + + MaxWidthPixelTextBox.Leave += MaxWidthPixelTextBox_FocusLeave; + MaxHeightPixelTextBox.Leave += MaxHeightPixelTextBox_FocusLeave; + SkipFileSizeTextBox.Leave += SkipFileSizeTextBox_FocusLeave; + MaxWidthPixelTextBox.KeyDown += TextBox_KeyDown; + MaxHeightPixelTextBox.KeyDown += TextBox_KeyDown; + SkipFileSizeTextBox.KeyDown += TextBox_KeyDown; + + ApplySettingsFromForm(); + UpdateDisplayInfo(); + UpdateRunButtonText(); + SetProgressValue(0); + + PathTextBox.DragDrop += Box_DragDrop; + PathTextBox.DragEnter += Box_DragEnter; + + this.DragDrop += Box_DragDrop; + this.DragEnter += Box_DragEnter; + + + +#if InitialPath && DEBUG + + //string path = @"C:\Users\wucl12\Downloads\Test\Italy"; + string path = @"D:\Users\MandO\Downloads\重庆照片"; + dragDropFolderPaths.Add(path); + UpdateDropFilePaths(); + UpdateRunButtonText(); +#endif + } + + /// + /// 启动时设置语言 + /// + void SetLanguage() + { + if(!Localize.IsEN) + { + + this.PathTextBox.Font = new System.Drawing.Font("等线", 12F); + this.SizeEstimateLabel.Font = new Font("等线", 12F); + this.KeepOriginalCheckBox.Font = new Font("等线", 12F); + this.MaxPixelMultiplyLabel.Font = new Font("等线", 12F); + this.MaxPixelLimitLabel.Font = new Font("等线", 12F); + //this.CompressLevelTextLabel.Font = new Font("等线", 15F); + this.TitleTextLabel.Font = new Font("等线", 12F); + this.InfoLabel.Font = new Font("等线", 12F); + this.RunButton.Font = new Font("等线", 12F, FontStyle.Bold); + this.SubFolderCheckBox.Font = new Font("等线", 12F); + this.SkipFileSizeLabel.Font = new Font("等线", 12F); + this.CompressLevelLabel.Font = new Font("等线", 12F); + } + + this.CompressLevelLabel.Text = Localize.Get("Compress Level (1-10)"); + this.SkipFileSizeLabel.Text = Localize.Get("Skip File Size (KB)"); + + this.KeepOriginalCheckBox.Text = Localize.Get("Keep Original (Compress in new folder)"); + this.SubFolderCheckBox.Text = Localize.Get("Include SubFolders"); + + this.MaxPixelLimitLabel.Text = Localize.Get("Max Pixel Limit"); + this.TitleTextLabel.Text = Localize.Get("Image Compressor") +" 2026.02.02 by WR"; + + this.Text = Localize.Get("Image Compressor"); + } + + + #region Resize + /// + /// 点击到左右边界 + /// + ClickResize clickResizeHorizen = ClickResize.None; + /// + /// 点击到上下边界 + /// + ClickResize clickResizeVertical = ClickResize.None; + /// + /// 记录点击边界值 + /// + enum ClickResize + { + None, + Left, + Right, + Top, + Buttom, + } + /// + /// 鼠标点击位置是移动还是缩放 + /// + enum SizeChangeState + { + None, + ChangeSize, + Move, + } + /// + /// 记录移动或者缩放状态 + /// + SizeChangeState sizeChangeState = SizeChangeState.None; + + /// + /// 绘制尺寸时的间距控制常数 + /// + const int sizePad = 15; + + /// + /// 减少卡顿 + /// + protected override CreateParams CreateParams + { + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; + return cp; + } + } + + /// + /// 动态缩放 + /// + /// + protected override void OnSizeChanged(EventArgs e) + { + SuspendLayout(); + this.CloseButton.Left = Width - sizePad - CloseButton.Width; + this.MaxmizeButton.Left = CloseButton.Left - sizePad - MaxmizeButton.Width; + this.MinimizeButton.Left = MaxmizeButton.Left - sizePad - MinimizeButton.Width; + + this.PathTextBox.Width = Width - sizePad - PathTextBox.Left; + + this.RunButton.Left = Width / 2 + sizePad / 2; + this.newProgressPanel.Top = Height - sizePad - newProgressPanel.Height; + this.newProgressPanel.Left = RunButton.Left; + this.newProgressPanel.Width = Width - sizePad - RunButton.Left; + this.ProgressPanel.Location = newProgressPanel.Location; + this.ProgressPanel.Width = newProgressPanel.Width; + + + this.RunButton.Top = this.ProgressPanel.Top - sizePad - RunButton.Height; + this.RunButton.Width = Width - sizePad - RunButton.Left; + + this.InfoLabel.Left = RunButton.Left; + this.InfoLabel.Top = this.RunButton.Top - sizePad - InfoLabel.Height; + + this.SizeEstimateLabel.Left = this.RunButton.Left; + this.SizeEstimateLabel.Top = this.InfoLabel.Top - sizePad - this.SizeEstimateLabel.Height; + + + this.PostPictureBox.Left = RunButton.Left; + this.PostPictureBox.Width = this.RunButton.Width; + this.PostPictureBox.Height = this.SizeEstimateLabel.Top - sizePad - this.PostPictureBox.Top; + this.PreviousPictureBox.Height = this.PostPictureBox.Height; + this.PreviousPictureBox.Width = this.PostPictureBox.Left- sizePad - this.PreviousPictureBox.Left; + + this.KeepOriginalCheckBox.Top = ProgressPanel.Top; + this.SubFolderCheckBox.Top = this.KeepOriginalCheckBox.Top - 10 - this.SubFolderCheckBox.Height; + + this.SkipFileSizeTextBox.Top = this.RunButton.Top - this.SkipFileSizeTextBox.Height; + this.CompressLevelDownButton.Top = this.PostPictureBox.Bottom + sizePad-5; + this.CompressLevelUpButton.Top = this.CompressLevelDownButton.Top; + this.CompressLevelTextLabel.Top = this.CompressLevelUpButton.Top + 7; + this.CompressLevelLabel.Top = this.CompressLevelTextLabel.Bottom - this.CompressLevelLabel.Height-3; + this.SkipFileSizeTextBox.Top = this.CompressLevelUpButton.Bottom + sizePad-5; + this.SkipFileSizeLabel.Top = this.SkipFileSizeTextBox.Top+5; + + this.MaxPixelLimitLabel.Top = this.CompressLevelLabel.Top; + this.MaxPixelMultiplyLabel.Top = this.MaxPixelLimitLabel.Top; + this.MaxWidthPixelTextBox.Top = this.CompressLevelUpButton.Top + 3; + this.MaxHeightPixelTextBox.Top = this.MaxWidthPixelTextBox.Top; + + + ResumeLayout(false); + PerformLayout(); + } + /// + /// 点击四边拖拽更改窗口大小的距离距离范围 + /// + const float ChangeSizeClickTolerance = 10; + bool ClickNear(float n1, float n2) + { + return Math.Abs(n1 - n2) < ChangeSizeClickTolerance; + } + Point moveLocation; + protected override void OnMouseDown(MouseEventArgs e) + { + + this.RunButton.Focus(); + sizeChangeState = SizeChangeState.None; + if(e.Y > ChangeSizeClickTolerance && e.Y < MinimizeButton.Bottom && e.X < MinimizeButton.Left) + { + sizeChangeState = SizeChangeState.Move; + moveLocation = e.Location; + return; + } + if (ClickNear(0, e.X)) + { + clickResizeHorizen = ClickResize.Left; + sizeChangeState = SizeChangeState.ChangeSize; + } + else if (ClickNear(Bounds.Width, e.X)) + { + clickResizeHorizen = ClickResize.Right; + sizeChangeState = SizeChangeState.ChangeSize; + } + else clickResizeHorizen = ClickResize.None; + + if (ClickNear(0, e.Y)) + { + clickResizeVertical = ClickResize.Top; + sizeChangeState = SizeChangeState.ChangeSize; + } + else if (ClickNear(Bounds.Height, e.Y)) + { + clickResizeVertical = ClickResize.Buttom; + sizeChangeState = SizeChangeState.ChangeSize; + } + else clickResizeVertical = ClickResize.None; + if (sizeChangeState == SizeChangeState.None) + { + + base.OnMouseDown(e); + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + ZoomInPictureBox.Visible = false; + + if (sizeChangeState == SizeChangeState.Move) + { + if(this.WindowState != FormWindowState.Normal) + { + this.WindowState = FormWindowState.Normal; + moveLocation = new Point(Width / 2, 10); + } + else + { + Size size = Bounds.Size; + Point location = new Point(Bounds.X + e.X - moveLocation.X, Bounds.Y + e.Y - moveLocation.Y); + Bounds = new Rectangle(location, size); + } + } + else if(sizeChangeState == SizeChangeState.ChangeSize) + { + this.WindowState = FormWindowState.Normal; + Point location = Bounds.Location; + Size size = Bounds.Size; + bool changed = false; + if (clickResizeHorizen == ClickResize.Left) + { + location.X = Bounds.X + e.X; + size.Width = Bounds.Width - e.X; + changed = true; + } + else if (clickResizeHorizen == ClickResize.Right) + { + size.Width = e.X; + changed = true; + } + if (clickResizeVertical == ClickResize.Top) + { + location.Y = Bounds.Y + e.Y; + size.Height = Bounds.Height - e.Y; + changed = true; + } + else if (clickResizeVertical == ClickResize.Buttom) + { + size.Height = e.Y; + changed = true; + } + if (changed) + { + Bounds = new Rectangle(location, size); + } + } + else + { + bool left = ClickNear(0, e.X); + bool onHorizon = left || ClickNear(Bounds.Width, e.X); + bool top = ClickNear(0, e.Y); + bool onVertical = top || ClickNear(Bounds.Height, e.Y); + if (onHorizon && onVertical) + { + if ((left && top) || ((!left) || (!top))) this.Cursor = Cursors.SizeNWSE; + else this.Cursor = Cursors.SizeNESW; + } + else if (onHorizon) + { + this.Cursor = Cursors.SizeWE; + } + else if (onVertical) + { + this.Cursor = Cursors.SizeNS; + } + else this.Cursor = Cursors.Default; + + + + base.OnMouseMove(e); + } + } + + + protected override void OnMouseUp(MouseEventArgs e) + { + if (sizeChangeState!= SizeChangeState.None) + { + clickResizeHorizen = ClickResize.None; + clickResizeVertical= ClickResize.None; + sizeChangeState = SizeChangeState.None; + OnSizeChanged(null); + } + else base.OnMouseUp(e); + } + #endregion + + #region Drag&Drop + + + List dragDropFolderPaths = new List(); + + /// + /// 改变路径Box的消息 + /// + /// + private void ChangePathTextBoxMessage(string messageText) + { + if (!string.IsNullOrEmpty(messageText)) + { + PathTextBox.Text = messageText; + PathTextBox.ForeColor = Color.Gray; + } + } + + private void Box_DragEnter(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + e.Effect = DragDropEffects.Link; + } + else e.Effect = DragDropEffects.None; + } + + private void Box_DragDrop(object sender, DragEventArgs e) + { + dragDropFolderPaths.Clear(); + Array files = (Array)e.Data.GetData(DataFormats.FileDrop); + foreach (object file in files) + { + FileInfo info = new FileInfo(file.ToString()); + if (info != null && info.Attributes.HasFlag(FileAttributes.Directory)) + { + dragDropFolderPaths.Add(info.FullName); + } + } + if (dragDropFolderPaths.Count == 0) + { + ChangePathTextBoxMessage(Localize.Get("No Folders Droped")); + return; + } + UpdateDropFilePaths(); + UpdateRunButtonText(); + + } + /// + /// 当Drop时更新路径 + /// + void UpdateDropFilePaths() + { + manager.ReadAllFilePaths(dragDropFolderPaths); + SetProgressValue(0); + if (manager.FilesCount == 0) + { + MessageBox.Show(Localize.Get("No Images (JPG, PNG, BMP) Found in Folder Droped"), Localize.Get("Warning")); + PostPictureBox.Image = null; + PreviousPictureBox.Image = null; + UpdateDisplayInfo(); + return; + } + UpdateDisplayInfo(); + DrawPreviewImg(); + PathTextBox.Lines = dragDropFolderPaths.ToArray(); + } + + + #endregion + + #region Zoom Picture + + /// + /// 滚轮缩放Zoom框 + /// + void OnZoomMouseWheelPre(object sender, MouseEventArgs e) + { + + if (e.Delta > 0) ZoomFactor.ZoomPercent *= 0.8; + else ZoomFactor.ZoomPercent *= 1.25; + DrawZoomInImage(PreviousPictureBox, e); + } + + void OnZoomMouseWheelPost(object sender, MouseEventArgs e) + { + + if (e.Delta > 0) ZoomFactor.ZoomPercent *= 0.8; + else ZoomFactor.ZoomPercent *= 1.25; + DrawZoomInImage(PostPictureBox, e); + } + + void OnZoomMouseMove(object sender, MouseEventArgs e) + { + ZoomInPictureBox.Location = new Point(ZoomInPictureBox.Left + e.X + 5, ZoomInPictureBox.Top - ZoomInPictureBox.Height + e.Y - 5); + } + + void OnPictureMouseMovePost(object sender, MouseEventArgs e) + { + DrawZoomInImage(PostPictureBox, e); + } + void OnPictureMouseMovePrevious(object sender, MouseEventArgs e) + { + DrawZoomInImage(PreviousPictureBox, e); + } + long CpuTime => DateTime.Now.Ticks / 10000; + long wait = 0; + void DrawZoomInImage(PictureBox box, MouseEventArgs e) + { + long t = CpuTime; + if (t - wait > 100) wait = t; + else return; + + if (PreviousPictureBox.Image == null || PostPictureBox.Image == null) + { + ZoomInPictureBox.Visible = false; + return; + } + ZoomInPictureBox.Visible = true; + ZoomInPictureBox.Location = new Point(box.Left + e.X + 5, box.Top + e.Y - 155); + ZoomFactor zoomFactor = new ZoomFactor(box.Bounds, e.Location, box.Image.Width, box.Image.Height); + ZoomInPictureBox.Image = GetZoomImage(zoomFactor); + } + + Image GetZoomImage(ZoomFactor factor) + { + + Bitmap newBit = new Bitmap(300, 150); + Rectangle destRectPre = new Rectangle(0, 0, 150, 150); + Rectangle destRectPost = new Rectangle(150, 0, 150, 150); + Graphics graphics = Graphics.FromImage(newBit); + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; + graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + graphics.SetClip(destRectPre); + Rectangle srcRectPre = factor.GetSourceImage(PreviousPictureBox.Image); + + graphics.DrawImage(PreviousPictureBox.Image, destRectPre, srcRectPre, GraphicsUnit.Pixel); + graphics.SetClip(destRectPost); + Rectangle srcRectPost = factor.GetSourceImage(PostPictureBox.Image); + graphics.DrawImage(PostPictureBox.Image, destRectPost, srcRectPost, GraphicsUnit.Pixel); + graphics.Dispose(); + //Debug.WriteLine("srcRectPre = {0}, srcRectPost = {1}", srcRectPre, srcRectPost); + return newBit; + } + + #endregion + + #region UI Event + /// + /// 防止内部修改文字的时候,调用了TextChange事件 + /// + bool internalUpdating = false; + /// + /// 在Drop文件之后,初始化Info显示 + /// + private void UpdateDisplayInfo() + { + internalUpdating = true; + CompressLevelTextLabel.Text = manager.CompressLevel.ToString(); + MaxHeightPixelTextBox.Text = manager.MaxHeight.ToString(); + MaxWidthPixelTextBox.Text = manager.MaxWidth.ToString(); + + int fileCount = manager.FilesCount; + if (fileCount > 0) + { + newProgressPanel.Text = $"0/{fileCount}"; + newProgressPanel.Refresh(); + manager.SetSkipFileSizeInKB(SkipFileSizeTextBox.Text); + InfoLabel.Text = string.Format(Localize.Get("Find {0} Imgs , Sum Size = {1}"), manager.FilesCount, manager.GetFileSizeString(manager.PreAllImageSizeinKB)); + + } + else + { + ChangePathTextBoxMessage(Localize.Get("Drag and Drop Folders Here To Start")); + newProgressPanel.Text = $"0/0"; + newProgressPanel.Refresh(); + SizeEstimateLabel.Text = Localize.Get("New Image Size Estimate: ") + "0KB / 0KB"; + InfoLabel.Text = ""; + } + internalUpdating = false; + } + /// + /// 将Form的设置运用到后台程序中去 + /// + void ApplySettingsFromForm(bool updateWidthHeight = false) + { + manager.SetSkipFileSizeInKB(SkipFileSizeTextBox.Text); + manager.IncludeSubFolders = SubFolderCheckBox.Checked; + manager.KeepOriginal = KeepOriginalCheckBox.Checked; + manager.CompressLevel = int.Parse(CompressLevelTextLabel.Text); + if(updateWidthHeight) + { + manager.MaxWidth = int.Parse(MaxWidthPixelTextBox.Text); + manager.MaxHeight = int.Parse(MaxHeightPixelTextBox.Text); + } + } + + + + /// + /// 根据Seed绘制一个压缩后的预览图 + /// + void DrawPreviewImg() + { + if (!manager.GetRandomIndex(seed, out int index)) + { + //manager没有文件 + PreviousPictureBox.Image = null; + PostPictureBox.Image = null; + SizeEstimateLabel.Text = Localize.Get("New Image Size Estimate: ") + "0KB / 0KB"; + return; + } + + var rawImage = manager.GetImageAtIndex(index, out string rawFileSize); + PreviousPictureBox.Image = rawImage; + + + var newImage = manager.GetCompressedImgAtIndex(index, out string newFileSize, out bool skip, out string errorMessage); + + + if (skip) + { + PostPictureBox.Image = rawImage; + SizeEstimateLabel.Text = Localize.Get("New Image Size Estimate: ")+$"{rawFileSize} / {rawFileSize}" + Localize.Get("(Skiped)"); + } + else + { + if (newImage == null) + { + SizeEstimateLabel.Text = errorMessage; + PostPictureBox.Image = null; + return; + } + PostPictureBox.Image = newImage; + SizeEstimateLabel.Text = Localize.Get("New Image Size Estimate: ") +$"{newFileSize} / {rawFileSize}"; + + } + + ZoomFactor.ZoomPercent = 0.1; + } + + + void SkipFileSizeTextBox_FocusLeave(object sender, EventArgs e) + { + if (!int.TryParse(SkipFileSizeTextBox.Text, out _)) + SkipFileSizeTextBox.Text = manager.CurrentSkipFileSizeInKB.ToString(); + ApplySettingsFromForm(); + } + + private void SubFolderCheckBox_CheckedChanged(object sender, EventArgs e) + { + ApplySettingsFromForm(); + } + + private void KeepOriginalCheckBox_CheckedChanged(object sender, EventArgs e) + { + ApplySettingsFromForm(); + } + int seed = 0; + private void PreviousPictureBox_Click(object sender, EventArgs e) + { + if (manager.FilesCount > 0) + { + seed++; + DrawPreviewImg(); + } + else seed = 0; + } + + private void AfterPictureBox_Click(object sender, EventArgs e) + { + if (manager.FilesCount > 0) + { + seed--; + DrawPreviewImg(); + } + else seed = 0; + } + + + + private void CompressLevelTextChanged(bool manuallWidthHeight=false) + { + ApplySettingsFromForm(manuallWidthHeight); + DrawPreviewImg(); + UpdateDisplayInfo(); + + } + + void MaxHeightPixelTextBox_FocusLeave(object sender, EventArgs e) + { + if (internalUpdating) return; + if (!int.TryParse(MaxHeightPixelTextBox.Text, out _)) + { + MaxHeightPixelTextBox.Text = manager.MaxHeight.ToString(); + } + CompressLevelTextChanged(true); + } + + + private void TextBox_KeyDown(object sender, KeyEventArgs e) + { + if(e.KeyCode == Keys.Enter) + { + this.RunButton.Focus(); + } + } + + + + void MaxWidthPixelTextBox_FocusLeave(object sender, EventArgs e) + { + if (internalUpdating) return; + if (!int.TryParse(MaxWidthPixelTextBox.Text, out _)) + { + MaxWidthPixelTextBox.Text = manager.MaxWidth.ToString(); + } + CompressLevelTextChanged(true); + } + + + private void CompressLevelDownButton_Click(object sender, EventArgs e) + { + if (manager.CompressLevel > 1) + { + this.CompressLevelTextLabel.Text = (manager.CompressLevel - 1).ToString(); + CompressLevelTextChanged(); + } + } + + private void CompressLevelUpButton_Click(object sender, EventArgs e) + { + if (manager.CompressLevel < 10) + { + this.CompressLevelTextLabel.Text = (manager.CompressLevel + 1).ToString(); + CompressLevelTextChanged(); + } + } + + private void CloseButton_Click(object sender, EventArgs e) + { + if (manager.State != RunningState.Running) + { + + this.Close(); + return; + } + else + { + //发送结束指令 + manager.Stop(); + while (true) + { + if (manager.State != RunningState.Running) + { + //确保运行结束后才关闭 + this.Close(); + return; + } + else Thread.Sleep(100); + } + } + } + + private void MaxmizeButton_Click(object sender, EventArgs e) + { + if (this.WindowState != FormWindowState.Maximized) this.WindowState = FormWindowState.Maximized; + else this.WindowState = FormWindowState.Normal; + } + + private void MinimizeButton_Click(object sender, EventArgs e) + { + this.WindowState = FormWindowState.Minimized; + } + + #endregion + + #region Run + + /// + /// 用于内部线程调用 + /// + /// + public delegate void SetProgressValueDelegate(int percent); + + /// + /// 设定进度条 + /// + /// + public void SetProgressValue(int fileCount) + { + if (InvokeRequired) + { + //从其他线程调用,则在此返回Form线程调用 + SetProgressValueDelegate setProgressValueDelegate = new SetProgressValueDelegate(SetProgressValue); + this.Invoke(setProgressValueDelegate, fileCount); + } + else + { + newProgressPanel.ProgressValue =(double)fileCount / manager.FilesCount; + this.newProgressPanel.Text = $"{fileCount} / {manager.FilesCount}"; + newProgressPanel.Refresh(); + } + } + /// + /// 根据RunningState更新按钮文字 + /// + public void UpdateRunButtonText() + { + switch(manager.State) + { + case RunningState.NoFile: + RunButton.Text = Localize.Get("Waiting for image folders"); + break; + case RunningState.Running: + RunButton.Text = Localize.Get("Running, Click to Pause"); + break; + case RunningState.WaitStop: + RunButton.Text = Localize.Get("Running, Wait to Pause"); + break; + case RunningState.AllThreadStoped: + RunButton.Text = Localize.Get("Paused, Click to Continue"); + break; + case RunningState.Finished: + RunButton.Text = Localize.Get("Done"); + break; + case RunningState.Ready: + RunButton.Text = Localize.Get("Ready"); + break; + default: + RunButton.Text = Localize.Get("Run"); + break; + } + } + + /// + /// 点击Run之后运行 + /// + /// + /// + void RunButton_Click(object sender, EventArgs e) + { + + if (manager.State == RunningState.Running) + { + manager.Stop(); + } + else if (manager.State == RunningState.Ready || manager.State == RunningState.AllThreadStoped) + { + manager.RunAllCompress(); + } + else //(manager.State == RunningState.Finished) + { + RunButton.Text = Localize.Get("Done !!!"); + } + + UpdateRunButtonText(); + } + + /// + /// 运行完后显示结束报告 + /// + internal void ShowReport() + { + if (InvokeRequired) + { + //从其他线程调用,则在此返回Form线程调用 + Action ac = new Action(ShowReport); + this.Invoke(ac); + } + else + { + CountProgress progress = manager.progress; + + int minutes = (int)progress.stopwatch.Elapsed.TotalMinutes; + float seconds = progress.stopwatch.Elapsed.Seconds + (progress.stopwatch.Elapsed.Milliseconds / 100) * 0.1f; + + string watchString; + if (minutes > 0) watchString = string.Format(Localize.Get("{0}min {1}s"),minutes,seconds); + else watchString = string.Format(Localize.Get("{0}s"),seconds); + + UpdateRunButtonText(); + InfoLabel.Text = string.Format(Localize.Get("Compressed {0}, Skiped {1}, Failed {2}, "), progress.SuccessCount, progress.SkipCount, progress.FailedCount) + + string.Format(Localize.Get("Time {0}, Compressed Result {1} / {2}"),watchString,manager.GetFileSizeString(progress.PostSizeKBSum), manager.GetFileSizeString(progress.PreSizeKBSum)); + if (progress.FailedInfos.Count > 0) + { + MessageBox.Show(string.Join("\n", progress.FailedInfos), Localize.Get("Failed Images Info")); + } + } + } + + + #endregion + + + } + + +} diff --git a/MainForm/ImageCompressorForm.resx b/MainForm/ImageCompressorForm.resx new file mode 100644 index 0000000..c8e7444 --- /dev/null +++ b/MainForm/ImageCompressorForm.resx @@ -0,0 +1,941 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + QmCC + + + \ No newline at end of file diff --git a/MainForm/NewPictureBox.cs b/MainForm/NewPictureBox.cs new file mode 100644 index 0000000..afc9051 --- /dev/null +++ b/MainForm/NewPictureBox.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + internal class NewPictureBox:PictureBox + { + /// + /// 以不抗锯齿方式绘制原图像素 + /// + /// + protected override void OnPaint(PaintEventArgs pe) + { + pe.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; + pe.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + pe.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + base.OnPaint(pe); + } + } +} diff --git a/MainForm/NewProgressPanel.cs b/MainForm/NewProgressPanel.cs new file mode 100644 index 0000000..fdcd07a --- /dev/null +++ b/MainForm/NewProgressPanel.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using System.Threading.Tasks; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Diagnostics; +using System.IO; + +namespace ImageCompressor +{ + /// + /// ProgressBar类有点问题,重写一个简单的ProgressBar。 + /// + internal class NewProgressPanel:Panel + { + public Font TextFont; + public Brush TextForeColor; + public NewProgressPanel(Font textFont,Color textForeColor) + { + this.TextFont = textFont; + this.TextForeColor = new SolidBrush(textForeColor); + SetStyle(ControlStyles.ResizeRedraw, true); + this.foreBrush = new SolidBrush(Color.Gray); + } + /// + /// 克隆原来的Panel以实现设计的参数传递。 + /// + /// + public void Clone(Panel raw) + { + this.Size = raw.Size; + this.Bounds = raw.Bounds; + this.Anchor = raw.Anchor; + this.BorderStyle = raw.BorderStyle; + this.Name = raw.Name; + this.TabIndex = raw.TabIndex; + this.BackColor= raw.BackColor; + this.ForeColor = raw.ForeColor; + } + public double ProgressValue { get; set; } + + Brush foreBrush; + + /// + /// 绘制背景,快但是不能耗时太久,会闪 + /// + /// + protected override void OnPaintBackground(PaintEventArgs e) + { + e.Graphics.Clear(this.BackColor); + e.Graphics.FillRectangle(foreBrush, 0, 0, (int)((double)e.ClipRectangle.Width * ProgressValue), e.ClipRectangle.Height); + } + + /// + /// 绘制耗时较多的部分 + /// + /// + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e);//控件必须通过重写它从 Control 继承的 OnPaint 方法来提供呈现逻辑。 + + + //测量string应该较为耗时,放在此处绘制 + SizeF size = e.Graphics.MeasureString(Text, TextFont); + if (!string.IsNullOrEmpty(Text)) + e.Graphics.DrawString(Text, TextFont, TextForeColor, Width / 2 - size.Width / 2, Height - size.Height - 2); + } + } +} diff --git a/MainForm/Program.cs b/MainForm/Program.cs new file mode 100644 index 0000000..b73d992 --- /dev/null +++ b/MainForm/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ImageCompressor +{ + internal static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ImageCompressorForm()); + } + } +} diff --git a/MainForm/ZoomFactor.cs b/MainForm/ZoomFactor.cs new file mode 100644 index 0000000..c725bf3 --- /dev/null +++ b/MainForm/ZoomFactor.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + + + /// + /// 计算保存Zoom的数据 + /// + class ZoomFactor + { + static double zoomPercent = 0.1; + /// + /// [0.1 - 1] + /// 对原图像的最短一边的像素 * value,作为新方形图像的一边像素值。 + /// + public static double ZoomPercent + { + get + { + return zoomPercent; + } + set + { + if (value < 0.01) zoomPercent = 0.01; + else if (value > 1) zoomPercent = 1; + else zoomPercent = value; + } + } + /// + /// 新图像宽度的百分比 + /// + double widthLocationPercent; + /// + /// 新图像高度的百分比 + /// + double heightLocationPercent; + + + public Rectangle GetSourceImage(Image image) + { + int rawImageHeight= image.Height; + int rawImageWidth= image.Width; + int NewImageX = (int)(rawImageWidth * widthLocationPercent); + int NewImageY = (int)(rawImageHeight * heightLocationPercent); + int NewImageSize = (int)(Math.Min(rawImageHeight, rawImageWidth) * zoomPercent); + return new Rectangle(NewImageX - NewImageSize/2, NewImageY - NewImageSize / 2, NewImageSize, NewImageSize); + } + + /// + /// 获取当前缩放数据 + /// + /// + /// + /// + /// + public ZoomFactor(Rectangle previewBoxRectangle, Point location, int imageWidth, int imageHeight) + { + double X = location.X; // - previewBoxRectangle.X; + double Y = location.Y;// - previewBoxRectangle.Y; + if ((double)imageWidth / (double)imageHeight > (double)previewBoxRectangle.Width / (double)previewBoxRectangle.Height) + { + double truePreviewBoxHeight = previewBoxRectangle.Width * ((double)imageHeight / (double)imageWidth); + double offsetY = (previewBoxRectangle.Height - truePreviewBoxHeight) * 0.5; + //图像比预览框更宽 + widthLocationPercent = X / (double)previewBoxRectangle.Width; + heightLocationPercent = (Y - offsetY) / truePreviewBoxHeight; + } + else + { + double truePreivewBoxWidth = previewBoxRectangle.Height * ((double)imageWidth / (double)imageHeight); + double offsetX = (previewBoxRectangle.Width - truePreivewBoxWidth) * 0.5; + widthLocationPercent = (X - offsetX) / truePreivewBoxWidth; + heightLocationPercent = Y / (double)previewBoxRectangle.Height; + } + + //Debug.WriteLine("On Move percent w = {0}, h = {1}", widthLocationPercent, heightLocationPercent); + } + } + +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7e9da3f --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("ImageCompressor")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ImageCompressor")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("8db25786-04b5-4d20-ae2f-a3db997e0df0")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..f221e72 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace ImageCompressor.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ImageCompressor.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..8dde3b3 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace ImageCompressor.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Resources/Icon.ico b/Resources/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..13232d7d654735d00d5e079c9e953ffa2825dd5d GIT binary patch literal 48903 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 REgt}U>1i2jmZ>|2{vW*>2G;-p literal 0 HcmV?d00001 diff --git a/Utils/Localize.cs b/Utils/Localize.cs new file mode 100644 index 0000000..0cd78f6 --- /dev/null +++ b/Utils/Localize.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageCompressor +{ + internal class Localize + { + + public static bool IsEN = CultureInfo.CurrentCulture.Name != "zh-CN"; + public static string Get(string name) + { + if (IsEN) return name; + else return CN[name]; + } + static readonly Dictionary CN = new Dictionary() + { + {"(Skiped)", "(跳过)"}, + {"_Compressed", "_压缩"}, + {"{0}min {1}s", "{0}分{1}秒"}, + {"{0}s", "{0}秒"}, + {"Cannot Create JPG Comporessor", "无法初始化JPG压缩设置"}, + {"Cannot create save folder. ", "无法创建新的储存文件夹"}, + {"Cannot delete original image: ", "无法删除原文件: " }, + {"Compress Level (1-10)", "压缩质量(1-10)"}, + {"Compressed {0}, Skiped {1}, Failed {2}, ", "已压缩 {0}, 跳过 {1},失败 {2}, "}, + {"Done !!!", "结束"}, + {"Done", "结束"}, + {"Drag and Drop Folders Here To Start", "将包含图像的文件夹拖入此处"}, + {"Estimate Fail", "无法估算"}, + {"Failed Images Info", "压缩图片失败"}, + {"Find {0} Imgs , Sum Size = {1}", "找到 {0} 张图片 , 总共大小 = {1}"}, + {"Image Compressor", "图像压缩工具"}, + {"Include SubFolders", "包含子文件夹"}, + {"Keep Original (Compress in new folder)", "保留源文件(储存到新文件夹)"}, + {"Max Pixel Limit", "像素限制"}, + {"Missing", "丢失"}, + {"New Image Size Estimate: ", "压缩前后大小估计: "}, + {"No Folders Droped", "没有找到拖入的文件夹"}, + {"No Images (JPG, PNG, BMP) Found in Folder Droped", "拖入文件夹内没有发现图像 (JPG, PNG, BMP)"}, + {"Paused, Click to Continue", "压缩暂停,单机继续"}, + {"Read file error at ", "打开图像失败:"}, + {"Read file missing", "读取文件丢失"}, + {"Read file not exist. ", "要读取的图像不存在"}, + {"Read image larger than 256 MB", "不能处理大于256MB的图片"}, + {"Ready", "单击开始压缩"}, + {"Run", "压缩中"}, + {"Running, Click to Pause", "压缩中,单击以暂停"}, + {"Running, Wait to Pause", "结束压缩中,马上暂停"}, + {"Save file error at ", "储存图像失败:"}, + {"Save file is occupied. ", "要保存的图像被其他程序占用"}, + {"Save file is ReadOnly. ", "要保存的图像是只读的"}, + {"Skip File Size (KB)", "跳过小图片(KB)"}, + {"Time {0}, Compressed Result {1} / {2}", "耗时 {0}, 压缩前后总大小 {1} / {2}"}, + {"Waiting for image folders", "等待拖入图片文件夹"}, + {"Warning", "警告"}, + }; + } +}