From be8997119798f0919c519612bccfd5647bb323e8 Mon Sep 17 00:00:00 2001 From: Julien Richard Date: Sun, 9 Jan 2022 18:05:39 +0100 Subject: [PATCH] New "Emoji" object in editor --- .../Interfaces/Drawing/Container.cs | 5 + src/Greenshot.Base/Interfaces/DrawingModes.cs | 3 +- src/Greenshot.Base/Interfaces/ISurface.cs | 1 + .../Drawing/EmojiContainer.cs | 191 ++++++++++++++++++ .../Drawing/ImageContainer.cs | 19 +- src/Greenshot.Editor/Drawing/Surface.cs | 14 +- .../Forms/ImageEditorForm.Designer.cs | 27 ++- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 8 +- .../Forms/ImageEditorForm.resx | 3 + src/Greenshot.Editor/Greenshot.Editor.csproj | 7 + .../Resources/btnEmoji.Image.bmp | Bin 0 -> 3382 bytes src/Greenshot/Languages/language-en-US.xml | 3 +- 12 files changed, 262 insertions(+), 19 deletions(-) create mode 100644 src/Greenshot.Editor/Drawing/EmojiContainer.cs create mode 100644 src/Greenshot.Editor/Resources/btnEmoji.Image.bmp diff --git a/src/Greenshot.Base/Interfaces/Drawing/Container.cs b/src/Greenshot.Base/Interfaces/Drawing/Container.cs index 7eb595fdf..1fc35eeb2 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Container.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Container.cs @@ -135,6 +135,11 @@ namespace Greenshot.Base.Interfaces.Drawing void Load(string filename); } + public interface IEmojiContainer : IDrawableContainer + { + string Emoji { get; set; } + } + public interface ICursorContainer : IDrawableContainer { Cursor Cursor { get; set; } diff --git a/src/Greenshot.Base/Interfaces/DrawingModes.cs b/src/Greenshot.Base/Interfaces/DrawingModes.cs index cd84aea4f..d406038c5 100644 --- a/src/Greenshot.Base/Interfaces/DrawingModes.cs +++ b/src/Greenshot.Base/Interfaces/DrawingModes.cs @@ -35,6 +35,7 @@ namespace Greenshot.Base.Interfaces Bitmap, Path, SpeechBubble, - StepLabel + StepLabel, + Emoji } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 7b8d6884e..ca0ee3a48 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -93,6 +93,7 @@ namespace Greenshot.Base.Interfaces IImageContainer AddImageContainer(string filename, int x, int y); ICursorContainer AddCursorContainer(string filename, int x, int y); IIconContainer AddIconContainer(string filename, int x, int y); + IEmojiContainer AddEmojiContainer(string emoji, int x, int y, int size); long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); diff --git a/src/Greenshot.Editor/Drawing/EmojiContainer.cs b/src/Greenshot.Editor/Drawing/EmojiContainer.cs new file mode 100644 index 000000000..cd419d79a --- /dev/null +++ b/src/Greenshot.Editor/Drawing/EmojiContainer.cs @@ -0,0 +1,191 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using System.Windows; +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing.Adorners; +using Greenshot.Editor.Helpers; +using log4net; +using Point = System.Drawing.Point; +using Size = System.Windows.Size; + +namespace Greenshot.Editor.Drawing +{ + /// + /// Description of EmojiContainer. + /// + [Serializable] + public class EmojiContainer : DrawableContainer, IEmojiContainer + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); + + [NonSerialized] private System.Windows.Controls.Image _image; + + private int _rotateAngle; + private string _emoji; + + public string Emoji + { + get => _emoji; + set + { + _emoji = value; + if (_image != null) + { + global::Emoji.Wpf.Image.SetSource(_image, Emoji); + } + } + } + + public EmojiContainer(Surface parent) : this(parent, "🙂", size: 64) + { + } + + public EmojiContainer(Surface parent, string emoji, int size) : base(parent) + { + Emoji = emoji; + Width = size; + Height = size; + Init(); + } + + public override void OnDoubleClick() + { + var host = new ElementHost(); + host.Dock = DockStyle.None; + var rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + host.Width = rect.Width; + host.Height = rect.Height; + host.Left = rect.Left; + host.Top = rect.Top; + + var picker = new Emoji.Wpf.Picker { Selection = Emoji }; + picker.Picked += (o, args) => + { + Emoji = args.Emoji; + _parent.Controls.Remove(host); + + }; + host.Child = picker; + + if (_parent != null) + { + _parent.KeysLocked = true; + _parent.Controls.Add(host); + } + + host.Show(); + host.Focus(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + + // Create WPF control + _image = new System.Windows.Controls.Image(); + global::Emoji.Wpf.Image.SetSource(_image, Emoji); + } + + public override void Transform(System.Drawing.Drawing2D.Matrix matrix) + { + _rotateAngle += CalculateAngle(matrix); + _rotateAngle %= 360; + base.Transform(matrix); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + var rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + var iconSize = Math.Min(rect.Width, rect.Height); + + if (iconSize > 0) + { + _image.Measure(new Size(iconSize, iconSize)); + _image.Arrange(new Rect(0, 0, iconSize, iconSize)); + + var renderTargetBitmap = new RenderTargetBitmap(iconSize, iconSize, 96, 96, PixelFormats.Pbgra32); + renderTargetBitmap.Render(_image); + + using var bitmap = BitmapFromSource(renderTargetBitmap); + + if (_rotateAngle != 0) + { + graphics.DrawImage(RotateImage(bitmap, _rotateAngle), Bounds); + return; + } + + graphics.DrawImage(bitmap, Bounds); + } + } + private Bitmap BitmapFromSource(BitmapSource bitmapSource) + { + var src = new FormatConvertedBitmap(); + src.BeginInit(); + src.Source = bitmapSource; + src.DestinationFormat = PixelFormats.Bgra32; + src.EndInit(); + + var bitmap = new Bitmap(src.PixelWidth, src.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + var data = bitmap.LockBits(new Rectangle(new Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + src.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); + bitmap.UnlockBits(data); + + return bitmap; + } + + private static Image RotateImage(Image img, float rotationAngle) + { + var bitmap = new Bitmap(img.Width, img.Height); + + using var gfx = Graphics.FromImage(bitmap); + gfx.InterpolationMode = InterpolationMode.HighQualityBicubic; + + gfx.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2); + gfx.RotateTransform(rotationAngle); + gfx.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2); + + gfx.DrawImage(img, new Point(0, 0)); + + return bitmap; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/ImageContainer.cs b/src/Greenshot.Editor/Drawing/ImageContainer.cs index a46b0dae5..5ccf01c4e 100644 --- a/src/Greenshot.Editor/Drawing/ImageContainer.cs +++ b/src/Greenshot.Editor/Drawing/ImageContainer.cs @@ -179,16 +179,19 @@ namespace Greenshot.Editor.Drawing /// public override void Transform(Matrix matrix) { - int rotateAngle = CalculateAngle(matrix); - // we currently assume only one transformation has been made. - if (rotateAngle != 0) + if (image != null) { - Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); - DisposeShadow(); - using var tmpMatrix = new Matrix(); - using (image) + int rotateAngle = CalculateAngle(matrix); + // we currently assume only one transformation has been made. + if (rotateAngle != 0) { - image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); + Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); + DisposeShadow(); + using var tmpMatrix = new Matrix(); + using (image) + { + image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); + } } } diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 7fd7485d0..644718598 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * @@ -748,6 +748,9 @@ namespace Greenshot.Editor.Drawing case DrawingModes.None: _undrawnElement = null; break; + case DrawingModes.Emoji: + _undrawnElement = new EmojiContainer(this); + break; } if (_undrawnElement != null) @@ -802,6 +805,15 @@ namespace Greenshot.Editor.Drawing return iconContainer; } + public IEmojiContainer AddEmojiContainer(string emoji, int x, int y, int size) + { + var iconContainer = new EmojiContainer(this, emoji, size); + iconContainer.Left = x; + iconContainer.Top = y; + AddElement(iconContainer); + return iconContainer; + } + public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) { CursorContainer cursorContainer = new CursorContainer(this) diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs index 82fecf559..938068f8e 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs @@ -70,7 +70,8 @@ namespace Greenshot.Editor.Forms { this.btnText = new GreenshotToolStripButton(); this.btnSpeechBubble = new GreenshotToolStripButton(); this.btnStepLabel = new GreenshotToolStripButton(); - this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); + this.btnEmoji = new GreenshotToolStripButton(); + this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); this.btnHighlight = new GreenshotToolStripButton(); this.btnObfuscate = new GreenshotToolStripButton(); this.toolStripSplitButton1 = new GreenshotToolStripDropDownButton(); @@ -334,8 +335,9 @@ namespace Greenshot.Editor.Forms { this.btnText, this.btnSpeechBubble, this.btnStepLabel, + this.btnEmoji, this.toolStripSeparator14, - this.btnHighlight, + this.btnHighlight, this.btnObfuscate, this.toolStripSplitButton1, this.toolStripSeparator13, @@ -443,10 +445,20 @@ namespace Greenshot.Editor.Forms { this.btnStepLabel.LanguageKey = "editor_counter"; this.btnStepLabel.Name = "btnStepLabel"; this.btnStepLabel.Click += new System.EventHandler(this.BtnStepLabelClick); - // - // toolStripSeparator14 - // - this.toolStripSeparator14.Name = "toolStripSeparator14"; + // + // btnStepEmoji + // + this.btnEmoji.CheckOnClick = true; + this.btnEmoji.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnEmoji.Image = ((System.Drawing.Image)(resources.GetObject("btnEmoji.Image"))); + this.btnEmoji.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnEmoji.LanguageKey = "editor_emoji"; + this.btnEmoji.Name = "btnEmoji"; + this.btnEmoji.Click += new System.EventHandler(this.BtnEmojiClick); + // + // toolStripSeparator14 + // + this.toolStripSeparator14.Name = "toolStripSeparator14"; // // btnHighlight // @@ -1928,7 +1940,8 @@ namespace Greenshot.Editor.Forms { private GreenshotToolStripButton btnText; private GreenshotToolStripButton btnSpeechBubble; private GreenshotToolStripButton btnStepLabel; - private GreenshotToolStripMenuItem drawLineToolStripMenuItem; + private GreenshotToolStripButton btnEmoji; + private GreenshotToolStripMenuItem drawLineToolStripMenuItem; private GreenshotToolStripButton btnLine; private GreenshotToolStripButton btnSettings; private GreenshotToolStripButton btnHelp; diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index e3b65b980..20b4de8cb 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -269,7 +269,7 @@ namespace Greenshot.Editor.Forms _toolbarButtons = new[] { - btnCursor, btnRect, btnEllipse, btnText, btnLine, btnArrow, btnFreehand, btnHighlight, btnObfuscate, btnCrop, btnStepLabel, btnSpeechBubble + btnCursor, btnRect, btnEllipse, btnText, btnLine, btnArrow, btnFreehand, btnHighlight, btnObfuscate, btnCrop, btnStepLabel, btnSpeechBubble, btnEmoji }; //toolbarDropDownButtons = new ToolStripDropDownButton[]{btnBlur, btnPixeliate, btnTextHighlighter, btnAreaHighlighter, btnMagnifier}; @@ -655,6 +655,12 @@ namespace Greenshot.Editor.Forms RefreshFieldControls(); } + private void BtnEmojiClick(object sender, EventArgs e) + { + _surface.DrawingMode = DrawingModes.Emoji; + RefreshFieldControls(); + } + private void BtnLineClick(object sender, EventArgs e) { _surface.DrawingMode = DrawingModes.Line; diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.resx b/src/Greenshot.Editor/Forms/ImageEditorForm.resx index 57fe2f2c7..63524f930 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.resx +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.resx @@ -1107,4 +1107,7 @@ 782, 17 + + ..\Resources\btnEmoji.Image.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/src/Greenshot.Editor/Greenshot.Editor.csproj b/src/Greenshot.Editor/Greenshot.Editor.csproj index 768bdb99d..601a9f38d 100644 --- a/src/Greenshot.Editor/Greenshot.Editor.csproj +++ b/src/Greenshot.Editor/Greenshot.Editor.csproj @@ -4,6 +4,9 @@ PreserveNewest + + + @@ -81,4 +84,8 @@ ImageEditorForm.cs + + + + \ No newline at end of file diff --git a/src/Greenshot.Editor/Resources/btnEmoji.Image.bmp b/src/Greenshot.Editor/Resources/btnEmoji.Image.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fa6bf1b076793830904adce758867d9a57163a1a GIT binary patch literal 3382 zcmc(gzm6m|5Qpm|q#jO!XK+YJbZJ``(IjP@p#N1sr&YkRU^W+I$pn;2}bS3##df!cf(aNr?Af(!-fxZe)zA@+MO8C#&X##df!dN6aNr?Af(!*} zOHsgqhX@HW6sY!`rR1<4A|%LApth6+9C(P3AVY!LQW0?AAwq%-1!_xGz=4Md2{II@ ztq9M#IPef5L52dg6(``pLxcnw3e;A-fCCQ^5@aY)TZsY=JVZ#4p+IdV2{`Z&Awh-$ zwUsR3z(a%t846V1Q2_@YA|%M|&#ko|z7so7k=Dd&qhpSC;D0H{n-D~nt8laX_w|oK z_P5h%-sV3}w|fbP_n(T{NjPouwsKKv{|e9Fz5l0>>DAR~CbO#V%`q%fd$PP)-fBt} zW3*?H>(9%fJyCA1CX=1hk9BmRW&g20gl#72Y+1GKoxa|6cpPxJR)Ow8TW!q2r?+m` zHy;M<#1y6)O%EC==H>1(U|J?Jtt7^bMY_c&e%&^?Jf(1_I-Ow-p@sJT2%k?&yDyWN zc(vRcZHKJmP&MfJ>0Td>sw9SnKdcW*-yNw=ug>~u(H$bUh9C`8Ut7$u;k>}jn}@;m zyv}_H9Sfaz-?v_bJeJ9t^StF%rB*`LZM`K70MzXbOu`rFvKkQP<|??bP*$!^q0GUF)S?8M1+OyY2UD z`ex+l`Iyv&Fec;`=$&~B;}zq8x=3%~c#(UK)+>$J5&DJDt@{NO)_JCS?TG z>AIiQyuI1CUU)!l3IXa~RZ15_yK1|hx5J6rXVXSCf{v=q5}`vR+&#STETCzqOj)OU z^cm2~^yOza9Bk0m*C^GYzQ9ib~V&+x%t-1K{&L&!b9HGBA@<)ndGSV zt)B`TvWh)D-uqafO=0N|OV7G$=r&!w8jsmoc44O_{Ki?^Dw>{CUmhLIg<8A2YyP8; f6EV~Au=o4pqxmP?>97xrEMb56bm}KU|NGG2fasv9 literal 0 HcmV?d00001 diff --git a/src/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml index 3db9fbf0e..09570f11f 100644 --- a/src/Greenshot/Languages/language-en-US.xml +++ b/src/Greenshot/Languages/language-en-US.xml @@ -305,8 +305,9 @@ All Greenshot features still work directly from the tray icon context menu witho Add counter (I) Add speechbubble (S) + Add emoji - Resize + Resize Resize settings Maintain aspect ratio Width