From 8dac7544845926472cca51d4f7f5f615c83b9808 Mon Sep 17 00:00:00 2001 From: Jaex Date: Sun, 30 Apr 2023 23:26:17 +0300 Subject: [PATCH] Added background type option to image beautifier --- ShareX.HelpersLib/Colors/GradientInfo.cs | 20 ++- ShareX.HelpersLib/Helpers/Helpers.cs | 9 ++ ShareX.HelpersLib/Helpers/ImageHelpers.cs | 47 ++++++- ShareX.MediaLib/Enums.cs | 9 ++ .../Forms/ImageBeautifierForm.Designer.cs | 40 +++++- ShareX.MediaLib/Forms/ImageBeautifierForm.cs | 130 ++++++++++-------- .../Forms/ImageBeautifierForm.resx | 3 + ShareX.MediaLib/ImageBeautifierOptions.cs | 79 ++++++++++- 8 files changed, 269 insertions(+), 68 deletions(-) diff --git a/ShareX.HelpersLib/Colors/GradientInfo.cs b/ShareX.HelpersLib/Colors/GradientInfo.cs index cb76e7848..b3eff4b6c 100644 --- a/ShareX.HelpersLib/Colors/GradientInfo.cs +++ b/ShareX.HelpersLib/Colors/GradientInfo.cs @@ -49,18 +49,22 @@ public class GradientInfo [JsonIgnore] public bool IsTransparent => IsValid && Colors.Any(x => x.Color.IsTransparent()); - public GradientInfo() + public GradientInfo() : this(LinearGradientMode.Vertical) { - Type = LinearGradientMode.Vertical; + } + + public GradientInfo(LinearGradientMode type) + { + Type = type; Colors = new List(); } - public GradientInfo(params GradientStop[] colors) : this() + public GradientInfo(LinearGradientMode type, params GradientStop[] colors) : this(type) { Colors = colors.ToList(); } - public GradientInfo(params Color[] colors) : this() + public GradientInfo(LinearGradientMode type, params Color[] colors) : this(type) { for (int i = 0; i < colors.Length; i++) { @@ -68,6 +72,14 @@ public GradientInfo(params Color[] colors) : this() } } + public GradientInfo(params GradientStop[] colors) : this(LinearGradientMode.Vertical, colors) + { + } + + public GradientInfo(params Color[] colors) : this(LinearGradientMode.Vertical, colors) + { + } + public void Clear() { Colors.Clear(); diff --git a/ShareX.HelpersLib/Helpers/Helpers.cs b/ShareX.HelpersLib/Helpers/Helpers.cs index 4e028759c..7c76b1c97 100644 --- a/ShareX.HelpersLib/Helpers/Helpers.cs +++ b/ShareX.HelpersLib/Helpers/Helpers.cs @@ -1021,5 +1021,14 @@ public static bool IsDefaultSettings(IEnumerable current, IEnumerable s return true; } + + public static string GetDesktopWallpaperFilePath() + { + byte[] transcodedImageCache = (byte[])RegistryHelpers.GetValue(@"Control Panel\Desktop", "TranscodedImageCache"); + byte[] transcodedImageCacheDest = new byte[transcodedImageCache.Length - 24]; + Array.Copy(transcodedImageCache, 24, transcodedImageCacheDest, 0, transcodedImageCacheDest.Length); + string wallpaperFilePath = Encoding.Unicode.GetString(transcodedImageCacheDest); + return wallpaperFilePath.TrimEnd('\0'); + } } } \ No newline at end of file diff --git a/ShareX.HelpersLib/Helpers/ImageHelpers.cs b/ShareX.HelpersLib/Helpers/ImageHelpers.cs index 975b79e5c..2b833ee60 100644 --- a/ShareX.HelpersLib/Helpers/ImageHelpers.cs +++ b/ShareX.HelpersLib/Helpers/ImageHelpers.cs @@ -229,18 +229,15 @@ private static Bitmap ApplyCutOutEffect(Bitmap bmp, AnchorStyles effectEdge, Cut { case CutOutEffectType.None: return bmp; - case CutOutEffectType.ZigZag: return TornEdges(bmp, effectSize, effectSize, effectEdge, false, false); - case CutOutEffectType.TornEdge: return TornEdges(bmp, effectSize, effectSize * 2, effectEdge, false, true); - case CutOutEffectType.Wave: return WavyEdges(bmp, effectSize, effectSize * 5, effectEdge); } - throw new NotImplementedException(); // should not be reachable + throw new NotImplementedException(); } public static Bitmap CutOutBitmapMiddle(Bitmap bmp, Orientation orientation, int start, int size, CutOutEffectType effectType, int effectSize) @@ -509,6 +506,48 @@ public static Bitmap AddCanvas(Image img, Padding margin, Color canvasColor) return bmp; } + public static Bitmap AddBackgroundImage(Bitmap bmp, Bitmap backgroundImage) + { + if (backgroundImage != null) + { + using (bmp) + using (backgroundImage) + { + Bitmap result = new Bitmap(bmp.Width, bmp.Height); + + float aspectRatio = (float)backgroundImage.Width / backgroundImage.Height; + + int width = result.Width; + int height = (int)(width / aspectRatio); + + if (height < result.Height) + { + height = result.Height; + width = (int)(height * aspectRatio); + } + + int centerX = (result.Width - width) / 2; + int centerY = (result.Height - height) / 2; + + using (Graphics graphics = Graphics.FromImage(result)) + { + graphics.DrawImage(backgroundImage, centerX, centerY, width, height); + graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height); + } + + return result; + } + } + + return bmp; + } + + public static Bitmap AddBackgroundImage(Bitmap bmp, string backgroundImageFilePath) + { + Bitmap backgroundImage = LoadImage(backgroundImageFilePath); + return AddBackgroundImage(bmp, backgroundImage); + } + public static Bitmap RoundedCorners(Bitmap bmp, int cornerRadius) { Bitmap bmpResult = bmp.CreateEmptyBitmap(); diff --git a/ShareX.MediaLib/Enums.cs b/ShareX.MediaLib/Enums.cs index d4bb1a50b..a005f367e 100644 --- a/ShareX.MediaLib/Enums.cs +++ b/ShareX.MediaLib/Enums.cs @@ -58,4 +58,13 @@ public enum ConverterVideoCodecs [Description("APNG")] apng } + + public enum ImageBeautifierBackgroundType + { + Gradient, + Color, + Image, + Desktop, + Transparent + } } \ No newline at end of file diff --git a/ShareX.MediaLib/Forms/ImageBeautifierForm.Designer.cs b/ShareX.MediaLib/Forms/ImageBeautifierForm.Designer.cs index 0d640ed22..6b2d29e57 100644 --- a/ShareX.MediaLib/Forms/ImageBeautifierForm.Designer.cs +++ b/ShareX.MediaLib/Forms/ImageBeautifierForm.Designer.cs @@ -46,6 +46,7 @@ private void InitializeComponent() this.tlpMain = new System.Windows.Forms.TableLayoutPanel(); this.pbPreview = new ShareX.HelpersLib.MyPictureBox(); this.pOptions = new System.Windows.Forms.Panel(); + this.cbBackgroundType = new System.Windows.Forms.ComboBox(); this.btnPrint = new System.Windows.Forms.Button(); this.btnSave = new System.Windows.Forms.Button(); this.btnUpload = new System.Windows.Forms.Button(); @@ -53,6 +54,8 @@ private void InitializeComponent() this.btnCopy = new System.Windows.Forms.Button(); this.pbBackground = new System.Windows.Forms.PictureBox(); this.ttMain = new System.Windows.Forms.ToolTip(this.components); + this.btnBackgroundImageFilePathBrowse = new System.Windows.Forms.Button(); + this.lblBackgroundImageFilePath = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.tbMargin)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.tbPadding)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.tbRoundedCorner)).BeginInit(); @@ -240,6 +243,9 @@ private void InitializeComponent() // // pOptions // + this.pOptions.Controls.Add(this.lblBackgroundImageFilePath); + this.pOptions.Controls.Add(this.btnBackgroundImageFilePathBrowse); + this.pOptions.Controls.Add(this.cbBackgroundType); this.pOptions.Controls.Add(this.btnPrint); this.pOptions.Controls.Add(this.btnSave); this.pOptions.Controls.Add(this.btnUpload); @@ -266,6 +272,16 @@ private void InitializeComponent() this.pOptions.Size = new System.Drawing.Size(329, 755); this.pOptions.TabIndex = 0; // + // cbBackgroundType + // + this.cbBackgroundType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbBackgroundType.FormattingEnabled = true; + this.cbBackgroundType.Location = new System.Drawing.Point(16, 360); + this.cbBackgroundType.Name = "cbBackgroundType"; + this.cbBackgroundType.Size = new System.Drawing.Size(296, 25); + this.cbBackgroundType.TabIndex = 19; + this.cbBackgroundType.SelectedIndexChanged += new System.EventHandler(this.cbBackgroundType_SelectedIndexChanged); + // // btnPrint // this.btnPrint.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -329,13 +345,30 @@ private void InitializeComponent() // pbBackground // this.pbBackground.Cursor = System.Windows.Forms.Cursors.Hand; - this.pbBackground.Location = new System.Drawing.Point(16, 360); + this.pbBackground.Location = new System.Drawing.Point(16, 392); this.pbBackground.Name = "pbBackground"; this.pbBackground.Size = new System.Drawing.Size(296, 40); this.pbBackground.TabIndex = 14; this.pbBackground.TabStop = false; this.pbBackground.Click += new System.EventHandler(this.pbBackground_Click); // + // btnBackgroundImageFilePathBrowse + // + this.btnBackgroundImageFilePathBrowse.Location = new System.Drawing.Point(16, 392); + this.btnBackgroundImageFilePathBrowse.Name = "btnBackgroundImageFilePathBrowse"; + this.btnBackgroundImageFilePathBrowse.Size = new System.Drawing.Size(296, 32); + this.btnBackgroundImageFilePathBrowse.TabIndex = 21; + this.btnBackgroundImageFilePathBrowse.Text = "Browse image file..."; + this.btnBackgroundImageFilePathBrowse.UseVisualStyleBackColor = true; + this.btnBackgroundImageFilePathBrowse.Click += new System.EventHandler(this.btnBackgroundImageFilePathBrowse_Click); + // + // lblBackgroundImageFilePath + // + this.lblBackgroundImageFilePath.Location = new System.Drawing.Point(13, 432); + this.lblBackgroundImageFilePath.Name = "lblBackgroundImageFilePath"; + this.lblBackgroundImageFilePath.Size = new System.Drawing.Size(296, 120); + this.lblBackgroundImageFilePath.TabIndex = 22; + // // ImageBeautifierForm // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); @@ -344,7 +377,7 @@ private void InitializeComponent() this.Controls.Add(this.tlpMain); this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.MinimumSize = new System.Drawing.Size(1000, 600); + this.MinimumSize = new System.Drawing.Size(1000, 700); this.Name = "ImageBeautifierForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; @@ -387,5 +420,8 @@ private void InitializeComponent() private System.Windows.Forms.Button btnCopy; private System.Windows.Forms.Button btnPrint; private System.Windows.Forms.ToolTip ttMain; + private System.Windows.Forms.ComboBox cbBackgroundType; + private System.Windows.Forms.Button btnBackgroundImageFilePathBrowse; + private System.Windows.Forms.Label lblBackgroundImageFilePath; } } \ No newline at end of file diff --git a/ShareX.MediaLib/Forms/ImageBeautifierForm.cs b/ShareX.MediaLib/Forms/ImageBeautifierForm.cs index 98c58a79d..2ce3bce1d 100644 --- a/ShareX.MediaLib/Forms/ImageBeautifierForm.cs +++ b/ShareX.MediaLib/Forms/ImageBeautifierForm.cs @@ -60,6 +60,9 @@ private ImageBeautifierForm(ImageBeautifierOptions options = null) cbSmartPadding.Checked = Options.SmartPadding; tbRoundedCorner.SetValue(Options.RoundedCorner); tbShadowSize.SetValue(Options.ShadowSize); + cbBackgroundType.Items.AddRange(Helpers.GetLocalizedEnumDescriptions()); + cbBackgroundType.SelectedIndex = (int)Options.BackgroundType; + lblBackgroundImageFilePath.Text = Options.BackgroundImageFilePath; UpdateUI(); UpdateBackgroundPreview(); @@ -83,12 +86,41 @@ private void UpdateUI() lblPaddingValue.Text = tbPadding.Value.ToString(); lblRoundedCornerValue.Text = tbRoundedCorner.Value.ToString(); lblShadowSizeValue.Text = tbShadowSize.Value.ToString(); + lblBackgroundImageFilePath.Text = Options.BackgroundImageFilePath; } private void UpdateBackgroundPreview() { pbBackground.Image?.Dispose(); - pbBackground.Image = Options.Background.CreateGradientPreview(pbBackground.ClientRectangle.Width, pbBackground.ClientRectangle.Height, true, true); + pbBackground.Image = null; + + switch (Options.BackgroundType) + { + case ImageBeautifierBackgroundType.Gradient: + pbBackground.Visible = true; + lblBackgroundImageFilePath.Visible = false; + btnBackgroundImageFilePathBrowse.Visible = false; + pbBackground.Image = Options.BackgroundGradient.CreateGradientPreview(pbBackground.ClientRectangle.Width, pbBackground.ClientRectangle.Height, true, true); + break; + case ImageBeautifierBackgroundType.Color: + pbBackground.Visible = true; + lblBackgroundImageFilePath.Visible = false; + btnBackgroundImageFilePathBrowse.Visible = false; + pbBackground.Image = new GradientInfo(Options.BackgroundColor). + CreateGradientPreview(pbBackground.ClientRectangle.Width, pbBackground.ClientRectangle.Height, true, true); + break; + case ImageBeautifierBackgroundType.Image: + pbBackground.Visible = false; + lblBackgroundImageFilePath.Visible = true; + btnBackgroundImageFilePathBrowse.Visible = true; + break; + case ImageBeautifierBackgroundType.Desktop: + case ImageBeautifierBackgroundType.Transparent: + pbBackground.Visible = false; + lblBackgroundImageFilePath.Visible = false; + btnBackgroundImageFilePathBrowse.Visible = false; + break; + } } private async Task UpdatePreview() @@ -107,7 +139,7 @@ private async Task UpdatePreview() UpdateOptions(); - Bitmap resultImage = await RenderPreviewAsync(SourceImage, Options); + Bitmap resultImage = await Options.RenderAsync(SourceImage); PreviewImage?.Dispose(); PreviewImage = resultImage; pbPreview.LoadImage(PreviewImage); @@ -124,52 +156,6 @@ private async Task UpdatePreview() } } - private static async Task RenderPreviewAsync(Bitmap sourceImage, ImageBeautifierOptions options) - { - return await Task.Run(() => - { - Bitmap resultImage = (Bitmap)sourceImage.Clone(); - - if (options.SmartPadding) - { - resultImage = ImageHelpers.AutoCropImage(resultImage, true, AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, options.Padding); - } - else if (options.Padding > 0) - { - Color color = resultImage.GetPixel(0, 0); - Bitmap resultImageNew = ImageHelpers.AddCanvas(resultImage, options.Padding, color); - resultImage.Dispose(); - resultImage = resultImageNew; - } - - if (options.RoundedCorner > 0) - { - resultImage = ImageHelpers.RoundedCorners(resultImage, options.RoundedCorner); - } - - if (options.Margin > 0) - { - Bitmap resultImageNew = ImageHelpers.AddCanvas(resultImage, options.Margin); - resultImage.Dispose(); - resultImage = resultImageNew; - } - - if (options.ShadowSize > 0) - { - resultImage = ImageHelpers.AddShadow(resultImage, 1f, options.ShadowSize, 0f, Color.Black, new Point(0, 0), false); - } - - if (options.Background != null && options.Background.IsValid) - { - Bitmap resultImageNew = ImageHelpers.FillBackground(resultImage, options.Background); - resultImage.Dispose(); - resultImage = resultImageNew; - } - - return resultImage; - }); - } - private void UpdateOptions() { Options.Margin = tbMargin.Value; @@ -264,17 +250,51 @@ private async void tbShadowSize_Scroll(object sender, EventArgs e) await UpdatePreview(); } + private async void cbBackgroundType_SelectedIndexChanged(object sender, EventArgs e) + { + Options.BackgroundType = (ImageBeautifierBackgroundType)cbBackgroundType.SelectedIndex; + UpdateBackgroundPreview(); + + await UpdatePreview(); + } + private async void pbBackground_Click(object sender, EventArgs e) { - using (GradientPickerForm gradientPickerForm = new GradientPickerForm(Options.Background.Copy())) + switch (Options.BackgroundType) { - if (gradientPickerForm.ShowDialog() == DialogResult.OK) - { - Options.Background = gradientPickerForm.Gradient; - UpdateBackgroundPreview(); + case ImageBeautifierBackgroundType.Gradient: + using (GradientPickerForm gradientPickerForm = new GradientPickerForm(Options.BackgroundGradient.Copy())) + { + if (gradientPickerForm.ShowDialog() == DialogResult.OK) + { + Options.BackgroundGradient = gradientPickerForm.Gradient; + UpdateBackgroundPreview(); - await UpdatePreview(); - } + await UpdatePreview(); + } + } + break; + case ImageBeautifierBackgroundType.Color: + if (ColorPickerForm.PickColor(Options.BackgroundColor, out Color newColor, this)) + { + Options.BackgroundColor = newColor; + UpdateBackgroundPreview(); + + await UpdatePreview(); + } + break; + } + } + + private async void btnBackgroundImageFilePathBrowse_Click(object sender, EventArgs e) + { + string filePath = ImageHelpers.OpenImageFileDialog(this); + + if (!string.IsNullOrEmpty(filePath)) + { + Options.BackgroundImageFilePath = filePath; + + await UpdatePreview(); } } } diff --git a/ShareX.MediaLib/Forms/ImageBeautifierForm.resx b/ShareX.MediaLib/Forms/ImageBeautifierForm.resx index 5a824bff2..1d44453f5 100644 --- a/ShareX.MediaLib/Forms/ImageBeautifierForm.resx +++ b/ShareX.MediaLib/Forms/ImageBeautifierForm.resx @@ -120,6 +120,9 @@ 17, 17 + + 17, 17 + 58 diff --git a/ShareX.MediaLib/ImageBeautifierOptions.cs b/ShareX.MediaLib/ImageBeautifierOptions.cs index 9de0e84fb..589b871b9 100644 --- a/ShareX.MediaLib/ImageBeautifierOptions.cs +++ b/ShareX.MediaLib/ImageBeautifierOptions.cs @@ -26,6 +26,8 @@ using ShareX.HelpersLib; using System.Drawing; using System.Drawing.Drawing2D; +using System.Threading.Tasks; +using System.Windows.Forms; namespace ShareX.MediaLib { @@ -36,9 +38,80 @@ public class ImageBeautifierOptions public bool SmartPadding { get; set; } = true; public int RoundedCorner { get; set; } = 20; public int ShadowSize { get; set; } = 30; - public GradientInfo Background { get; set; } = new GradientInfo(Color.FromArgb(255, 81, 47), Color.FromArgb(221, 36, 118)) + public ImageBeautifierBackgroundType BackgroundType { get; set; } = ImageBeautifierBackgroundType.Gradient; + public GradientInfo BackgroundGradient { get; set; } = new GradientInfo(LinearGradientMode.ForwardDiagonal, Color.FromArgb(255, 81, 47), Color.FromArgb(221, 36, 118)); + public Color BackgroundColor { get; set; } = Color.DarkGray; + public string BackgroundImageFilePath { get; set; } = ""; + + public Bitmap Render(Bitmap image) { - Type = LinearGradientMode.ForwardDiagonal - }; + Bitmap resultImage = (Bitmap)image.Clone(); + + if (SmartPadding) + { + resultImage = ImageHelpers.AutoCropImage(resultImage, true, AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, Padding); + } + else if (Padding > 0) + { + Color color = resultImage.GetPixel(0, 0); + Bitmap resultImageNew = ImageHelpers.AddCanvas(resultImage, Padding, color); + resultImage.Dispose(); + resultImage = resultImageNew; + } + + if (RoundedCorner > 0) + { + resultImage = ImageHelpers.RoundedCorners(resultImage, RoundedCorner); + } + + if (Margin > 0) + { + Bitmap resultImageNew = ImageHelpers.AddCanvas(resultImage, Margin); + resultImage.Dispose(); + resultImage = resultImageNew; + } + + if (ShadowSize > 0) + { + resultImage = ImageHelpers.AddShadow(resultImage, 1f, ShadowSize, 0f, Color.Black, new Point(0, 0), false); + } + + switch (BackgroundType) + { + case ImageBeautifierBackgroundType.Gradient: + if (BackgroundGradient != null && BackgroundGradient.IsVisible) + { + Bitmap resultImageNew = ImageHelpers.FillBackground(resultImage, BackgroundGradient); + resultImage.Dispose(); + resultImage = resultImageNew; + } + break; + case ImageBeautifierBackgroundType.Color: + if (!BackgroundColor.IsTransparent()) + { + Bitmap resultImageNew = ImageHelpers.FillBackground(resultImage, BackgroundColor); + resultImage.Dispose(); + resultImage = resultImageNew; + } + break; + case ImageBeautifierBackgroundType.Image: + resultImage = ImageHelpers.AddBackgroundImage(resultImage, BackgroundImageFilePath); + break; + case ImageBeautifierBackgroundType.Desktop: + string desktopWallpaperFilePath = Helpers.GetDesktopWallpaperFilePath(); + resultImage = ImageHelpers.AddBackgroundImage(resultImage, desktopWallpaperFilePath); + break; + default: + case ImageBeautifierBackgroundType.Transparent: + break; + } + + return resultImage; + } + + public async Task RenderAsync(Bitmap image) + { + return await Task.Run(() => Render(image)); + } } } \ No newline at end of file