diff --git a/ShareX.HelpersLib/ApplicationInstanceManager.cs b/ShareX.HelpersLib/ApplicationInstanceManager.cs index 42b86751d..5c3d1c034 100644 --- a/ShareX.HelpersLib/ApplicationInstanceManager.cs +++ b/ShareX.HelpersLib/ApplicationInstanceManager.cs @@ -23,11 +23,11 @@ You should have received a copy of the GNU General Public License #endregion License Information (GPL v3) -using Newtonsoft.Json; using System; -using System.IO; -using System.IO.Pipes; -using System.Text; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Channels; +using System.Runtime.Remoting.Channels.Ipc; +using System.Security.Permissions; using System.Threading; namespace ShareX.HelpersLib @@ -36,15 +36,15 @@ public class ApplicationInstanceManager : IDisposable { private static readonly string MutexName = "82E6AC09-0FEF-4390-AD9F-0DD3F5561EFC"; private static readonly string AppName = "ShareX"; - private static readonly string PipeName = $"{Environment.MachineName}-{Environment.UserName}-{AppName}"; - private static readonly string SemaphoreName = PipeName + "Semaphore"; + private static readonly string EventName = string.Format("{0}-{1}-{2}", Environment.MachineName, Environment.UserName, AppName); + private static readonly string SemaphoreName = string.Format("{0}{1}", EventName, "Semaphore"); public bool IsSingleInstance { get; private set; } public bool IsFirstInstance { get; private set; } private Mutex mutex; private Semaphore semaphore; - private NamedPipeServerStream pipeServer; + private IpcServerChannel serverChannel; public ApplicationInstanceManager(bool isSingleInstance, string[] args, EventHandler callback) { @@ -75,28 +75,44 @@ public void Dispose() { if (IsFirstInstance) { - mutex.ReleaseMutex(); - } + if (mutex != null) + { + mutex.ReleaseMutex(); + } - mutex.Dispose(); - semaphore?.Dispose(); - pipeServer?.Dispose(); + if (serverChannel != null) + { + ChannelServices.UnregisterChannel(serverChannel); + } + + if (semaphore != null) + { + semaphore.Close(); + } + } } private void CreateFirstInstance(EventHandler callback) { try { - semaphore = new Semaphore(1, 1, SemaphoreName, out var createdNew); - // Mixing single instance and multi instance (via command line parameter) copies of the program can - // result in CreateFirstInstance being called if it isn't really the first one. Make sure this is - // really first instance by detecting if the semaphore was created - if (!createdNew) - { - return; - } + bool createdNew; - CreateServer(callback); + using (EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, EventName, out createdNew)) + { + // Mixing single instance and multi instance (via command line parameter) copies of the program can + // result in CreateFirstInstance being called if it isn't really the first one. Make sure this is + // really first instance by detecting if EventWaitHandle was created + if (!createdNew) + { + return; + } + + semaphore = new Semaphore(1, 1, SemaphoreName); + ThreadPool.RegisterWaitForSingleObject(eventWaitHandle, WaitOrTimerCallback, callback, Timeout.Infinite, false); + + RegisterRemoteType(AppName); + } } catch (Exception e) { @@ -108,11 +124,19 @@ private void CreateMultipleInstance(string[] args) { try { - semaphore = Semaphore.OpenExisting(SemaphoreName); + InstanceProxy.CommandLineArgs = args; - // Wait until the server is ready to accept data - semaphore.WaitOne(); - SendDataToServer(args); + using (EventWaitHandle eventWaitHandle = EventWaitHandle.OpenExisting(EventName)) + { + semaphore = Semaphore.OpenExisting(SemaphoreName); + semaphore.WaitOne(); + UpdateRemoteObject(AppName); + + if (eventWaitHandle != null) + { + eventWaitHandle.Set(); + } + } } catch (Exception e) { @@ -122,67 +146,69 @@ private void CreateMultipleInstance(string[] args) Environment.Exit(0); } - private void SendDataToServer(string[] args) + private void UpdateRemoteObject(string uri) { - using (var pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.Out)) + IpcClientChannel clientChannel = new IpcClientChannel(); + ChannelServices.RegisterChannel(clientChannel, true); + + InstanceProxy proxy = Activator.GetObject(typeof(InstanceProxy), string.Format("ipc://{0}{1}{2}/{2}", Environment.MachineName, Environment.UserName, uri)) as InstanceProxy; + + if (proxy != null) { - pipeClient.Connect(); - - var pipeData = new InstanceCallbackEventArgs - { - CommandLineArgs = args - }; - - var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(pipeData)); - pipeClient.Write(bytes, 0, bytes.Length); + proxy.SetCommandLineArgs(InstanceProxy.CommandLineArgs); } + + ChannelServices.UnregisterChannel(clientChannel); } - private void CreateServer(EventHandler callback) + private void RegisterRemoteType(string uri) { - pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); - pipeServer.BeginWaitForConnection(ConnectionCallback, callback); + serverChannel = new IpcServerChannel(Environment.MachineName + Environment.UserName + uri); + ChannelServices.RegisterChannel(serverChannel, true); + + RemotingConfiguration.RegisterWellKnownServiceType(typeof(InstanceProxy), uri, WellKnownObjectMode.Singleton); } - private void ConnectionCallback(IAsyncResult ar) + private void WaitOrTimerCallback(object state, bool timedOut) { - try - { - pipeServer.EndWaitForConnection(ar); - } - catch (ObjectDisposedException) - { - // Operation got aborted as part of program exit. - return; - } + EventHandler callback = state as EventHandler; - var callback = ar.AsyncState as EventHandler; - var sr = new StreamReader(pipeServer, Encoding.UTF8); - try + if (callback != null) { - if (callback != null) + try { - var data = sr.ReadToEnd(); - callback(this, JsonConvert.DeserializeObject(data)); + callback(state, new InstanceCallbackEventArgs(InstanceProxy.CommandLineArgs)); + } + finally + { + if (semaphore != null) + { + semaphore.Release(); + } } } - finally - { - // Close the existing server - sr.Dispose(); + } + } - // Create a new server - CreateServer(callback); + [Serializable] + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + internal class InstanceProxy : MarshalByRefObject + { + public static string[] CommandLineArgs { get; internal set; } - // Signal that we are ready to accept a new connection - semaphore.Release(); - } + public void SetCommandLineArgs(string[] commandLineArgs) + { + CommandLineArgs = commandLineArgs; } } public class InstanceCallbackEventArgs : EventArgs { - [JsonProperty] - public string[] CommandLineArgs { get; internal set; } + public string[] CommandLineArgs { get; private set; } + + internal InstanceCallbackEventArgs(string[] commandLineArgs) + { + CommandLineArgs = commandLineArgs; + } } } \ No newline at end of file diff --git a/ShareX.HelpersLib/CLI/CLICommand.cs b/ShareX.HelpersLib/CLI/CLICommand.cs index e3a2d7d08..e4a6cb4e2 100644 --- a/ShareX.HelpersLib/CLI/CLICommand.cs +++ b/ShareX.HelpersLib/CLI/CLICommand.cs @@ -46,11 +46,18 @@ public bool CheckCommand(string command) public override string ToString() { - string text = string.Format("Command: \"{0}\"", Command); + string text = ""; + + if (IsCommand) + { + text += "-"; + } + + text += Command; if (!string.IsNullOrEmpty(Parameter)) { - text += string.Format(" Parameter: \"{0}\"", Parameter); + text += " \"" + Parameter + "\""; } return text; diff --git a/ShareX.HelpersLib/Colors/GradientInfo.cs b/ShareX.HelpersLib/Colors/GradientInfo.cs index cb2b02e21..9b5347e64 100644 --- a/ShareX.HelpersLib/Colors/GradientInfo.cs +++ b/ShareX.HelpersLib/Colors/GradientInfo.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License #endregion License Information (GPL v3) +using Newtonsoft.Json; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; @@ -38,6 +39,7 @@ public class GradientInfo public List Colors { get; set; } + [JsonIgnore] public bool IsValid => Colors != null && Colors.Count > 0; public GradientInfo() diff --git a/ShareX.HelpersLib/Controls/ExportImportControl.cs b/ShareX.HelpersLib/Controls/ExportImportControl.cs index 08dd648f4..26a1d4d3d 100644 --- a/ShareX.HelpersLib/Controls/ExportImportControl.cs +++ b/ShareX.HelpersLib/Controls/ExportImportControl.cs @@ -220,10 +220,8 @@ private void OnImportCompleted() } } - private void tsmiImportClipboard_Click(object sender, EventArgs e) + public void ImportJson(string json) { - string json = ClipboardHelpers.GetText(true); - if (!string.IsNullOrEmpty(json)) { OnImportRequested(json); @@ -231,6 +229,18 @@ private void tsmiImportClipboard_Click(object sender, EventArgs e) } } + private void tsmiImportClipboard_Click(object sender, EventArgs e) + { + string json = ClipboardHelpers.GetText(true); + ImportJson(json); + } + + public void ImportFile(string filePath) + { + string json = File.ReadAllText(filePath, Encoding.UTF8); + OnImportRequested(json); + } + private void tsmiImportFile_Click(object sender, EventArgs e) { string filter = "Settings (*.json)|*.json|All files (*.*)|*.*"; @@ -246,8 +256,7 @@ private void tsmiImportFile_Click(object sender, EventArgs e) { foreach (string filename in ofd.FileNames) { - string json = File.ReadAllText(filename, Encoding.UTF8); - OnImportRequested(json); + ImportFile(filename); } OnImportCompleted(); diff --git a/ShareX.HelpersLib/Enums.cs b/ShareX.HelpersLib/Enums.cs index d2ac30d28..9ab197155 100644 --- a/ShareX.HelpersLib/Enums.cs +++ b/ShareX.HelpersLib/Enums.cs @@ -188,4 +188,13 @@ public enum ImageCombinerAlignment Center, RightOrBottom } + + public enum ImageInterpolationMode // Localized + { + HighQualityBicubic, + Bicubic, + HighQualityBilinear, + Bilinear, + NearestNeighbor + } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Forms/GradientPickerForm.cs b/ShareX.HelpersLib/Forms/GradientPickerForm.cs index 315747ca3..5ee89266a 100644 --- a/ShareX.HelpersLib/Forms/GradientPickerForm.cs +++ b/ShareX.HelpersLib/Forms/GradientPickerForm.cs @@ -197,7 +197,7 @@ private void nudLocation_ValueChanged(object sender, EventArgs e) { if (isReady) { - GradientStop gradientStop = GetSelectedGradientStop(out ListViewItem lvi); + GradientStop gradientStop = GetSelectedGradientStop(); if (gradientStop != null) { diff --git a/ShareX.HelpersLib/Helpers/Helpers.cs b/ShareX.HelpersLib/Helpers/Helpers.cs index b55d67a77..3e65601fe 100644 --- a/ShareX.HelpersLib/Helpers/Helpers.cs +++ b/ShareX.HelpersLib/Helpers/Helpers.cs @@ -791,12 +791,20 @@ public static bool BrowseFolder(string title, TextBox tb, string initialDirector return false; } - public static string GetVariableFolderPath(string path) + public static string GetVariableFolderPath(string path, bool supportCustomSpecialFolders = false) { if (!string.IsNullOrEmpty(path)) { try { + if (supportCustomSpecialFolders) + { + foreach (KeyValuePair specialFolder in HelpersOptions.ShareXSpecialFolders) + { + path = path.Replace(specialFolder.Value, $"%{specialFolder.Key}%", StringComparison.OrdinalIgnoreCase); + } + } + foreach (Environment.SpecialFolder specialFolder in GetEnums()) { path = path.Replace(Environment.GetFolderPath(specialFolder), $"%{specialFolder}%", StringComparison.OrdinalIgnoreCase); @@ -811,12 +819,20 @@ public static string GetVariableFolderPath(string path) return path; } - public static string ExpandFolderVariables(string path) + public static string ExpandFolderVariables(string path, bool supportCustomSpecialFolders = false) { if (!string.IsNullOrEmpty(path)) { try { + if (supportCustomSpecialFolders) + { + foreach (KeyValuePair specialFolder in HelpersOptions.ShareXSpecialFolders) + { + path = path.Replace($"%{specialFolder.Key}%", specialFolder.Value, StringComparison.OrdinalIgnoreCase); + } + } + foreach (Environment.SpecialFolder specialFolder in GetEnums()) { path = path.Replace($"%{specialFolder}%", Environment.GetFolderPath(specialFolder), StringComparison.OrdinalIgnoreCase); @@ -908,7 +924,7 @@ public static long GetFileSize(string path) return -1; } - public static void CreateDirectoryFromDirectoryPath(string directoryPath) + public static void CreateDirectory(string directoryPath) { if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath)) { @@ -930,7 +946,7 @@ public static void CreateDirectoryFromFilePath(string filePath) if (!string.IsNullOrEmpty(filePath)) { string directoryPath = Path.GetDirectoryName(filePath); - CreateDirectoryFromDirectoryPath(directoryPath); + CreateDirectory(directoryPath); } } @@ -955,7 +971,7 @@ public static string CopyFile(string filePath, string destinationFolder, bool ov { string fileName = Path.GetFileName(filePath); string destinationFilePath = Path.Combine(destinationFolder, fileName); - CreateDirectoryFromDirectoryPath(destinationFolder); + CreateDirectory(destinationFolder); File.Copy(filePath, destinationFilePath, overwrite); return destinationFilePath; } @@ -969,7 +985,7 @@ public static string MoveFile(string filePath, string destinationFolder, bool ov { string fileName = Path.GetFileName(filePath); string destinationFilePath = Path.Combine(destinationFolder, fileName); - CreateDirectoryFromDirectoryPath(destinationFolder); + CreateDirectory(destinationFolder); if (overwrite && File.Exists(destinationFilePath)) { @@ -1015,7 +1031,7 @@ public static string BackupFileWeekly(string filePath, string destinationFolder) if (!File.Exists(newFilePath)) { - CreateDirectoryFromDirectoryPath(destinationFolder); + CreateDirectory(destinationFolder); File.Copy(filePath, newFilePath, false); return newFilePath; } @@ -1035,7 +1051,7 @@ public static void BackupFileMonthly(string filePath, string destinationFolder) if (!File.Exists(newFilePath)) { - CreateDirectoryFromDirectoryPath(destinationFolder); + CreateDirectory(destinationFolder); File.Copy(filePath, newFilePath, false); } } diff --git a/ShareX.HelpersLib/Helpers/ImageHelpers.cs b/ShareX.HelpersLib/Helpers/ImageHelpers.cs index 6f908a301..eceb7898c 100644 --- a/ShareX.HelpersLib/Helpers/ImageHelpers.cs +++ b/ShareX.HelpersLib/Helpers/ImageHelpers.cs @@ -2078,5 +2078,23 @@ public static Size GetImageFileDimensions(string filePath) return Size.Empty; } + + public static InterpolationMode GetInterpolationMode(ImageInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + default: + case ImageInterpolationMode.HighQualityBicubic: + return InterpolationMode.HighQualityBicubic; + case ImageInterpolationMode.Bicubic: + return InterpolationMode.Bicubic; + case ImageInterpolationMode.HighQualityBilinear: + return InterpolationMode.HighQualityBilinear; + case ImageInterpolationMode.Bilinear: + return InterpolationMode.Bilinear; + case ImageInterpolationMode.NearestNeighbor: + return InterpolationMode.NearestNeighbor; + } + } } } \ No newline at end of file diff --git a/ShareX.HelpersLib/HelpersOptions.cs b/ShareX.HelpersLib/HelpersOptions.cs index 91eeffd25..a48b2dc00 100644 --- a/ShareX.HelpersLib/HelpersOptions.cs +++ b/ShareX.HelpersLib/HelpersOptions.cs @@ -40,5 +40,6 @@ public static class HelpersOptions public static List RecentColors { get; set; } = new List(); public static string LastSaveDirectory { get; set; } = ""; public static bool URLEncodeIgnoreEmoji { get; set; } = false; + public static Dictionary ShareXSpecialFolders { get; set; } = new Dictionary(); } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Properties/Resources.Designer.cs b/ShareX.HelpersLib/Properties/Resources.Designer.cs index eac34bfca..bae32c7fe 100644 --- a/ShareX.HelpersLib/Properties/Resources.Designer.cs +++ b/ShareX.HelpersLib/Properties/Resources.Designer.cs @@ -146,7 +146,7 @@ internal static string adjectives { } /// - /// Looks up a localized string similar to Add image effects / watermark. + /// Looks up a localized string similar to Add image effects. /// internal static string AfterCaptureTasks_AddImageEffects { get { @@ -2058,51 +2058,6 @@ internal static string ImageDestination_FileUploader { } } - /// - /// Looks up a localized string similar to Bicubic. - /// - internal static string ImageEditorInterpolationMode_Bicubic { - get { - return ResourceManager.GetString("ImageEditorInterpolationMode_Bicubic", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bilinear. - /// - internal static string ImageEditorInterpolationMode_Bilinear { - get { - return ResourceManager.GetString("ImageEditorInterpolationMode_Bilinear", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to High quality bicubic. - /// - internal static string ImageEditorInterpolationMode_HighQualityBicubic { - get { - return ResourceManager.GetString("ImageEditorInterpolationMode_HighQualityBicubic", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to High quality bilinear. - /// - internal static string ImageEditorInterpolationMode_HighQualityBilinear { - get { - return ResourceManager.GetString("ImageEditorInterpolationMode_HighQualityBilinear", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Nearest neighbor. - /// - internal static string ImageEditorInterpolationMode_NearestNeighbor { - get { - return ResourceManager.GetString("ImageEditorInterpolationMode_NearestNeighbor", resourceCulture); - } - } - /// /// Looks up a localized string similar to Auto size. /// @@ -2148,6 +2103,51 @@ internal static string ImageEditorStartMode_PreviousState { } } + /// + /// Looks up a localized string similar to Bicubic. + /// + internal static string ImageInterpolationMode_Bicubic { + get { + return ResourceManager.GetString("ImageInterpolationMode_Bicubic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bilinear. + /// + internal static string ImageInterpolationMode_Bilinear { + get { + return ResourceManager.GetString("ImageInterpolationMode_Bilinear", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High quality bicubic. + /// + internal static string ImageInterpolationMode_HighQualityBicubic { + get { + return ResourceManager.GetString("ImageInterpolationMode_HighQualityBicubic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High quality bilinear. + /// + internal static string ImageInterpolationMode_HighQualityBilinear { + get { + return ResourceManager.GetString("ImageInterpolationMode_HighQualityBilinear", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nearest neighbor. + /// + internal static string ImageInterpolationMode_NearestNeighbor { + get { + return ResourceManager.GetString("ImageInterpolationMode_NearestNeighbor", resourceCulture); + } + } + /// /// Looks up a localized string similar to Big square. /// @@ -2251,9 +2251,19 @@ internal static System.Drawing.Bitmap Loading { /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static System.Drawing.Bitmap LoadingSmall { + internal static System.Drawing.Bitmap LoadingSmallBlack { get { - object obj = ResourceManager.GetObject("LoadingSmall", resourceCulture); + object obj = ResourceManager.GetObject("LoadingSmallBlack", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap LoadingSmallWhite { + get { + object obj = ResourceManager.GetObject("LoadingSmallWhite", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } diff --git a/ShareX.HelpersLib/Properties/Resources.resx b/ShareX.HelpersLib/Properties/Resources.resx index b487622e4..9500916ca 100644 --- a/ShareX.HelpersLib/Properties/Resources.resx +++ b/ShareX.HelpersLib/Properties/Resources.resx @@ -135,7 +135,7 @@ Custom text uploader - + High quality bicubic @@ -477,7 +477,7 @@ Would you like to download it? Manual - Add image effects / watermark + Add image effects Delete file locally @@ -683,7 +683,7 @@ Would you like to download and install it? Screen record - + Bilinear @@ -710,7 +710,7 @@ Would you like to download and install it? Paste - + High quality bilinear @@ -734,7 +734,7 @@ Would you like to download and install it? Remove shape or cancel capture - + Nearest neighbor @@ -746,7 +746,7 @@ Would you like to download and install it? Status: {0} - + Bicubic @@ -1193,9 +1193,6 @@ Would you like to download and install it? Amazon S3 Standard-Infrequent Access - - ..\Resources\LoadingSmall.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Random non ambiguous alphanumeric char. Repeat using {n} @@ -1250,4 +1247,10 @@ Would you like to download and install it? Amazon S3 One Zone-Infrequent Access + + ..\Resources\LoadingSmallBlack.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LoadingSmallWhite.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/ShareX.HelpersLib/Resources/LoadingSmall.gif b/ShareX.HelpersLib/Resources/LoadingSmallBlack.gif similarity index 100% rename from ShareX.HelpersLib/Resources/LoadingSmall.gif rename to ShareX.HelpersLib/Resources/LoadingSmallBlack.gif diff --git a/ShareX.HelpersLib/Resources/LoadingSmallWhite.gif b/ShareX.HelpersLib/Resources/LoadingSmallWhite.gif new file mode 100644 index 000000000..dc6640f1c Binary files /dev/null and b/ShareX.HelpersLib/Resources/LoadingSmallWhite.gif differ diff --git a/ShareX.HelpersLib/Settings/SettingsBase.cs b/ShareX.HelpersLib/Settings/SettingsBase.cs index 40bdc81c1..dcc665708 100644 --- a/ShareX.HelpersLib/Settings/SettingsBase.cs +++ b/ShareX.HelpersLib/Settings/SettingsBase.cs @@ -161,7 +161,7 @@ private bool SaveInternal(string filePath) { string fileName = Path.GetFileName(filePath); backupFilePath = Path.Combine(BackupFolder, fileName); - Helpers.CreateDirectoryFromDirectoryPath(BackupFolder); + Helpers.CreateDirectory(BackupFolder); } File.Replace(tempFilePath, filePath, backupFilePath); diff --git a/ShareX.HelpersLib/ShareX.HelpersLib.csproj b/ShareX.HelpersLib/ShareX.HelpersLib.csproj index d36e1b73c..6f10e3d65 100644 --- a/ShareX.HelpersLib/ShareX.HelpersLib.csproj +++ b/ShareX.HelpersLib/ShareX.HelpersLib.csproj @@ -1473,7 +1473,10 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/ShareX.ImageEffectsLib/ImageEffectsForm.Designer.cs b/ShareX.ImageEffectsLib/ImageEffectsForm.Designer.cs index 6b1146506..eeb0c4e65 100644 --- a/ShareX.ImageEffectsLib/ImageEffectsForm.Designer.cs +++ b/ShareX.ImageEffectsLib/ImageEffectsForm.Designer.cs @@ -56,7 +56,13 @@ private void InitializeComponent() this.btnRefresh = new System.Windows.Forms.Button(); this.btnDuplicatePreset = new System.Windows.Forms.Button(); this.lblPresets = new System.Windows.Forms.Label(); + this.btnPackager = new System.Windows.Forms.Button(); + this.scMain = new ShareX.HelpersLib.SplitContainerCustomSplitter(); this.cmsLoadImage.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.scMain)).BeginInit(); + this.scMain.Panel1.SuspendLayout(); + this.scMain.Panel2.SuspendLayout(); + this.scMain.SuspendLayout(); this.SuspendLayout(); // // pgSettings @@ -139,9 +145,9 @@ private void InitializeComponent() // // pbResult // - resources.ApplyResources(this.pbResult, "pbResult"); this.pbResult.BackColor = System.Drawing.SystemColors.Window; this.pbResult.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + resources.ApplyResources(this.pbResult, "pbResult"); this.pbResult.DrawCheckeredBackground = true; this.pbResult.EnableRightClickMenu = true; this.pbResult.FullscreenOnClick = true; @@ -259,12 +265,36 @@ private void InitializeComponent() resources.ApplyResources(this.lblPresets, "lblPresets"); this.lblPresets.Name = "lblPresets"; // + // btnPackager + // + resources.ApplyResources(this.btnPackager, "btnPackager"); + this.btnPackager.Name = "btnPackager"; + this.btnPackager.UseVisualStyleBackColor = true; + this.btnPackager.Click += new System.EventHandler(this.btnPackager_Click); + // + // scMain + // + resources.ApplyResources(this.scMain, "scMain"); + this.scMain.Name = "scMain"; + // + // scMain.Panel1 + // + this.scMain.Panel1.Controls.Add(this.pgSettings); + // + // scMain.Panel2 + // + this.scMain.Panel2.Controls.Add(this.pbResult); + this.scMain.SplitterColor = System.Drawing.Color.White; + this.scMain.SplitterLineColor = System.Drawing.Color.FromArgb(((int)(((byte)(189)))), ((int)(((byte)(189)))), ((int)(((byte)(189))))); + // // ImageEffectsForm // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Window; this.CancelButton = this.btnClose; + this.Controls.Add(this.scMain); + this.Controls.Add(this.btnPackager); this.Controls.Add(this.lblPresets); this.Controls.Add(this.btnDuplicatePreset); this.Controls.Add(this.btnRefresh); @@ -283,13 +313,15 @@ private void InitializeComponent() this.Controls.Add(this.btnClear); this.Controls.Add(this.btnRemove); this.Controls.Add(this.btnAdd); - this.Controls.Add(this.pgSettings); this.Controls.Add(this.lvEffects); - this.Controls.Add(this.pbResult); this.Name = "ImageEffectsForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Shown += new System.EventHandler(this.ImageEffectsForm_Shown); this.cmsLoadImage.ResumeLayout(false); + this.scMain.Panel1.ResumeLayout(false); + this.scMain.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.scMain)).EndInit(); + this.scMain.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -323,6 +355,8 @@ private void InitializeComponent() private System.Windows.Forms.Button btnRefresh; private System.Windows.Forms.Button btnDuplicatePreset; private System.Windows.Forms.Label lblPresets; + private System.Windows.Forms.Button btnPackager; + private HelpersLib.SplitContainerCustomSplitter scMain; } } diff --git a/ShareX.ImageEffectsLib/ImageEffectsForm.cs b/ShareX.ImageEffectsLib/ImageEffectsForm.cs index 646b6b13f..f78846e9b 100644 --- a/ShareX.ImageEffectsLib/ImageEffectsForm.cs +++ b/ShareX.ImageEffectsLib/ImageEffectsForm.cs @@ -35,6 +35,10 @@ namespace ShareX.ImageEffectsLib { public partial class ImageEffectsForm : Form { + public static bool IsInstanceActive => instance != null && !instance.IsDisposed; + + private static ImageEffectsForm instance; + public event Action ImageProcessRequested; public bool AutoGeneratePreviewImage { get; set; } @@ -48,6 +52,8 @@ public partial class ImageEffectsForm : Form public ImageEffectsForm(Bitmap bmp, List presets, int selectedPresetIndex) { + pauseUpdate = true; + InitializeComponent(); ShareXResources.ApplyTheme(this); @@ -64,9 +70,24 @@ public ImageEffectsForm(Bitmap bmp, List presets, int selecte } SelectedPresetIndex = selectedPresetIndex; + eiImageEffects.ObjectType = typeof(ImageEffectPreset); eiImageEffects.SerializationBinder = new TypeNameSerializationBinder("ShareX.ImageEffectsLib", "ShareX.ImageEffectsLib"); + AddAllEffectsToContextMenu(); + LoadSettings(); + + pauseUpdate = false; + } + + public static ImageEffectsForm GetFormInstance(List presets, int selectedPresetIndex) + { + if (!IsInstanceActive) + { + instance = new ImageEffectsForm(null, presets, selectedPresetIndex); + } + + return instance; } public void EnableToolMode(Action imageProcessRequested, string filePath = null) @@ -85,6 +106,11 @@ public void EditorMode() btnClose.Text = Resources.ImageEffectsForm_EditorMode_Cancel; } + public void ImportImageEffect(string json) + { + eiImageEffects.ImportJson(json); + } + protected void OnImageProcessRequested(Bitmap bmp) { ImageProcessRequested?.Invoke(bmp); @@ -161,8 +187,6 @@ private void AddEffectToContextMenu(string groupName, params Type[] imageEffects private void LoadSettings() { - pauseUpdate = true; - foreach (ImageEffectPreset preset in Presets) { cbPresets.Items.Add(preset); @@ -174,8 +198,6 @@ private void LoadSettings() } UpdateControlStates(); - - pauseUpdate = false; } private ImageEffectPreset GetSelectedPreset() @@ -201,7 +223,9 @@ private void AddPreset(ImageEffectPreset preset) { Presets.Add(preset); cbPresets.Items.Add(preset); + ignorePresetsSelectedIndexChanged = true; cbPresets.SelectedIndex = cbPresets.Items.Count - 1; + ignorePresetsSelectedIndexChanged = false; LoadPreset(preset); txtPresetName.Focus(); } @@ -419,7 +443,6 @@ private void LoadPreset(ImageEffectPreset preset) private void ImageEffectsForm_Shown(object sender, EventArgs e) { - LoadSettings(); this.ForceActivate(); } @@ -462,10 +485,10 @@ private void btnDuplicatePreset_Click(object sender, EventArgs e) private void cbPresets_SelectedIndexChanged(object sender, EventArgs e) { + SelectedPresetIndex = cbPresets.SelectedIndex; + if (!ignorePresetsSelectedIndexChanged) { - SelectedPresetIndex = cbPresets.SelectedIndex; - ImageEffectPreset preset = GetSelectedPreset(); if (preset != null) { @@ -565,7 +588,7 @@ private void lvEffects_SelectedIndexChanged(object sender, EventArgs e) private void lvEffects_ItemChecked(object sender, ItemCheckedEventArgs e) { - if (e.Item != null && e.Item.Tag is ImageEffect) + if (e.Item != null && e.Item.Focused && e.Item.Tag is ImageEffect) { ImageEffect imageEffect = (ImageEffect)e.Item.Tag; imageEffect.Enabled = e.Item.Checked; @@ -608,6 +631,33 @@ private void eiImageEffects_ImportRequested(object obj) } } + private void btnPackager_Click(object sender, EventArgs e) + { + ImageEffectPreset preset = GetSelectedPreset(); + + if (preset != null) + { + if (string.IsNullOrEmpty(preset.Name)) + { + // TODO: Translate + MessageBox.Show("Preset name cannot be empty.", "ShareX - " + "Missing preset name", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + else + { + string json = eiImageEffects.Serialize(preset); + + if (!string.IsNullOrEmpty(json)) + { + using (ImageEffectPackagerForm packagerForm = new ImageEffectPackagerForm(json, preset.Name, + HelpersOptions.ShareXSpecialFolders["ShareXImageEffects"])) + { + packagerForm.ShowDialog(); + } + } + } + } + } + private void tsmiLoadImageFromFile_Click(object sender, EventArgs e) { string filePath = ImageHelpers.OpenImageFileDialog(); diff --git a/ShareX.ImageEffectsLib/ImageEffectsForm.resx b/ShareX.ImageEffectsLib/ImageEffectsForm.resx index 98d7486fc..32c9892f4 100644 --- a/ShareX.ImageEffectsLib/ImageEffectsForm.resx +++ b/ShareX.ImageEffectsLib/ImageEffectsForm.resx @@ -118,15 +118,15 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Top, Bottom, Left + + Fill - 184, 72 + 0, 0 - 336, 424 + 330, 424 @@ -139,10 +139,10 @@ System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - $this + scMain.Panel1 - 20 + 0 408, 40 @@ -166,14 +166,11 @@ $this - 19 + 21 Top, Bottom, Left - - 164 - 8, 72 @@ -193,7 +190,10 @@ $this - 21 + 22 + + + 164 520, 40 @@ -217,7 +217,7 @@ $this - 18 + 20 744, 40 @@ -241,7 +241,7 @@ $this - 17 + 19 632, 40 @@ -265,7 +265,7 @@ $this - 16 + 18 Bottom, Left @@ -274,13 +274,13 @@ True - 328, 504 + 456, 504 120, 24 - 19 + 20 Save image... @@ -298,7 +298,7 @@ $this - 15 + 17 Bottom, Left @@ -322,16 +322,16 @@ $this - 14 + 16 - - Top, Bottom, Left, Right + + Fill - 528, 72 + 0, 0 - 432, 424 + 440, 424 16 @@ -343,10 +343,10 @@ ShareX.HelpersLib.MyPictureBox, ShareX.HelpersLib, Version=13.1.1.0, Culture=neutral, PublicKeyToken=null - $this + scMain.Panel2 - 22 + 0 17, 17 @@ -364,23 +364,11 @@ Bottom, Left - 200, 504 + 328, 504 126, 17 - - 130, 22 - - - From file... - - - 130, 22 - - - From clipboard - 131, 48 @@ -394,7 +382,7 @@ 120, 24 - 18 + 19 Load image @@ -412,7 +400,19 @@ $this - 13 + 15 + + + 130, 22 + + + From file... + + + 130, 22 + + + From clipboard 408, 8 @@ -436,7 +436,7 @@ $this - 12 + 14 552, 8 @@ -460,7 +460,7 @@ $this - 11 + 13 104, 10 @@ -481,7 +481,7 @@ $this - 10 + 12 True @@ -508,7 +508,7 @@ $this - 9 + 11 104, 42 @@ -529,7 +529,7 @@ $this - 8 + 10 Bottom, Right @@ -556,7 +556,7 @@ $this - 7 + 9 Bottom, Right @@ -586,19 +586,19 @@ $this - 6 + 8 Bottom, Left - 456, 504 + 584, 504 120, 24 - 20 + 21 Upload image @@ -616,7 +616,7 @@ $this - 5 + 7 856, 40 @@ -640,7 +640,7 @@ $this - 4 + 6 696, 8 @@ -664,7 +664,7 @@ $this - 3 + 5 True @@ -691,7 +691,88 @@ $this - 2 + 4 + + + Bottom, Left + + + 200, 504 + + + 120, 24 + + + 18 + + + Packager... + + + btnPackager + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Bottom, Left, Right + + + 184, 72 + + + scMain.Panel1 + + + System.Windows.Forms.SplitterPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + scMain + + + 0 + + + scMain.Panel2 + + + System.Windows.Forms.SplitterPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + scMain + + + 1 + + + 776, 424 + + + 330 + + + 6 + + + 22 + + + scMain + + + ShareX.HelpersLib.SplitContainerCustomSplitter, ShareX.HelpersLib, Version=13.1.1.0, Culture=neutral, PublicKeyToken=null + + + $this + + + 0 True diff --git a/ShareX.ImageEffectsLib/ShareX.ImageEffectsLib.csproj b/ShareX.ImageEffectsLib/ShareX.ImageEffectsLib.csproj index 9388f7e6d..45f067e61 100644 --- a/ShareX.ImageEffectsLib/ShareX.ImageEffectsLib.csproj +++ b/ShareX.ImageEffectsLib/ShareX.ImageEffectsLib.csproj @@ -95,6 +95,7 @@ + @@ -130,6 +131,13 @@ + + + Form + + + ImageEffectPackagerForm.cs + @@ -174,6 +182,9 @@ + + ImageEffectPackagerForm.cs + ImageEffectsForm.cs diff --git a/ShareX.ImageEffectsLib/WatermarkForm.cs b/ShareX.ImageEffectsLib/WatermarkForm.cs index b6d0fcf87..37238bb6e 100644 --- a/ShareX.ImageEffectsLib/WatermarkForm.cs +++ b/ShareX.ImageEffectsLib/WatermarkForm.cs @@ -35,7 +35,7 @@ namespace ShareX.ImageEffectsLib public partial class WatermarkForm : Form { private WatermarkConfig config; - private bool IsGuiReady; + private bool isReady; public WatermarkForm(WatermarkConfig watermarkConfig) { @@ -85,7 +85,7 @@ private void WatermarkUI_Load(object sender, EventArgs e) txtWatermarkImageLocation.Text = config.Image.ImageLocation; - IsGuiReady = true; + isReady = true; UpdatePreview(); } @@ -96,7 +96,7 @@ private void WatermarkUI_Resize(object sender, EventArgs e) private void UpdatePreview() { - if (IsGuiReady) + if (isReady) { using (Bitmap bmp = new Bitmap(pbPreview.ClientSize.Width, pbPreview.ClientSize.Height)) { diff --git a/ShareX.MediaLib/FFmpegDownloader.cs b/ShareX.MediaLib/FFmpegDownloader.cs index 0ff1ae4b5..6cd3605b2 100644 --- a/ShareX.MediaLib/FFmpegDownloader.cs +++ b/ShareX.MediaLib/FFmpegDownloader.cs @@ -25,7 +25,6 @@ You should have received a copy of the GNU General Public License using ShareX.HelpersLib; using System; -using System.Collections.Generic; using System.Windows.Forms; namespace ShareX.MediaLib @@ -59,7 +58,7 @@ public static bool ExtractFFmpeg(string archivePath, string extractPath) { try { - ZipManager.Extract(archivePath, extractPath, false, new List() { "ffmpeg.exe" }); + ZipManager.Extract(archivePath, extractPath, false, entry => entry.Name.Equals("ffmpeg.exe", StringComparison.OrdinalIgnoreCase)); return true; } catch (Exception e) diff --git a/ShareX.MediaLib/ShareX.MediaLib.csproj b/ShareX.MediaLib/ShareX.MediaLib.csproj index d5e2aa3fc..466f54e5a 100644 --- a/ShareX.MediaLib/ShareX.MediaLib.csproj +++ b/ShareX.MediaLib/ShareX.MediaLib.csproj @@ -70,6 +70,7 @@ + diff --git a/ShareX.MediaLib/VideoThumbnailer.cs b/ShareX.MediaLib/VideoThumbnailer.cs index 312529345..d0d9ae88d 100644 --- a/ShareX.MediaLib/VideoThumbnailer.cs +++ b/ShareX.MediaLib/VideoThumbnailer.cs @@ -178,7 +178,7 @@ private string GetOutputDirectory() break; } - Helpers.CreateDirectoryFromDirectoryPath(directory); + Helpers.CreateDirectory(directory); return directory; } diff --git a/ShareX.ScreenCaptureLib/Enums.cs b/ShareX.ScreenCaptureLib/Enums.cs index dcc82c923..8904f47e8 100644 --- a/ShareX.ScreenCaptureLib/Enums.cs +++ b/ShareX.ScreenCaptureLib/Enums.cs @@ -318,15 +318,6 @@ public enum ImageEditorStartMode // Localized Fullscreen } - public enum ImageEditorInterpolationMode // Localized - { - HighQualityBicubic, - Bicubic, - HighQualityBilinear, - Bilinear, - NearestNeighbor - } - public enum ImageInsertMethod { Center, diff --git a/ShareX.ScreenCaptureLib/Forms/ImageSizeForm.cs b/ShareX.ScreenCaptureLib/Forms/ImageSizeForm.cs index fb22fffc0..5b85b1743 100644 --- a/ShareX.ScreenCaptureLib/Forms/ImageSizeForm.cs +++ b/ShareX.ScreenCaptureLib/Forms/ImageSizeForm.cs @@ -33,12 +33,12 @@ namespace ShareX.ScreenCaptureLib public partial class ImageSizeForm : Form { public Size ImageSize { get; private set; } - public ImageEditorInterpolationMode InterpolationMode { get; private set; } + public ImageInterpolationMode InterpolationMode { get; private set; } private double widthRatio, heightRatio; private bool ignoreValueChanged = true; - public ImageSizeForm(Size size, ImageEditorInterpolationMode interpolationMode) + public ImageSizeForm(Size size, ImageInterpolationMode interpolationMode) { InitializeComponent(); ShareXResources.ApplyTheme(this); @@ -56,7 +56,7 @@ public ImageSizeForm(Size size, ImageEditorInterpolationMode interpolationMode) nudWidth.TextChanged += NudWidth_TextChanged; nudHeight.TextChanged += NudHeight_TextChanged; - cbResampling.Items.AddRange(Helpers.GetLocalizedEnumDescriptions()); + cbResampling.Items.AddRange(Helpers.GetLocalizedEnumDescriptions()); cbResampling.SelectedIndex = (int)InterpolationMode; ignoreValueChanged = false; @@ -119,7 +119,7 @@ private void cbAspectRatio_CheckedChanged(object sender, EventArgs e) private void cbResampling_SelectedIndexChanged(object sender, EventArgs e) { - InterpolationMode = (ImageEditorInterpolationMode)cbResampling.SelectedIndex; + InterpolationMode = (ImageInterpolationMode)cbResampling.SelectedIndex; } private void btnOK_Click(object sender, EventArgs e) diff --git a/ShareX.ScreenCaptureLib/Forms/TextDrawingInputBox.resx b/ShareX.ScreenCaptureLib/Forms/TextDrawingInputBox.resx index 6a15bef6d..32e5987a6 100644 --- a/ShareX.ScreenCaptureLib/Forms/TextDrawingInputBox.resx +++ b/ShareX.ScreenCaptureLib/Forms/TextDrawingInputBox.resx @@ -747,6 +747,9 @@ Bottom + + Bottom, Left + True diff --git a/ShareX.ScreenCaptureLib/RegionCaptureOptions.cs b/ShareX.ScreenCaptureLib/RegionCaptureOptions.cs index 780b3ee85..88ff7b763 100644 --- a/ShareX.ScreenCaptureLib/RegionCaptureOptions.cs +++ b/ShareX.ScreenCaptureLib/RegionCaptureOptions.cs @@ -89,7 +89,7 @@ public class RegionCaptureOptions public WindowState ImageEditorWindowState = new WindowState(); public bool AutoCloseEditorOnTask = false; public bool ShowEditorPanTip = true; - public ImageEditorInterpolationMode ImageEditorResizeInterpolationMode = ImageEditorInterpolationMode.Bicubic; + public ImageInterpolationMode ImageEditorResizeInterpolationMode = ImageInterpolationMode.Bicubic; public Size EditorNewImageSize = new Size(800, 600); public bool EditorNewImageTransparent = false; public Color EditorNewImageBackgroundColor = Color.White; diff --git a/ShareX.ScreenCaptureLib/Shapes/AnnotationOptions.cs b/ShareX.ScreenCaptureLib/Shapes/AnnotationOptions.cs index fd0965d3b..f07ce4d9e 100644 --- a/ShareX.ScreenCaptureLib/Shapes/AnnotationOptions.cs +++ b/ShareX.ScreenCaptureLib/Shapes/AnnotationOptions.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License #endregion License Information (GPL v3) +using ShareX.HelpersLib; using System.Collections.Generic; using System.Drawing; @@ -74,7 +75,7 @@ public class AnnotationOptions public Color TextFillColor { get; set; } = PrimaryColor; // Image drawing - public ImageEditorInterpolationMode ImageInterpolationMode = ImageEditorInterpolationMode.NearestNeighbor; + public ImageInterpolationMode ImageInterpolationMode = ImageInterpolationMode.NearestNeighbor; public string LastImageFilePath { get; set; } // Step drawing diff --git a/ShareX.ScreenCaptureLib/Shapes/Drawing/ImageDrawingShape.cs b/ShareX.ScreenCaptureLib/Shapes/Drawing/ImageDrawingShape.cs index e7ae26242..20f2951cd 100644 --- a/ShareX.ScreenCaptureLib/Shapes/Drawing/ImageDrawingShape.cs +++ b/ShareX.ScreenCaptureLib/Shapes/Drawing/ImageDrawingShape.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License #endregion License Information (GPL v3) +using ShareX.HelpersLib; using System.Drawing; using System.Drawing.Drawing2D; @@ -33,7 +34,7 @@ public class ImageDrawingShape : BaseDrawingShape public override ShapeType ShapeType { get; } = ShapeType.DrawingImage; public Image Image { get; protected set; } - public ImageEditorInterpolationMode ImageInterpolationMode { get; protected set; } + public ImageInterpolationMode ImageInterpolationMode { get; protected set; } public override void OnConfigLoad() { @@ -79,7 +80,7 @@ protected void DrawImage(Graphics g) if (Image != null) { g.PixelOffsetMode = PixelOffsetMode.Half; - g.InterpolationMode = Manager.GetInterpolationMode(ImageInterpolationMode); + g.InterpolationMode = ImageHelpers.GetInterpolationMode(ImageInterpolationMode); g.DrawImage(Image, Rectangle); diff --git a/ShareX.ScreenCaptureLib/Shapes/Drawing/MagnifyDrawingShape.cs b/ShareX.ScreenCaptureLib/Shapes/Drawing/MagnifyDrawingShape.cs index de291f8eb..013f065bd 100644 --- a/ShareX.ScreenCaptureLib/Shapes/Drawing/MagnifyDrawingShape.cs +++ b/ShareX.ScreenCaptureLib/Shapes/Drawing/MagnifyDrawingShape.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License #endregion License Information (GPL v3) +using ShareX.HelpersLib; using System; using System.Drawing; using System.Drawing.Drawing2D; @@ -34,7 +35,7 @@ public class MagnifyDrawingShape : EllipseDrawingShape public override ShapeType ShapeType { get; } = ShapeType.DrawingMagnify; public int MagnifyStrength { get; set; } = 200; - public ImageEditorInterpolationMode ImageInterpolationMode { get; set; } + public ImageInterpolationMode ImageInterpolationMode { get; set; } public MagnifyDrawingShape() { @@ -58,7 +59,7 @@ public override void OnConfigSave() public override void OnDraw(Graphics g) { g.PixelOffsetMode = PixelOffsetMode.Half; - g.InterpolationMode = Manager.GetInterpolationMode(ImageInterpolationMode); + g.InterpolationMode = ImageHelpers.GetInterpolationMode(ImageInterpolationMode); using (GraphicsPath gp = new GraphicsPath()) { diff --git a/ShareX.ScreenCaptureLib/Shapes/Drawing/StickerDrawingShape.cs b/ShareX.ScreenCaptureLib/Shapes/Drawing/StickerDrawingShape.cs index 8235cc527..fa2370073 100644 --- a/ShareX.ScreenCaptureLib/Shapes/Drawing/StickerDrawingShape.cs +++ b/ShareX.ScreenCaptureLib/Shapes/Drawing/StickerDrawingShape.cs @@ -35,7 +35,7 @@ public class StickerDrawingShape : ImageDrawingShape public override void OnConfigLoad() { - ImageInterpolationMode = ImageEditorInterpolationMode.NearestNeighbor; + ImageInterpolationMode = ImageInterpolationMode.NearestNeighbor; } public override void OnConfigSave() diff --git a/ShareX.ScreenCaptureLib/Shapes/ShapeManager.cs b/ShareX.ScreenCaptureLib/Shapes/ShapeManager.cs index 440a21214..98803140d 100644 --- a/ShareX.ScreenCaptureLib/Shapes/ShapeManager.cs +++ b/ShareX.ScreenCaptureLib/Shapes/ShapeManager.cs @@ -1928,7 +1928,7 @@ private void ChangeImageSize() if (size != oldSize) { - InterpolationMode interpolationMode = GetInterpolationMode(Options.ImageEditorResizeInterpolationMode); + InterpolationMode interpolationMode = ImageHelpers.GetInterpolationMode(Options.ImageEditorResizeInterpolationMode); Bitmap bmp = ImageHelpers.ResizeImage(Form.Canvas, size, interpolationMode); if (bmp != null) @@ -1942,24 +1942,6 @@ private void ChangeImageSize() Form.Resume(); } - internal InterpolationMode GetInterpolationMode(ImageEditorInterpolationMode interpolationMode) - { - switch (interpolationMode) - { - default: - case ImageEditorInterpolationMode.HighQualityBicubic: - return InterpolationMode.HighQualityBicubic; - case ImageEditorInterpolationMode.Bicubic: - return InterpolationMode.Bicubic; - case ImageEditorInterpolationMode.HighQualityBilinear: - return InterpolationMode.HighQualityBilinear; - case ImageEditorInterpolationMode.Bilinear: - return InterpolationMode.Bilinear; - case ImageEditorInterpolationMode.NearestNeighbor: - return InterpolationMode.NearestNeighbor; - } - } - private void ChangeCanvasSize() { Form.Pause(); diff --git a/ShareX.ScreenCaptureLib/Shapes/ShapeManagerMenu.cs b/ShareX.ScreenCaptureLib/Shapes/ShapeManagerMenu.cs index d641c2be4..afe895a7e 100644 --- a/ShareX.ScreenCaptureLib/Shapes/ShapeManagerMenu.cs +++ b/ShareX.ScreenCaptureLib/Shapes/ShapeManagerMenu.cs @@ -506,10 +506,10 @@ internal void CreateToolbar() tsddbShapeOptions.DropDownItems.Add(tslnudCornerRadius); tscbImageInterpolationMode = new ToolStripLabeledComboBox(Resources.ShapeManager_CreateToolbar_InterpolationMode); - tscbImageInterpolationMode.Content.AddRange(Helpers.GetLocalizedEnumDescriptions()); + tscbImageInterpolationMode.Content.AddRange(Helpers.GetLocalizedEnumDescriptions()); tscbImageInterpolationMode.Content.SelectedIndexChanged += (sender, e) => { - AnnotationOptions.ImageInterpolationMode = (ImageEditorInterpolationMode)tscbImageInterpolationMode.Content.SelectedIndex; + AnnotationOptions.ImageInterpolationMode = (ImageInterpolationMode)tscbImageInterpolationMode.Content.SelectedIndex; tscbImageInterpolationMode.Invalidate(); UpdateCurrentShape(); }; diff --git a/ShareX.Setup/Program.cs b/ShareX.Setup/Program.cs index efe602e59..82ed1e05e 100644 --- a/ShareX.Setup/Program.cs +++ b/ShareX.Setup/Program.cs @@ -25,7 +25,6 @@ You should have received a copy of the GNU General Public License using ShareX.HelpersLib; using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -343,7 +342,7 @@ private static void CopyFFmpeg(string destination, bool include32bit, bool inclu if (!File.Exists(FFmpeg32bit)) { string filename = SetupHelpers.DownloadFile("https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.2.2-win32-static.zip"); - ZipManager.Extract(filename, ".", false, new List() { "ffmpeg.exe" }); + ZipManager.Extract(filename, ".", false, entry => entry.Name.Equals("ffmpeg.exe", StringComparison.OrdinalIgnoreCase)); File.Move("ffmpeg.exe", FFmpeg32bit); } @@ -355,7 +354,7 @@ private static void CopyFFmpeg(string destination, bool include32bit, bool inclu if (!File.Exists(FFmpeg64bit)) { string filename = SetupHelpers.DownloadFile("https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.2.2-win64-static.zip"); - ZipManager.Extract(filename, ".", false, new List() { "ffmpeg.exe" }); + ZipManager.Extract(filename, ".", false, entry => entry.Name.Equals("ffmpeg.exe", StringComparison.OrdinalIgnoreCase)); File.Move("ffmpeg.exe", FFmpeg64bit); } diff --git a/ShareX.Setup/ShareX.Setup.csproj b/ShareX.Setup/ShareX.Setup.csproj index a2371671b..ae441455e 100644 --- a/ShareX.Setup/ShareX.Setup.csproj +++ b/ShareX.Setup/ShareX.Setup.csproj @@ -67,6 +67,7 @@ + diff --git a/ShareX.UploadersLib/FileUploaders/GoogleDrive.cs b/ShareX.UploadersLib/FileUploaders/GoogleDrive.cs index 7d33b5eb8..3602eb37d 100644 --- a/ShareX.UploadersLib/FileUploaders/GoogleDrive.cs +++ b/ShareX.UploadersLib/FileUploaders/GoogleDrive.cs @@ -151,7 +151,7 @@ private void SetPermissions(string fileID, GoogleDrivePermissionRole role, Googl { if (!CheckAuthorization()) return; - string url = string.Format("https://www.googleapis.com/drive/v3/files/{0}/permissions", fileID); + string url = string.Format("https://www.googleapis.com/drive/v3/files/{0}/permissions?supportsAllDrives=true", fileID); string json = JsonConvert.SerializeObject(new { diff --git a/ShareX/Forms/AboutForm.cs b/ShareX/Forms/AboutForm.cs index 9954e9562..e1afb21fc 100644 --- a/ShareX/Forms/AboutForm.cs +++ b/ShareX/Forms/AboutForm.cs @@ -61,6 +61,8 @@ public AboutForm() #else if (!Program.PortableApps) { + uclUpdate.UpdateLoadingImage(); + UpdateChecker updateChecker = Program.UpdateManager.CreateUpdateChecker(); uclUpdate.CheckUpdate(updateChecker); } diff --git a/ShareX/Forms/MainForm.cs b/ShareX/Forms/MainForm.cs index bbb895a1c..43fa081b9 100644 --- a/ShareX/Forms/MainForm.cs +++ b/ShareX/Forms/MainForm.cs @@ -315,13 +315,6 @@ public void UpdateControls() InitHotkeys(); -#if !WindowsStore - if (!Program.Portable && !IntegrationHelpers.CheckCustomUploaderExtension()) - { - IntegrationHelpers.CreateCustomUploaderExtension(true); - } -#endif - IsReady = true; } @@ -957,6 +950,7 @@ private void AfterApplicationSettingsJobs() HelpersOptions.RotateImageByExifOrientationData = Program.Settings.RotateImageByExifOrientationData; HelpersOptions.BrowserPath = Program.Settings.BrowserPath; HelpersOptions.RecentColors = Program.Settings.RecentColors; + Program.UpdateHelpersSpecialFolders(); TaskManager.RecentManager.MaxCount = Program.Settings.RecentTasksMaxCount; @@ -1057,18 +1051,28 @@ public void UseCommandLineArgs(List commands) foreach (CLICommand command in commands) { - DebugHelper.WriteLine("CommandLine: " + command.Command); + DebugHelper.WriteLine("CommandLine: " + command); - if (command.IsCommand && command.Command.Equals("CustomUploader", StringComparison.InvariantCultureIgnoreCase)) + if (command.IsCommand) { - TaskHelpers.AddCustomUploader(command.Parameter); + if (command.Command.Equals("CustomUploader", StringComparison.InvariantCultureIgnoreCase)) + { + TaskHelpers.ImportCustomUploader(command.Parameter); - continue; - } + continue; + } - if (command.IsCommand && (CheckCLIHotkey(command) || CheckCLIWorkflow(command))) - { - continue; + if (command.Command.Equals("ImageEffect", StringComparison.InvariantCultureIgnoreCase)) + { + TaskHelpers.ImportImageEffect(command.Parameter); + + continue; + } + + if (CheckCLIHotkey(command) || CheckCLIWorkflow(command)) + { + continue; + } } if (URLHelpers.IsValidURL(command.Command)) diff --git a/ShareX/Forms/TaskSettingsForm.cs b/ShareX/Forms/TaskSettingsForm.cs index 0cf24ecd5..7dee35cb4 100644 --- a/ShareX/Forms/TaskSettingsForm.cs +++ b/ShareX/Forms/TaskSettingsForm.cs @@ -813,12 +813,7 @@ private void chkShowImageEffectsWindowAfterCapture_CheckedChanged(object sender, private void btnImageEffects_Click(object sender, EventArgs e) { - using (ImageEffectsForm imageEffectsForm = new ImageEffectsForm(null, TaskSettings.ImageSettings.ImageEffectPresets, - TaskSettings.ImageSettings.SelectedImageEffectPreset)) - { - imageEffectsForm.ShowDialog(); - TaskSettings.ImageSettings.SelectedImageEffectPreset = imageEffectsForm.SelectedPresetIndex; - } + TaskHelpers.OpenImageEffectsSingleton(TaskSettings); } private void nudThumbnailWidth_ValueChanged(object sender, EventArgs e) diff --git a/ShareX/IntegrationHelpers.cs b/ShareX/IntegrationHelpers.cs index 30694673c..a4304f8a5 100644 --- a/ShareX/IntegrationHelpers.cs +++ b/ShareX/IntegrationHelpers.cs @@ -62,6 +62,15 @@ public static class IntegrationHelpers private static readonly string ShellCustomUploaderCommandPath = $@"{ShellCustomUploaderAssociatePath}\shell\open\command"; private static readonly string ShellCustomUploaderCommandValue = $"{ApplicationPath} -CustomUploader \"%1\""; + private static readonly string ShellImageEffectExtensionPath = @"Software\Classes\.sxie"; + private static readonly string ShellImageEffectExtensionValue = "ShareX.sxie"; + private static readonly string ShellImageEffectAssociatePath = $@"Software\Classes\{ShellImageEffectExtensionValue}"; + private static readonly string ShellImageEffectAssociateValue = "ShareX image effect"; + private static readonly string ShellImageEffectIconPath = $@"{ShellImageEffectAssociatePath}\DefaultIcon"; + private static readonly string ShellImageEffectIconValue = $"{ApplicationPath},0"; + private static readonly string ShellImageEffectCommandPath = $@"{ShellImageEffectAssociatePath}\shell\open\command"; + private static readonly string ShellImageEffectCommandValue = $"{ApplicationPath} -ImageEffect \"%1\""; + private static readonly string ChromeNativeMessagingHosts = @"SOFTWARE\Google\Chrome\NativeMessagingHosts\com.getsharex.sharex"; private static readonly string FirefoxNativeMessagingHosts = @"SOFTWARE\Mozilla\NativeMessagingHosts\ShareX"; @@ -214,6 +223,57 @@ private static void UnregisterCustomUploaderExtension() RegistryHelpers.RemoveRegistry(ShellCustomUploaderAssociatePath, true); } + public static bool CheckImageEffectExtension() + { + try + { + return RegistryHelpers.CheckRegistry(ShellImageEffectExtensionPath, null, ShellImageEffectExtensionValue) && + RegistryHelpers.CheckRegistry(ShellImageEffectCommandPath, null, ShellImageEffectCommandValue); + } + catch (Exception e) + { + DebugHelper.WriteException(e); + } + + return false; + } + + public static void CreateImageEffectExtension(bool create) + { + try + { + if (create) + { + UnregisterImageEffectExtension(); + RegisterImageEffectExtension(); + } + else + { + UnregisterImageEffectExtension(); + } + } + catch (Exception e) + { + DebugHelper.WriteException(e); + } + } + + private static void RegisterImageEffectExtension() + { + RegistryHelpers.CreateRegistry(ShellImageEffectExtensionPath, ShellImageEffectExtensionValue); + RegistryHelpers.CreateRegistry(ShellImageEffectAssociatePath, ShellImageEffectAssociateValue); + RegistryHelpers.CreateRegistry(ShellImageEffectIconPath, ShellImageEffectIconValue); + RegistryHelpers.CreateRegistry(ShellImageEffectCommandPath, ShellImageEffectCommandValue); + + NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_ASSOCCHANGED, HChangeNotifyFlags.SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero); + } + + private static void UnregisterImageEffectExtension() + { + RegistryHelpers.RemoveRegistry(ShellImageEffectExtensionPath); + RegistryHelpers.RemoveRegistry(ShellImageEffectAssociatePath, true); + } + public static bool CheckChromeExtensionSupport() { try @@ -401,6 +461,7 @@ public static void Uninstall() CreateShellContextMenuButton(false); CreateEditShellContextMenuButton(false); CreateCustomUploaderExtension(false); + CreateImageEffectExtension(false); CreateSendToMenuButton(false); } } diff --git a/ShareX/Program.cs b/ShareX/Program.cs index 9bf3f3f6b..3b9090230 100644 --- a/ShareX/Program.cs +++ b/ShareX/Program.cs @@ -232,6 +232,7 @@ public static string ScreenshotsFolder } public static string ToolsFolder => Path.Combine(PersonalFolder, "Tools"); + public static string ImageEffectsFolder => Path.Combine(PersonalFolder, "ImageEffects"); public static string ScreenRecorderCacheFilePath => Path.Combine(PersonalFolder, "ScreenRecorder.avi"); public static string DefaultFFmpegFilePath => Path.Combine(ToolsFolder, "ffmpeg.exe"); public static string ChromeHostManifestFilePath => Path.Combine(ToolsFolder, "Chrome-host-manifest.json"); @@ -315,6 +316,8 @@ private static void Run() IgnoreHotkeyWarning = CLI.IsCommandExist("NoHotkeys"); + CreateParentFolders(); + RegisterExtensions(); CheckPuushMode(); DebugWriteFlags(); CleanTempFiles(); @@ -323,10 +326,9 @@ private static void Run() Uploader.UpdateServicePointManager(); UpdateManager = new GitHubUpdateManager("ShareX", "ShareX", Dev, Portable); - LanguageHelper.ChangeLanguage(Settings.Language); - Helpers.TryFixHandCursor(); + DebugHelper.WriteLine("MainForm init started."); MainForm = new MainForm(); DebugHelper.WriteLine("MainForm init finished."); @@ -470,6 +472,43 @@ private static void UpdatePersonalPath() } } + private static void CreateParentFolders() + { + if (!Sandbox && Directory.Exists(PersonalFolder)) + { + Helpers.CreateDirectory(SettingManager.BackupFolder); + Helpers.CreateDirectory(ImageEffectsFolder); + Helpers.CreateDirectory(LogsFolder); + Helpers.CreateDirectory(ScreenshotsParentFolder); + Helpers.CreateDirectory(ToolsFolder); + } + } + + private static void RegisterExtensions() + { +#if !WindowsStore + if (!Portable) + { + if (!IntegrationHelpers.CheckCustomUploaderExtension()) + { + IntegrationHelpers.CreateCustomUploaderExtension(true); + } + + if (!IntegrationHelpers.CheckImageEffectExtension()) + { + IntegrationHelpers.CreateImageEffectExtension(true); + } + } +#endif + } + + public static void UpdateHelpersSpecialFolders() + { + Dictionary specialFolders = new Dictionary(); + specialFolders.Add("ShareXImageEffects", ImageEffectsFolder); + HelpersOptions.ShareXSpecialFolders = specialFolders; + } + private static void MigratePersonalPathConfig() { if (File.Exists(PreviousPersonalPathConfigFilePath)) diff --git a/ShareX/SettingManager.cs b/ShareX/SettingManager.cs index 97fbc38ca..f567306e8 100644 --- a/ShareX/SettingManager.cs +++ b/ShareX/SettingManager.cs @@ -352,17 +352,17 @@ public static bool Export(string archivePath, bool settings, bool history) if (settings) { - files.Add(ApplicationConfigFilename); - files.Add(HotkeysConfigFilename); - files.Add(UploadersConfigFilename); + files.Add(ApplicationConfigFilePath); + files.Add(HotkeysConfigFilePath); + files.Add(UploadersConfigFilePath); } if (history) { - files.Add(Program.HistoryFilename); + files.Add(Program.HistoryFilePath); } - ZipManager.Compress(archivePath, files, Program.PersonalFolder); + ZipManager.Compress(archivePath, files); return true; } catch (Exception e) diff --git a/ShareX/ShareX.csproj b/ShareX/ShareX.csproj index 4bb4ddc0e..a7d4b7cc8 100644 --- a/ShareX/ShareX.csproj +++ b/ShareX/ShareX.csproj @@ -105,6 +105,7 @@ + diff --git a/ShareX/TaskHelpers.cs b/ShareX/TaskHelpers.cs index bdad016f7..d84d30727 100644 --- a/ShareX/TaskHelpers.cs +++ b/ShareX/TaskHelpers.cs @@ -578,7 +578,7 @@ public static void PrintImage(Image img) } } - public static Bitmap AddImageEffects(Bitmap bmp, TaskSettingsImage taskSettingsImage) + public static Bitmap ApplyImageEffects(Bitmap bmp, TaskSettingsImage taskSettingsImage) { if (bmp != null && !bmp.PixelFormat.HasFlag(PixelFormat.Indexed)) { @@ -1061,6 +1061,28 @@ public static void OpenImageEffects(TaskSettings taskSettings = null) } } + public static ImageEffectsForm OpenImageEffectsSingleton(TaskSettings taskSettings = null) + { + if (taskSettings == null) taskSettings = Program.DefaultTaskSettings; + + bool firstInstance = !ImageEffectsForm.IsInstanceActive; + + ImageEffectsForm imageEffectsForm = ImageEffectsForm.GetFormInstance(taskSettings.ImageSettings.ImageEffectPresets, + taskSettings.ImageSettings.SelectedImageEffectPreset); + + if (firstInstance) + { + imageEffectsForm.FormClosed += (sender, e) => taskSettings.ImageSettings.SelectedImageEffectPreset = imageEffectsForm.SelectedPresetIndex; + imageEffectsForm.Show(); + } + else + { + imageEffectsForm.ForceActivate(); + } + + return imageEffectsForm; + } + public static void OpenMonitorTest() { using (MonitorTestForm monitorTestForm = new MonitorTestForm()) @@ -1566,7 +1588,7 @@ public static Screenshot GetScreenshot(TaskSettings taskSettings = null) return screenshot; } - public static void AddCustomUploader(string filePath) + public static void ImportCustomUploader(string filePath) { if (Program.UploadersConfig != null) { @@ -1595,7 +1617,7 @@ public static void AddCustomUploader(string filePath) if (cui.DestinationType.HasFlag(CustomUploaderDestinationType.TextUploader)) destinations.Add("texts"); if (cui.DestinationType.HasFlag(CustomUploaderDestinationType.FileUploader)) destinations.Add("files"); if (cui.DestinationType.HasFlag(CustomUploaderDestinationType.URLShortener) || - (cui.DestinationType.HasFlag(CustomUploaderDestinationType.URLSharingService))) destinations.Add("urls"); + cui.DestinationType.HasFlag(CustomUploaderDestinationType.URLSharingService)) destinations.Add("urls"); string destinationsText = string.Join("/", destinations); @@ -1666,6 +1688,30 @@ public static void AddCustomUploader(string filePath) } } + public static void ImportImageEffect(string filePath) + { + string configJson = null; + + try + { + configJson = ImageEffectPackager.ExtractPackage(filePath, Program.ImageEffectsFolder); + } + catch (Exception ex) + { + ex.ShowError(); + } + + if (!string.IsNullOrEmpty(configJson)) + { + ImageEffectsForm imageEffectsForm = OpenImageEffectsSingleton(Program.DefaultTaskSettings); + + if (imageEffectsForm != null) + { + imageEffectsForm.ImportImageEffect(configJson); + } + } + } + public static void OpenActionsToolbar() { ActionsToolbarForm.Instance.ForceActivate(); diff --git a/ShareX/WorkerTask.cs b/ShareX/WorkerTask.cs index b5e1674bc..a3da4abbf 100644 --- a/ShareX/WorkerTask.cs +++ b/ShareX/WorkerTask.cs @@ -575,7 +575,7 @@ private bool DoAfterCaptureJobs() if (Info.TaskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.AddImageEffects)) { - Image = TaskHelpers.AddImageEffects(Image, Info.TaskSettings.ImageSettingsReference); + Image = TaskHelpers.ApplyImageEffects(Image, Info.TaskSettings.ImageSettingsReference); if (Image == null) {