diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index f2ce406a1..68bf0563f 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -10,4 +10,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Greenshot.Editor/Controls/Emoji/ChunkHelper.cs b/src/Greenshot.Editor/Controls/Emoji/ChunkHelper.cs
deleted file mode 100644
index d4aa24002..000000000
--- a/src/Greenshot.Editor/Controls/Emoji/ChunkHelper.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-ο»Ώ/*
- * 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.Collections;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Greenshot.Editor.Controls.Emoji;
-
-///
-/// This seems to enumerate multiple IEnumerables.
-/// TODO: Replace this with LINQ
-///
-///
-internal sealed class ChunkHelper : IEnumerable>
-{
- private readonly IEnumerable _elements;
- private readonly int _size;
- private bool _hasMore;
-
- public ChunkHelper(IEnumerable elements, int size)
- {
- _elements = elements;
- _size = size;
- }
-
- public IEnumerator> GetEnumerator()
- {
- using var enumerator = _elements.GetEnumerator();
- _hasMore = enumerator.MoveNext();
- while (_hasMore)
- {
- yield return GetNextBatch(enumerator).ToList();
- }
- }
-
- private IEnumerable GetNextBatch(IEnumerator enumerator)
- {
- for (int i = 0; i < _size; ++i)
- {
- yield return enumerator.Current;
- _hasMore = enumerator.MoveNext();
- if (!_hasMore)
- {
- yield break;
- }
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-}
\ No newline at end of file
diff --git a/src/Greenshot.Editor/Controls/Emoji/EmojiData.cs b/src/Greenshot.Editor/Controls/Emoji/EmojiData.cs
index b053ab3f4..b01951026 100644
--- a/src/Greenshot.Editor/Controls/Emoji/EmojiData.cs
+++ b/src/Greenshot.Editor/Controls/Emoji/EmojiData.cs
@@ -11,15 +11,18 @@
//
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
+#if DEBUG
+using System.Collections.Generic;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Text;
using SixLabors.Fonts.Unicode;
+#endif
namespace Greenshot.Editor.Controls.Emoji
{
@@ -28,27 +31,17 @@ namespace Greenshot.Editor.Controls.Emoji
///
public static class EmojiData
{
- private const string FilePath = "emojis.xml";
+ private const string EmojisXmlFilePath = "emojis.xml";
+ private const string EmojisTestFile = @"emoji-test.txt.gz";
+#if DEBUG
+ private const string Adult = "(π¨|π©)(π»|πΌ|π½|πΎ|πΏ)?";
+ private const string Child = "(π¦|π§|πΆ)(π»|πΌ|π½|πΎ|πΏ)?";
+ private static readonly Regex MatchFamily = new($"{Adult}(\u200d{Adult})*(\u200d{Child})+");
- public static Emojis Data { get; private set; } = new Emojis();
-
- public static void Load()
- {
- var x = new XmlSerializer(typeof(Emojis));
-
- if (File.Exists(FilePath))
- {
- Data = (Emojis)x.Deserialize(new XmlTextReader(FilePath));
- }
- else
- {
- // To be removed
- ParseEmojiList();
- x.Serialize(new XmlTextWriter(FilePath, Encoding.UTF8), Data);
- }
- }
-
- private static readonly List SkinToneComponents = new List
+ private static readonly Regex MatchGroup = new(@"^# group: (.*)", RegexOptions.Compiled);
+ private static readonly Regex MatchSubgroup = new(@"^# subgroup: (.*)", RegexOptions.Compiled);
+ private static readonly Regex MatchSequence = new(@"^([0-9a-fA-F ]+[0-9a-fA-F]).*; *([-a-z]*) *# [^ ]* (E[0-9.]* )?(.*)", RegexOptions.Compiled);
+ private static readonly List SkinToneComponents = new()
{
"π»", // light skin tone
"πΌ", // medium-light skin tone
@@ -57,29 +50,51 @@ namespace Greenshot.Editor.Controls.Emoji
"πΏ", // dark skin tone
};
- private static readonly List HairStyleComponents = new List
+ private static readonly List HairStyleComponents = new()
{
"π¦°", // red hair
"π¦±", // curly hair
"π¦³", // white hair
"π¦²", // bald
};
+
+ private static readonly Regex MatchSkinTone = new($"({string.Join("|", SkinToneComponents)})", RegexOptions.Compiled);
+ private static readonly Regex MatchHairStyle = new($"({string.Join("|", HairStyleComponents)})", RegexOptions.Compiled);
- private static string ToColonSyntax(string s)
- => Regex.Replace(s.Trim().ToLowerInvariant(), "[^a-z0-9]+", "-");
+#endif
+
+ public static Emojis Data { get; private set; } = new();
+
+ public static void Load()
+ {
+ var x = new XmlSerializer(typeof(Emojis));
+
+ if (File.Exists(EmojisXmlFilePath))
+ {
+ Data = (Emojis)x.Deserialize(new XmlTextReader(EmojisXmlFilePath));
+ }
+#if RELEASE
+ else
+ {
+ throw new NotSupportedException($"Missing {EmojisXmlFilePath}, can't load ");
+ }
+#elif DEBUG
+ else
+ {
+ // To be removed
+ ParseEmojiList();
+ x.Serialize(new XmlTextWriter(EmojisXmlFilePath, Encoding.UTF8), Data);
+ }
+#endif
+ }
+
+
+#if DEBUG
+ private static string ToColonSyntax(string s) => Regex.Replace(s.Trim().ToLowerInvariant(), "[^a-z0-9]+", "-");
private static void ParseEmojiList()
{
var lookupByName = new Dictionary();
- var matchGroup = new Regex(@"^# group: (.*)");
- var matchSubgroup = new Regex(@"^# subgroup: (.*)");
- var matchSequence = new Regex(@"^([0-9a-fA-F ]+[0-9a-fA-F]).*; *([-a-z]*) *# [^ ]* (E[0-9.]* )?(.*)");
- var matchSkinTone = new Regex($"({string.Join("|", SkinToneComponents)})");
- var matchHairStyle = new Regex($"({string.Join("|", HairStyleComponents)})");
-
- var adult = "(π¨|π©)(π»|πΌ|π½|πΎ|πΏ)?";
- var child = "(π¦|π§|πΆ)(π»|πΌ|π½|πΎ|πΏ)?";
- var matchFamily = new Regex($"{adult}(\u200d{adult})*(\u200d{child})+");
var qualifiedLut = new Dictionary();
var allText = new List();
@@ -89,7 +104,7 @@ namespace Greenshot.Editor.Controls.Emoji
foreach (var line in EmojiDescriptionLines())
{
- var m = matchGroup.Match(line);
+ var m = MatchGroup.Match(line);
if (m.Success)
{
currentGroup = new Emojis.Group { Name = m.Groups[1].ToString() };
@@ -97,85 +112,82 @@ namespace Greenshot.Editor.Controls.Emoji
continue;
}
- m = matchSubgroup.Match(line);
+ m = MatchSubgroup.Match(line);
if (m.Success)
{
currentSubgroup = new Emojis.Group { Name = m.Groups[1].ToString() };
- currentGroup.SubGroups.Add(currentSubgroup);
+ currentGroup?.SubGroups?.Add(currentSubgroup);
continue;
}
- m = matchSequence.Match(line);
- if (m.Success)
+ m = MatchSequence.Match(line);
+ if (!m.Success)
{
- string sequence = m.Groups[1].ToString();
- string name = m.Groups[4].ToString();
+ continue;
+ }
+ string sequence = m.Groups[1].ToString();
+ string name = m.Groups[4].ToString();
- string text = string.Join("", from n in sequence.Split(' ')
- select char.ConvertFromUtf32(Convert.ToInt32(n, 16)));
- bool has_modifier = false;
+ string text = string.Join("", sequence.Split(' ').Select(c => char.ConvertFromUtf32(Convert.ToInt32(c, 16))));
+ bool hasModifier = false;
- if (matchFamily.Match(text).Success)
- {
- // If this is a family emoji, no need to add it to our big matching
- // regex, since the match_family regex is already included.
- }
- else
- {
- // Construct a regex to replace e.g. "π»" with "(π»|πΌ|π½|πΎ|πΏ)" in a big
- // regex so that we can match all variations of this Emoji even if they are
- // not in the standard.
- bool hasNonfirstModifier = false;
- var regexText = matchSkinTone.Replace(
- matchHairStyle.Replace(text, (x) =>
- {
- has_modifier = true;
- hasNonfirstModifier |= x.Value != HairStyleComponents[0];
- return matchHairStyle.ToString();
- }), (x) =>
- {
- has_modifier = true;
- hasNonfirstModifier |= x.Value != SkinToneComponents[0];
- return matchSkinTone.ToString();
- });
-
- if (!hasNonfirstModifier)
+ // If this is a family emoji, no need to add it to our big matching
+ // regex, since the match_family regex is already included.
+ if (!MatchFamily.Match(text).Success)
+ {
+ // Construct a regex to replace e.g. "π»" with "(π»|πΌ|π½|πΎ|πΏ)" in a big
+ // regex so that we can match all variations of this Emoji even if they are
+ // not in the standard.
+ bool hasNonfirstModifier = false;
+ var regexText = MatchSkinTone.Replace(
+ MatchHairStyle.Replace(text, (x) =>
{
- allText.Add(has_modifier ? regexText : text);
- }
- }
+ hasModifier = true;
+ hasNonfirstModifier |= x.Value != HairStyleComponents[0];
+ return MatchHairStyle.ToString();
+ }), (x) =>
+ {
+ hasModifier = true;
+ hasNonfirstModifier |= x.Value != SkinToneComponents[0];
+ return MatchSkinTone.ToString();
+ });
- // If there is already a differently-qualified version of this character, skip it.
- // FIXME: this only works well if fully-qualified appears first in the list.
- var unqualified = text.Replace("\ufe0f", "");
- if (qualifiedLut.ContainsKey(unqualified))
+ if (!hasNonfirstModifier)
{
- continue;
+ allText.Add(hasModifier ? regexText : text);
}
+ }
- // Fix simple fully-qualified emojis
- if (CodePoint.GetCodePointCount(text.AsSpan()) == 2)
- {
- text = text.TrimEnd('\ufe0f');
- }
+ // If there is already a differently-qualified version of this character, skip it.
+ // FIXME: this only works well if fully-qualified appears first in the list.
+ var unqualified = text.Replace("\ufe0f", "");
+ if (qualifiedLut.ContainsKey(unqualified))
+ {
+ continue;
+ }
- qualifiedLut[unqualified] = text;
+ // Fix simple fully-qualified emojis
+ if (CodePoint.GetCodePointCount(text.AsSpan()) == 2)
+ {
+ text = text.TrimEnd('\ufe0f');
+ }
- var emoji = new Emojis.Emoji { Name = name, Text = text, };
+ qualifiedLut[unqualified] = text;
- lookupByName[ToColonSyntax(name)] = emoji;
+ var emoji = new Emojis.Emoji { Name = name, Text = text};
- // Get the left part of the name and check whether weβre a variation of an existing
- // emoji. If so, append to that emoji. Otherwise, add to current subgroup.
- // FIXME: does not work properly because variations can appear before the generic emoji
- if (name.Contains(":") && lookupByName.TryGetValue(ToColonSyntax(name.Split(':')[0]), out var parent_emoji))
- {
- parent_emoji.Variations.Add(emoji);
- }
- else
- {
- currentSubgroup.Emojis.Add(emoji);
- }
+ lookupByName[ToColonSyntax(name)] = emoji;
+
+ // Get the left part of the name and check whether weβre a variation of an existing
+ // emoji. If so, append to that emoji. Otherwise, add to current subgroup.
+ // FIXME: does not work properly because variations can appear before the generic emoji
+ if (name.Contains(":") && lookupByName.TryGetValue(ToColonSyntax(name.Split(':')[0]), out var parentEmoji))
+ {
+ parentEmoji.Variations.Add(emoji);
+ }
+ else
+ {
+ currentSubgroup?.Emojis?.Add(emoji);
}
}
@@ -186,14 +198,16 @@ namespace Greenshot.Editor.Controls.Emoji
private static IEnumerable EmojiDescriptionLines()
{
var exeDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
- var emojiTestFile = Path.Combine(exeDirectory, @"emoji-test.txt");
+ var emojiTestFile = Path.Combine(exeDirectory, EmojisTestFile);
if (!File.Exists(emojiTestFile))
{
throw new FileNotFoundException($"Can't find {emojiTestFile}, bad installation?");
}
using var fileStream = new FileStream(emojiTestFile, FileMode.Open, FileAccess.Read);
+ using var gzStream = new GZipStream(fileStream, CompressionMode.Decompress);
using var streamReader = new StreamReader(fileStream);
return streamReader.ReadToEnd().Split('\r', '\n');
}
+#endif
}
}
\ No newline at end of file
diff --git a/src/Greenshot.Editor/Controls/Emoji/Emojis.cs b/src/Greenshot.Editor/Controls/Emoji/Emojis.cs
index 8ddf41e34..ff1c74971 100644
--- a/src/Greenshot.Editor/Controls/Emoji/Emojis.cs
+++ b/src/Greenshot.Editor/Controls/Emoji/Emojis.cs
@@ -42,14 +42,7 @@ public class Emojis
[XmlElement(ElementName = "Emoji")]
public List Emojis { get; set; } = new();
- public IEnumerable> EmojiChunkList => new ChunkHelper(EmojiList, 8);
-
public string Icon => SubGroups.FirstOrDefault()?.Emojis.FirstOrDefault()?.Text;
-
- public IEnumerable EmojiList
- => from s in SubGroups
- from e in s.Emojis
- select e;
}
public class Emoji
diff --git a/src/Greenshot.Editor/Drawing/Emoji/EmojiContainer.cs b/src/Greenshot.Editor/Drawing/Emoji/EmojiContainer.cs
index 0e9eb0497..ecd6202b3 100644
--- a/src/Greenshot.Editor/Drawing/Emoji/EmojiContainer.cs
+++ b/src/Greenshot.Editor/Drawing/Emoji/EmojiContainer.cs
@@ -153,7 +153,10 @@ namespace Greenshot.Editor.Drawing.Emoji
protected override Image ComputeBitmap()
{
var iconSize = Math.Min(Bounds.Width, Bounds.Height);
- if (iconSize <= 0) return null;
+ if (iconSize <= 0)
+ {
+ return null;
+ }
var image = EmojiRenderer.GetBitmap(Emoji, iconSize);
if (RotationAngle != 0)
diff --git a/src/Greenshot.Editor/Drawing/Emoji/EmojiRenderer.cs b/src/Greenshot.Editor/Drawing/Emoji/EmojiRenderer.cs
index c79442510..fcb0f422a 100644
--- a/src/Greenshot.Editor/Drawing/Emoji/EmojiRenderer.cs
+++ b/src/Greenshot.Editor/Drawing/Emoji/EmojiRenderer.cs
@@ -21,6 +21,7 @@
using System;
using System.IO;
+using System.IO.Compression;
using System.Reflection;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
@@ -35,9 +36,9 @@ namespace Greenshot.Editor.Drawing.Emoji
///
internal static class EmojiRenderer
{
- private static readonly FontCollection _fontCollection = new FontCollection();
+ private static readonly FontCollection TwemojiFontCollection = new();
- private static readonly Lazy _twemojiFontFamily = new Lazy(() =>
+ private static readonly Lazy TwemojiFontFamily = new(() =>
{
var exeDirectory = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
var twemojiFontFile = Path.Combine(exeDirectory, "TwemojiMozilla.ttf");
@@ -47,8 +48,8 @@ namespace Greenshot.Editor.Drawing.Emoji
}
using var fileStream = new FileStream(twemojiFontFile, FileMode.Open, FileAccess.Read);
- _fontCollection.Add(fileStream);
- _fontCollection.TryGet("Twemoji Mozilla", out var fontFamily);
+ TwemojiFontCollection.Add(fileStream);
+ TwemojiFontCollection.TryGet("Twemoji Mozilla", out var fontFamily);
return fontFamily;
});
@@ -62,7 +63,7 @@ namespace Greenshot.Editor.Drawing.Emoji
private static void RenderEmoji(string emoji, int iconSize, Image image)
{
- var fontFamily = _twemojiFontFamily.Value;
+ var fontFamily = TwemojiFontFamily.Value;
var font = fontFamily.CreateFont(iconSize, FontStyle.Regular);
var verticalOffset = font.Size * 0.045f;
var textOptions = new TextOptions(font)
diff --git a/src/Greenshot.Editor/Greenshot.Editor.csproj b/src/Greenshot.Editor/Greenshot.Editor.csproj
index 6a3069383..affaf81c7 100644
--- a/src/Greenshot.Editor/Greenshot.Editor.csproj
+++ b/src/Greenshot.Editor/Greenshot.Editor.csproj
@@ -15,6 +15,11 @@
+
+
+
+
Component
@@ -89,9 +94,9 @@
-
+
PreserveNewest
- emoji-test.txt
+ emoji-test.txt.gz
PreserveNewest