New "Emoji" object in editor

This commit is contained in:
Julien Richard 2022-01-09 18:05:39 +01:00
commit be89971197
12 changed files with 262 additions and 19 deletions

View file

@ -135,6 +135,11 @@ namespace Greenshot.Base.Interfaces.Drawing
void Load(string filename); void Load(string filename);
} }
public interface IEmojiContainer : IDrawableContainer
{
string Emoji { get; set; }
}
public interface ICursorContainer : IDrawableContainer public interface ICursorContainer : IDrawableContainer
{ {
Cursor Cursor { get; set; } Cursor Cursor { get; set; }

View file

@ -35,6 +35,7 @@ namespace Greenshot.Base.Interfaces
Bitmap, Bitmap,
Path, Path,
SpeechBubble, SpeechBubble,
StepLabel StepLabel,
Emoji
} }
} }

View file

@ -93,6 +93,7 @@ namespace Greenshot.Base.Interfaces
IImageContainer AddImageContainer(string filename, int x, int y); IImageContainer AddImageContainer(string filename, int x, int y);
ICursorContainer AddCursorContainer(string filename, int x, int y); ICursorContainer AddCursorContainer(string filename, int x, int y);
IIconContainer AddIconContainer(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); long SaveElementsToStream(Stream stream);
void LoadElementsFromStream(Stream stream); void LoadElementsFromStream(Stream stream);

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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
{
/// <summary>
/// Description of EmojiContainer.
/// </summary>
[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;
}
}
}

View file

@ -179,16 +179,19 @@ namespace Greenshot.Editor.Drawing
/// <param name="matrix"></param> /// <param name="matrix"></param>
public override void Transform(Matrix matrix) public override void Transform(Matrix matrix)
{ {
int rotateAngle = CalculateAngle(matrix); if (image != null)
// we currently assume only one transformation has been made.
if (rotateAngle != 0)
{ {
Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); int rotateAngle = CalculateAngle(matrix);
DisposeShadow(); // we currently assume only one transformation has been made.
using var tmpMatrix = new Matrix(); if (rotateAngle != 0)
using (image)
{ {
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);
}
} }
} }

View file

@ -1,4 +1,4 @@
/* /*
* Greenshot - a free and open source screenshot tool * Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
* *
@ -748,6 +748,9 @@ namespace Greenshot.Editor.Drawing
case DrawingModes.None: case DrawingModes.None:
_undrawnElement = null; _undrawnElement = null;
break; break;
case DrawingModes.Emoji:
_undrawnElement = new EmojiContainer(this);
break;
} }
if (_undrawnElement != null) if (_undrawnElement != null)
@ -802,6 +805,15 @@ namespace Greenshot.Editor.Drawing
return iconContainer; 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) public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y)
{ {
CursorContainer cursorContainer = new CursorContainer(this) CursorContainer cursorContainer = new CursorContainer(this)

View file

@ -70,7 +70,8 @@ namespace Greenshot.Editor.Forms {
this.btnText = new GreenshotToolStripButton(); this.btnText = new GreenshotToolStripButton();
this.btnSpeechBubble = new GreenshotToolStripButton(); this.btnSpeechBubble = new GreenshotToolStripButton();
this.btnStepLabel = 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.btnHighlight = new GreenshotToolStripButton();
this.btnObfuscate = new GreenshotToolStripButton(); this.btnObfuscate = new GreenshotToolStripButton();
this.toolStripSplitButton1 = new GreenshotToolStripDropDownButton(); this.toolStripSplitButton1 = new GreenshotToolStripDropDownButton();
@ -334,8 +335,9 @@ namespace Greenshot.Editor.Forms {
this.btnText, this.btnText,
this.btnSpeechBubble, this.btnSpeechBubble,
this.btnStepLabel, this.btnStepLabel,
this.btnEmoji,
this.toolStripSeparator14, this.toolStripSeparator14,
this.btnHighlight, this.btnHighlight,
this.btnObfuscate, this.btnObfuscate,
this.toolStripSplitButton1, this.toolStripSplitButton1,
this.toolStripSeparator13, this.toolStripSeparator13,
@ -443,10 +445,20 @@ namespace Greenshot.Editor.Forms {
this.btnStepLabel.LanguageKey = "editor_counter"; this.btnStepLabel.LanguageKey = "editor_counter";
this.btnStepLabel.Name = "btnStepLabel"; this.btnStepLabel.Name = "btnStepLabel";
this.btnStepLabel.Click += new System.EventHandler(this.BtnStepLabelClick); this.btnStepLabel.Click += new System.EventHandler(this.BtnStepLabelClick);
// //
// toolStripSeparator14 // btnStepEmoji
// //
this.toolStripSeparator14.Name = "toolStripSeparator14"; 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 // btnHighlight
// //
@ -1928,7 +1940,8 @@ namespace Greenshot.Editor.Forms {
private GreenshotToolStripButton btnText; private GreenshotToolStripButton btnText;
private GreenshotToolStripButton btnSpeechBubble; private GreenshotToolStripButton btnSpeechBubble;
private GreenshotToolStripButton btnStepLabel; private GreenshotToolStripButton btnStepLabel;
private GreenshotToolStripMenuItem drawLineToolStripMenuItem; private GreenshotToolStripButton btnEmoji;
private GreenshotToolStripMenuItem drawLineToolStripMenuItem;
private GreenshotToolStripButton btnLine; private GreenshotToolStripButton btnLine;
private GreenshotToolStripButton btnSettings; private GreenshotToolStripButton btnSettings;
private GreenshotToolStripButton btnHelp; private GreenshotToolStripButton btnHelp;

View file

@ -269,7 +269,7 @@ namespace Greenshot.Editor.Forms
_toolbarButtons = new[] _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}; //toolbarDropDownButtons = new ToolStripDropDownButton[]{btnBlur, btnPixeliate, btnTextHighlighter, btnAreaHighlighter, btnMagnifier};
@ -655,6 +655,12 @@ namespace Greenshot.Editor.Forms
RefreshFieldControls(); RefreshFieldControls();
} }
private void BtnEmojiClick(object sender, EventArgs e)
{
_surface.DrawingMode = DrawingModes.Emoji;
RefreshFieldControls();
}
private void BtnLineClick(object sender, EventArgs e) private void BtnLineClick(object sender, EventArgs e)
{ {
_surface.DrawingMode = DrawingModes.Line; _surface.DrawingMode = DrawingModes.Line;

View file

@ -1107,4 +1107,7 @@
<metadata name="zoomMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="zoomMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>782, 17</value> <value>782, 17</value>
</metadata> </metadata>
<data name="btnEmoji.Image" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\btnEmoji.Image.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root> </root>

View file

@ -4,6 +4,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Emoji.Wpf" Version="0.3.3" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Greenshot.Base\Greenshot.Base.csproj" /> <ProjectReference Include="..\Greenshot.Base\Greenshot.Base.csproj" />
@ -81,4 +84,8 @@
<DependentUpon>ImageEditorForm.cs</DependentUpon> <DependentUpon>ImageEditorForm.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
</ItemGroup>
</Project> </Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -305,8 +305,9 @@ All Greenshot features still work directly from the tray icon context menu witho
<resource name="editor_counter">Add counter (I)</resource> <resource name="editor_counter">Add counter (I)</resource>
<resource name="editor_speechbubble">Add speechbubble (S)</resource> <resource name="editor_speechbubble">Add speechbubble (S)</resource>
<resource name="editor_emoji">Add emoji</resource>
<resource name="editor_resize">Resize</resource> <resource name="editor_resize">Resize</resource>
<resource name="editor_resize_settings">Resize settings</resource> <resource name="editor_resize_settings">Resize settings</resource>
<resource name="editor_resize_aspectratio">Maintain aspect ratio</resource> <resource name="editor_resize_aspectratio">Maintain aspect ratio</resource>
<resource name="editor_resize_width">Width</resource> <resource name="editor_resize_width">Width</resource>