diff --git a/src/Greenshot.Editor/Controls/EmojiControl.cs b/src/Greenshot.Editor/Controls/EmojiControl.cs index 5b317f7a5..71df67f2a 100644 --- a/src/Greenshot.Editor/Controls/EmojiControl.cs +++ b/src/Greenshot.Editor/Controls/EmojiControl.cs @@ -1,17 +1,17 @@ -using System; -using System.Windows; +using System.Windows; using System.Windows.Controls; +using System.Windows.Media; using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Controls { internal class EmojiControl : Image { - public static readonly DependencyProperty EmojiProperty = DependencyProperty.Register("Emoji", typeof(string), typeof(EmojiControl), new PropertyMetadata(default(string), PropertyChangedCallback)); + public static readonly DependencyProperty EmojiProperty = DependencyProperty.Register("Emoji", typeof(string), typeof(EmojiControl), new PropertyMetadata(default(string), OnEmojiPropertyChanged)); - private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnEmojiPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - ((EmojiControl)d).Source = EmojiRenderer.GetBitmapSource((string)e.NewValue, iconSize: 48); + ((EmojiControl)d).Source = null; } public string Emoji @@ -19,5 +19,28 @@ namespace Greenshot.Editor.Controls get { return (string)GetValue(EmojiProperty); } set { SetValue(EmojiProperty, value); } } + + public static readonly DependencyProperty UseSystemFontProperty = DependencyProperty.Register("UseSystemFont", typeof(bool), typeof(EmojiControl), new PropertyMetadata(default(bool), OnUseSystemFontPropertyChanged)); + + private static void OnUseSystemFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((EmojiControl)d).Source = null; + } + + protected override void OnRender(DrawingContext dc) + { + if (Source == null && !string.IsNullOrEmpty(Emoji)) + { + Source = EmojiRenderer.GetBitmapSource(Emoji, iconSize: 48, useSystemFont: UseSystemFont); + } + + base.OnRender(dc); + } + + public bool UseSystemFont + { + get { return (bool)GetValue(UseSystemFontProperty); } + set { SetValue(UseSystemFontProperty, value); } + } } } diff --git a/src/Greenshot.Editor/Controls/EmojiData.cs b/src/Greenshot.Editor/Controls/EmojiData.cs index 726b17c81..141dc7c5f 100644 --- a/src/Greenshot.Editor/Controls/EmojiData.cs +++ b/src/Greenshot.Editor/Controls/EmojiData.cs @@ -18,7 +18,6 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Greenshot.Editor.Drawing; using SixLabors.Fonts.Unicode; namespace Greenshot.Editor.Controls @@ -87,7 +86,7 @@ namespace Greenshot.Editor.Controls select e; } - private static string m_match_one_string; + private static string m_match_one_string; // FIXME: this could be read directly from emoji-test.txt.gz private static List SkinToneComponents = new List @@ -190,7 +189,7 @@ namespace Greenshot.Editor.Controls var unqualified = text.Replace("\ufe0f", ""); if (qualified_lut.ContainsKey(unqualified)) continue; - + // Fix simple fully-qualified emojis if (CodePoint.GetCodePointCount(text.AsSpan()) == 2) { @@ -242,8 +241,8 @@ namespace Greenshot.Editor.Controls private static IEnumerable EmojiDescriptionLines() { - using var stream = Assembly.GetCallingAssembly().GetManifestResourceStream("Greenshot.Editor.Resources.emoji-test.txt"); - using var streamReader = new StreamReader(stream); + using var fileStream = new FileStream(Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), @"Resources\emoji-test.txt"), FileMode.Open, FileAccess.Read); + using var streamReader = new StreamReader(fileStream); return streamReader.ReadToEnd().Split('\r', '\n'); } } diff --git a/src/Greenshot.Editor/Controls/EmojiPicker.xaml b/src/Greenshot.Editor/Controls/EmojiPicker.xaml index a58856913..282f58957 100644 --- a/src/Greenshot.Editor/Controls/EmojiPicker.xaml +++ b/src/Greenshot.Editor/Controls/EmojiPicker.xaml @@ -17,7 +17,8 @@ BorderThickness="1" Height="Auto" Padding="0" Margin="1" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Disabled" - MaxWidth="280"> + MaxWidth="280"> + @@ -35,7 +36,7 @@ @@ -47,7 +48,7 @@ x:Name="VariationButton" Background="Transparent" BorderBrush="Transparent" Click="OnEmojiPicked" Focusable="False" ToolTip="{Binding Path=Name}"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + Use system font + + + diff --git a/src/Greenshot.Editor/Controls/EmojiPicker.xaml.cs b/src/Greenshot.Editor/Controls/EmojiPicker.xaml.cs index fc255b4a5..1ea25deee 100644 --- a/src/Greenshot.Editor/Controls/EmojiPicker.xaml.cs +++ b/src/Greenshot.Editor/Controls/EmojiPicker.xaml.cs @@ -42,6 +42,14 @@ namespace Greenshot.Editor.Controls public IList EmojiGroups => EmojiData.AllGroups; + public static readonly DependencyProperty UseSystemFontProperty = DependencyProperty.Register("UseSystemFont", typeof(bool), typeof(EmojiPicker), new PropertyMetadata(default(bool))); + + public bool UseSystemFont + { + get { return (bool)GetValue(UseSystemFontProperty); } + set { SetValue(UseSystemFontProperty, value); } + } + // Backwards compatibility for when the backend was a TextBlock. public double FontSize { diff --git a/src/Greenshot.Editor/Drawing/EmojiContainer.cs b/src/Greenshot.Editor/Drawing/EmojiContainer.cs index 84a64b813..4cd38fdd2 100644 --- a/src/Greenshot.Editor/Drawing/EmojiContainer.cs +++ b/src/Greenshot.Editor/Drawing/EmojiContainer.cs @@ -24,12 +24,9 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.Serialization; -using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Forms; using System.Windows.Forms.Integration; -using System.Windows.Media; -using System.Windows.Media.Imaging; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Controls; @@ -37,7 +34,6 @@ using Greenshot.Editor.Drawing.Adorners; using Greenshot.Editor.Helpers; using Image = System.Drawing.Image; using Matrix = System.Drawing.Drawing2D.Matrix; -using Size = System.Windows.Size; namespace Greenshot.Editor.Drawing { @@ -56,6 +52,7 @@ namespace Greenshot.Editor.Drawing private string _emoji; private int _rotationAngle; + private bool _useSystemFont; public string Emoji { @@ -67,6 +64,16 @@ namespace Greenshot.Editor.Drawing } } + public bool UseSystemFont + { + get => _useSystemFont; + set + { + _useSystemFont = value; + ResetCachedBitmap(); + } + } + public EmojiContainer(Surface parent) : this(parent, "🙂", size: 64) { } @@ -111,6 +118,7 @@ namespace Greenshot.Editor.Drawing _emojiPicker.Picked += (_, args) => { _currentContainer.Emoji = args.Emoji; + _currentContainer.UseSystemFont = _emojiPicker.UseSystemFont; _currentContainer.Invalidate(); }; @@ -211,7 +219,7 @@ namespace Greenshot.Editor.Drawing private Image ComputeBitmap(int iconSize) { - var image = EmojiRenderer.GetBitmap(Emoji, iconSize); + var image = EmojiRenderer.GetBitmap(Emoji, iconSize, useSystemFont: _useSystemFont); if (_rotationAngle != 0) { var newImage = image.Rotate(_rotationAngle); diff --git a/src/Greenshot.Editor/Drawing/EmojiRenderer.cs b/src/Greenshot.Editor/Drawing/EmojiRenderer.cs index 58b3d58f7..dfd93fbce 100644 --- a/src/Greenshot.Editor/Drawing/EmojiRenderer.cs +++ b/src/Greenshot.Editor/Drawing/EmojiRenderer.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using System.IO; using System.Reflection; using System.Windows.Media; using System.Windows.Media.Imaging; @@ -19,28 +20,37 @@ namespace Greenshot.Editor.Drawing { internal static class EmojiRenderer { - private static Lazy _fontFamily = new Lazy(() => + static FontCollection _fontCollection = new FontCollection(); + + private static Lazy _twemoji = new Lazy(() => { - using var stream = Assembly.GetCallingAssembly().GetManifestResourceStream("Greenshot.Editor.Resources.TwemojiMozilla.ttf"); - var fontCollection = new FontCollection(); - fontCollection.Add(stream); - fontCollection.TryGet("Twemoji Mozilla", out var fontFamily); + using var fileStream = new FileStream(Path.Combine(Path.GetDirectoryName(Assembly.GetCallingAssembly().Location), @"Resources\TwemojiMozilla.ttf"), FileMode.Open, FileAccess.Read); + _fontCollection.Add(fileStream); + _fontCollection.TryGet("Twemoji Mozilla", out var fontFamily); return fontFamily; }); - public static Image GetImage(string emoji, int iconSize) + private static Lazy _segoeUI = new Lazy(() => + { + using var fileStream = new FileStream(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Fonts\seguiemj.ttf"), FileMode.Open, FileAccess.Read); + _fontCollection.Add(fileStream); + _fontCollection.TryGet("Segoe UI Emoji", out var fontFamily); + return fontFamily; + }); + + public static Image GetImage(string emoji, int iconSize, bool useSystemFont) { var image = new Image(iconSize, iconSize); - RenderEmoji(emoji, iconSize, image); + RenderEmoji(emoji, iconSize, image, useSystemFont); return image; } - private static void RenderEmoji(string emoji, int iconSize, SixLabors.ImageSharp.Image image) + private static void RenderEmoji(string emoji, int iconSize, SixLabors.ImageSharp.Image image, bool useSystemFont) { - var font = _fontFamily.Value.CreateFont(iconSize, FontStyle.Regular); - - var verticalOffset = font.Size * 0.045f; + var fontFamily = useSystemFont ? _segoeUI.Value : _twemoji.Value; + var font = fontFamily.CreateFont(useSystemFont ? iconSize * 0.95f : iconSize, FontStyle.Regular); + var verticalOffset = useSystemFont ? -font.Size * 0.050f : font.Size * 0.045f; var textOptions = new TextOptions(font) { Origin = new SixLabors.ImageSharp.PointF(font.Size / 2.0f, font.Size / 2.0f - verticalOffset), @@ -51,7 +61,7 @@ namespace Greenshot.Editor.Drawing image.Mutate(x => x.DrawText(textOptions, emoji, SixLabors.ImageSharp.Color.Black)); } - public static Image GetBitmap(string emoji, int iconSize) + public static Image GetBitmap(string emoji, int iconSize, bool useSystemFont) { int width = iconSize; int height = iconSize; @@ -64,7 +74,7 @@ namespace Greenshot.Editor.Drawing unsafe { var image = SixLabors.ImageSharp.Image.WrapMemory((void*)bitmapData.Scan0, width: width, height: height); - RenderEmoji(emoji, iconSize, image); + RenderEmoji(emoji, iconSize, image, useSystemFont); } } finally @@ -75,7 +85,7 @@ namespace Greenshot.Editor.Drawing return bitmap; } - public static BitmapSource GetBitmapSource(string emoji, int iconSize) + public static BitmapSource GetBitmapSource(string emoji, int iconSize, bool useSystemFont) { var pixelFormat = PixelFormats.Bgra32; int width = iconSize; @@ -85,7 +95,7 @@ namespace Greenshot.Editor.Drawing var image = SixLabors.ImageSharp.Image.WrapMemory(byteMemory: pixels, width: width, height: height); - RenderEmoji(emoji, iconSize, image); + RenderEmoji(emoji, iconSize, image, useSystemFont); var source = BitmapSource.Create(pixelWidth: width, pixelHeight: height, dpiX: 96, dpiY: 96, pixelFormat: pixelFormat, palette: null, pixels: pixels, stride: stride); source.Freeze(); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs index 527d95d46..8a18b2a00 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs @@ -450,7 +450,7 @@ namespace Greenshot.Editor.Forms { // this.btnEmoji.CheckOnClick = true; this.btnEmoji.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnEmoji.Image = EmojiRenderer.GetBitmap("🙂", 32); + this.btnEmoji.Image = EmojiRenderer.GetBitmap("🙂", 32, useSystemFont: false); this.btnEmoji.ImageTransparentColor = System.Drawing.Color.Magenta; this.btnEmoji.Text = "Emoji (M)"; this.btnEmoji.Name = "btnEmoji"; diff --git a/src/Greenshot.Editor/Greenshot.Editor.csproj b/src/Greenshot.Editor/Greenshot.Editor.csproj index 5a367fc09..cc37e0211 100644 --- a/src/Greenshot.Editor/Greenshot.Editor.csproj +++ b/src/Greenshot.Editor/Greenshot.Editor.csproj @@ -86,7 +86,14 @@ ImageEditorForm.cs - - + + + + + PreserveNewest + + + PreserveNewest + \ No newline at end of file