This commit is contained in:
Julien Richard 2025-03-16 07:23:30 +00:00 committed by GitHub
commit cf9a39215c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 6194 additions and 42 deletions

3
.gitignore vendored
View file

@ -215,3 +215,6 @@ ModelManifest.xml
# Rider files
.idea
# Files compressed during the build
*.gz

View file

@ -31,6 +31,15 @@ Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: ove
Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\SixLabors.ImageSharp.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\SixLabors.ImageSharp.Drawing.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\SixLabors.Fonts.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\System.Memory.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\System.Numerics.Vectors.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\System.Runtime.CompilerServices.Unsafe.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\System.Buffers.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\Twemoji.Mozilla.ttf; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#ReleaseDir}\emojis.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
Source: {#GreenshotProjectDir}\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion
Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion
;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion

View file

@ -20,6 +20,7 @@
*/
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
@ -265,6 +266,12 @@ namespace Greenshot.Base.Core
return exceptionText.ToString();
}
/// <summary>
/// Returns the directory where the application is located
/// </summary>
public static string GetApplicationFolder()
=> Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
/// <summary>

View file

@ -73,7 +73,7 @@ namespace Greenshot.Base.Core
try
{
string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string applicationFolder = EnvironmentInfo.GetApplicationFolder();
// PAF Path
if (applicationFolder != null)

View file

@ -0,0 +1,28 @@
/*
* 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/>.
*/
namespace Greenshot.Base.Interfaces.Drawing
{
public interface IEmojiContainer : IDrawableContainer
{
string Emoji { get; set; }
}
}

View file

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

View file

@ -264,5 +264,10 @@ namespace Greenshot.Base.Interfaces
{
get;
}
/// <summary>
/// Provide access to the controls, this is for the EmojiContainer and needs to go.
/// </summary>
public Control.ControlCollection Controls { get; }
}
}

View file

@ -0,0 +1,178 @@
/*
* 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Greenshot.Editor.Controls.Emoji;
using SixLabors.Fonts.Unicode;
using Task = Microsoft.Build.Utilities.Task;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Build.Framework;
namespace Greenshot.BuildTasks;
/// <summary>
/// A custom task to generate the emoji data we need for the picker.
/// This is based upon code from Sam Hocevar, the license is here:
/// Emoji.Wpf — Emoji support for WPF
///
/// Copyright © 2017—2021 Sam Hocevar <sam@hocevar.net>
///
/// This library is free software. It comes without any warranty, to
/// the extent permitted by applicable law. You can redistribute it
/// and/or modify it under the terms of the Do What the Fuck You Want
/// to Public License, Version 2, as published by the WTFPL Task Force.
/// See http://www.wtfpl.net/ for more details.
/// </summary>
public class EmojiDataTask : Task
{
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 string ToColonSyntax(string s) => Regex.Replace(s.Trim().ToLowerInvariant(), "[^a-z0-9]+", "-");
/// <summary>
/// The name of the output file
/// </summary>
[Required]
public string OutputFilename { get; set; }
//The name of the namespace where the class is going to be generated
[Required]
public string EmojiTestTxtFile { get; set; }
public override bool Execute()
{
var data = ParseEmojiList(EmojiTestTxtFile);
if (!data.Groups.Any())
{
return false;
}
Log.LogMessage($"Creating file {OutputFilename}");
var x = new XmlSerializer(typeof(Emojis));
using var writer = new XmlTextWriter(OutputFilename, Encoding.UTF8);
x.Serialize(writer, data);
return true;
}
private static Emojis ParseEmojiList(string emojiTestTxtFile)
{
var result = new Emojis();
var lookupByName = new Dictionary<string, Emojis.Emoji>();
var qualifiedLut = new Dictionary<string, string>();
Emojis.Group currentGroup = null;
Emojis.Group currentSubgroup = null;
foreach (var line in ReadLines(emojiTestTxtFile))
{
var m = MatchGroup.Match(line);
if (m.Success)
{
currentGroup = new Emojis.Group { Name = m.Groups[1].ToString() };
result.Groups.Add(currentGroup);
continue;
}
m = MatchSubgroup.Match(line);
if (m.Success)
{
currentSubgroup = new Emojis.Group { Name = m.Groups[1].ToString() };
currentGroup?.SubGroups?.Add(currentSubgroup);
continue;
}
m = MatchSequence.Match(line);
if (!m.Success)
{
continue;
}
string sequence = m.Groups[1].ToString();
string name = m.Groups[4].ToString();
string text = string.Join("", sequence.Split(' ').Select(c => char.ConvertFromUtf32(Convert.ToInt32(c, 16))));
// 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;
}
// Fix simple fully-qualified emojis
if (CodePoint.GetCodePointCount(text.AsSpan()) == 2)
{
text = text.TrimEnd('\ufe0f');
}
qualifiedLut[unqualified] = text;
var emoji = new Emojis.Emoji { Text = text };
lookupByName[ToColonSyntax(name)] = emoji;
// Get the left part of the name and check whether were 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);
}
}
// Remove the Component group. Not sure we want to have the skin tones in the picker.
result.Groups.RemoveAll(g => g.Name == "Component");
return result;
}
/// <summary>
/// This reads the specified file into lines
/// </summary>
/// <param name="file">string</param>
/// <returns></returns>
/// <exception cref="FileNotFoundException"></exception>
private static IEnumerable<string> ReadLines(string file)
{
if (!File.Exists(file))
{
throw new FileNotFoundException($"Can't find {file}");
}
using var stream = new FileStream(file, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream, Encoding.UTF8);
while (reader.ReadLine() is { } line)
{
yield return line;
}
}
}

View file

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<DefineConstants>$(DefineConstants);GREENSHOT_BUILDTASKS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" version="17.3.2">
<PrivateAssets>all</PrivateAssets>
<ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>
<PackageReference Include="SixLabors.ImageSharp.Drawing" version="1.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Greenshot.Editor\Controls\Emoji\Emojis.cs">
<Link>Emojis.cs</Link>
</Compile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,69 @@
/*
* 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.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Greenshot.Editor.Controls.Emoji;
/// <summary>
/// This seems to enumerate multiple IEnumerables.
/// TODO: Replace this with LINQ
/// </summary>
/// <typeparam name="T"></typeparam>
internal sealed class ChunkHelper<T> : IEnumerable<IEnumerable<T>>
{
private readonly IEnumerable<T> _elements;
private readonly int _size;
private bool _hasMore;
public ChunkHelper(IEnumerable<T> elements, int size)
{
_elements = elements;
_size = size;
}
public IEnumerator<IEnumerable<T>> GetEnumerator()
{
using var enumerator = _elements.GetEnumerator();
_hasMore = enumerator.MoveNext();
while (_hasMore)
{
yield return GetNextBatch(enumerator).ToList();
}
}
private IEnumerable<T> GetNextBatch(IEnumerator<T> enumerator)
{
for (int i = 0; i < _size; ++i)
{
yield return enumerator.Current;
_hasMore = enumerator.MoveNext();
if (!_hasMore)
{
yield break;
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

View file

@ -0,0 +1,54 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
*
* 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.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Greenshot.Editor.Drawing.Emoji;
namespace Greenshot.Editor.Controls.Emoji
{
internal class EmojiControl : Image
{
public static readonly DependencyProperty EmojiProperty = DependencyProperty.Register("Emoji", typeof(string), typeof(EmojiControl), new PropertyMetadata(default(string), OnEmojiPropertyChanged));
private static void OnEmojiPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((EmojiControl)d).Source = null;
}
public string Emoji
{
get => (string)GetValue(EmojiProperty);
set => SetValue(EmojiProperty, value);
}
protected override void OnRender(DrawingContext dc)
{
if (Source == null && !string.IsNullOrEmpty(Emoji))
{
Source = EmojiRenderer.GetBitmapSource(Emoji, iconSize: 48);
}
base.OnRender(dc);
}
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.IO;
using System.Xml;
using System.Xml.Serialization;
using Greenshot.Base.Core;
namespace Greenshot.Editor.Controls.Emoji
{
/// <summary>
/// This class processes the emoji-test.txt extract, as was generated in a build task, so it can show a list of possible emoji depending on skin tone and hairstyle.
/// </summary>
public static class EmojiData
{
private static readonly string EmojisXmlFilePath = Path.Combine(EnvironmentInfo.GetApplicationFolder(), "emojis.xml");
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));
}
else
{
throw new NotSupportedException($"Missing {EmojisXmlFilePath}, can't load ");
}
}
}
}

View file

@ -0,0 +1,140 @@
<StackPanel x:Class="Greenshot.Editor.Controls.Emoji.EmojiPicker"
x:Name="StackPanel_INTERNAL"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:emoji="clr-namespace:Greenshot.Editor.Controls.Emoji"
Orientation="Horizontal"
mc:Ignorable="d">
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<ControlTemplate x:Key="VariationPopupTemplate" TargetType="ContentControl">
<ListView Name="VariationListView" ItemsSource="{Binding AllVariations}"
BorderThickness="1" Height="Auto" Padding="0" Margin="1"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
MaxWidth="280">
<!-- 6 columns -->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Button Background="Transparent" BorderBrush="Transparent"
Margin="0" Click="OnEmojiPicked"
Width="40" Height="40">
<emoji:EmojiControl Height="24" Emoji="{Binding Path=Text}" />
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ControlTemplate>
<DataTemplate x:Key="CellTemplate">
<ToggleButton Width="40" Height="40" Margin="0" Padding="2"
x:Name="VariationButton" Background="Transparent" BorderBrush="Transparent"
Click="OnEmojiPicked" Focusable="False" >
<Grid>
<emoji:EmojiControl Height="24" Margin="4" Emoji="{Binding Path=Text}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Polygon Visibility="{Binding HasVariations, Converter={StaticResource BoolToVis}}"
Width="6" Height="6" VerticalAlignment="Bottom" HorizontalAlignment="Right"
Stretch="Fill" Points="0,1 1,1 1,0" Fill="Black"/>
<Popup x:Name="VariationPopup" StaysOpen="False" AllowsTransparency="True" Margin="0"
IsOpen="{Binding IsChecked, ElementName=VariationButton, Mode=TwoWay}">
<ContentControl Template="{StaticResource ResourceKey=VariationPopupTemplate}"/>
</Popup>
</Grid>
</ToggleButton>
</DataTemplate>
</StackPanel.Resources>
<ToggleButton x:Name="Button_INTERNAL">
<emoji:EmojiControl x:Name="Image" Emoji="{Binding ElementName=StackPanel_INTERNAL, Mode=OneWay, Path=Selection, UpdateSourceTrigger=PropertyChanged}"/>
</ToggleButton>
<Popup IsOpen="{Binding IsChecked, ElementName=Button_INTERNAL, Mode=TwoWay}"
StaysOpen="False"
KeyDown="OnPopupKeyDown" Loaded="OnPopupLoaded"
AllowsTransparency="True" Margin="0">
<Border>
<StackPanel Orientation="Vertical">
<TabControl ItemsSource="{Binding EmojiGroups, ElementName=StackPanel_INTERNAL}" Padding="0">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<emoji:EmojiControl Height="24" Emoji="{Binding Icon}" >
<Image.ToolTip>
<TextBlock Text="{Binding Name}"/>
</Image.ToolTip>
</emoji:EmojiControl>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ListView Name="EmojiListView" ItemsSource="{Binding EmojiChunkList}"
BorderThickness="0"
MaxHeight="320" Height="Auto" Padding="0" Margin="1"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!-- Get rid of the ugly padding and margin in default ListViewItem -->
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<!-- Remove the mouse over highlight -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<!-- Now for our actual content -->
<ListView.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding}"
ItemTemplate="{StaticResource ResourceKey=CellTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</Border>
</Popup>
</StackPanel>

View file

@ -0,0 +1,134 @@
//
// Emoji.Wpf — Emoji support for WPF
//
// Copyright © 2017—2021 Sam Hocevar <sam@hocevar.net>
//
// This program is free software. It comes without any warranty, to
// the extent permitted by applicable law. You can redistribute it
// and/or modify it under the terms of the Do What the Fuck You Want
// to Public License, Version 2, as published by the WTFPL Task Force.
// See http://www.wtfpl.net/ for more details.
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace Greenshot.Editor.Controls.Emoji;
/// <summary>
/// The event which is created when the emoji is picked
/// </summary>
public class EmojiPickedEventArgs : EventArgs
{
public EmojiPickedEventArgs() { }
public EmojiPickedEventArgs(string emoji) => Emoji = emoji;
public string Emoji;
}
public delegate void EmojiPickedEventHandler(object sender, EmojiPickedEventArgs e);
/// <summary>
/// Interaction logic for Picker.xaml
/// </summary>
public partial class EmojiPicker : StackPanel
{
public EmojiPicker()
{
InitializeComponent();
}
public IList<Emojis.Group> EmojiGroups => EmojiData.Data.Groups;
// Backwards compatibility for when the backend was a TextBlock.
public double FontSize
{
get => Image.Height * 0.75;
set => Image.Height = value / 0.75;
}
public event PropertyChangedEventHandler SelectionChanged;
public event EmojiPickedEventHandler Picked;
private static void OnSelectionPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
(source as EmojiPicker)?.OnSelectionChanged(e.NewValue as string);
}
public string Selection
{
get => (string)GetValue(SelectionProperty);
set => SetValue(SelectionProperty, value);
}
private void OnSelectionChanged(string s)
{
var isDisabled = string.IsNullOrEmpty(s);
Image.Emoji = isDisabled ? "???" : s;
Image.Opacity = isDisabled ? 0.3 : 1.0;
SelectionChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Selection)));
}
private void OnEmojiPicked(object sender, RoutedEventArgs e)
{
if (sender is not Control { DataContext: Emojis.Emoji emoji })
{
return;
}
if (emoji.Variations.Count != 0 && sender is not Button)
{
return;
}
Selection = emoji.Text;
Button_INTERNAL.IsChecked = false;
e.Handled = true;
Picked?.Invoke(this, new EmojiPickedEventArgs(Selection));
}
public static readonly DependencyProperty SelectionProperty = DependencyProperty.Register(
nameof(Selection), typeof(string), typeof(EmojiPicker),
new FrameworkPropertyMetadata("☺", OnSelectionPropertyChanged));
private void OnPopupKeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Escape || sender is not Popup popup) return;
popup.IsOpen = false;
e.Handled = true;
}
private void OnPopupLoaded(object sender, RoutedEventArgs e)
{
if (sender is not Popup popup) return;
var child = popup.Child;
IInputElement oldFocus = null;
child.Focusable = true;
child.IsVisibleChanged += (o, ea) =>
{
if (!child.IsVisible) return;
oldFocus = Keyboard.FocusedElement;
Keyboard.Focus(child);
};
popup.Closed += (o, ea) => Keyboard.Focus(oldFocus);
}
public void ShowPopup(bool show)
{
foreach (var child in Children)
{
if (child is ToggleButton button)
{
button.IsChecked = show;
}
}
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
namespace Greenshot.Editor.Controls.Emoji;
[XmlRoot("Es")]
public class Emojis
{
[XmlArray(ElementName = "Gs")]
public List<Group> Groups { get; set; } = new();
[XmlType("G")]
public class Group
{
[XmlAttribute(AttributeName= "N")]
public string Name { get; set; }
[XmlArray(ElementName = "Sg")]
public List<Group> SubGroups { get; set; } = new();
[XmlArray(ElementName = "Es")]
public List<Emoji> Emojis { get; set; } = new();
#if !GREENSHOT_BUILDTASKS
public IEnumerable<IEnumerable<Emoji>> EmojiChunkList => new ChunkHelper<Emoji>(EmojiList, 8);
public string Icon => SubGroups.FirstOrDefault()?.Emojis.FirstOrDefault()?.Text;
public IEnumerable<Emoji> EmojiList => SubGroups.SelectMany(s => s.Emojis);
#endif
}
[XmlType("E")]
public class Emoji
{
[XmlAttribute(AttributeName = "T")]
public string Text { get; set; }
[XmlArray(ElementName = "V")]
public List<Emoji> Variations { get; set; } = new();
/// <summary>
/// Xml trick so that the Xml serializer does not output the 'Variations' element when the emoji has no variation
/// (see https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer#controlling-generated-xml)
/// </summary>
[XmlIgnore]
public bool VariationsSpecified => HasVariations;
public bool HasVariations => Variations.Count > 0;
public IEnumerable<Emoji> AllVariations => HasVariations ? new[] { this }.Union(Variations) : Array.Empty<Emoji>();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,179 @@
/*
* 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.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using Greenshot.Base.Core;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Controls.Emoji;
using Greenshot.Editor.Helpers;
using Image = System.Drawing.Image;
namespace Greenshot.Editor.Drawing.Emoji
{
/// <summary>
/// Description of EmojiContainer.
/// </summary>
[Serializable]
public sealed class EmojiContainer : VectorGraphicsContainer, IEmojiContainer, IHaveScaleOptions
{
[NonSerialized] private static EmojiContainer _currentContainer;
[NonSerialized] private static ElementHost _emojiPickerHost;
[NonSerialized] private static EmojiPicker _emojiPicker;
[NonSerialized] private bool _justCreated = true;
private string _emoji;
public string Emoji
{
get => _emoji;
set
{
_emoji = value;
ResetCachedBitmap();
}
}
public EmojiContainer(Surface parent, string emoji, int size = 64) : base(parent)
{
Emoji = emoji;
Width = size;
Height = size;
Init();
}
public override void OnDoubleClick()
{
ShowEmojiPicker();
}
private void ShowEmojiPicker()
{
_currentContainer = this;
GetOrCreatePickerControl();
var absRectangle = Bounds;
var displayRectangle = Parent.ToSurfaceCoordinates(absRectangle);
_emojiPickerHost.Width = 0; // Trick to hide the picker's button
_emojiPickerHost.Height = displayRectangle.Height;
_emojiPickerHost.Left = displayRectangle.Left;
_emojiPickerHost.Top = displayRectangle.Top;
_emojiPicker.Selection = Emoji;
_emojiPicker.ShowPopup(true);
}
private void GetOrCreatePickerControl()
{
// Create one picker control by surface
// TODO: This is not ideal, as we need to controls from the surface, should replace this with a different solution.
_emojiPickerHost = _parent.Controls.Find("EmojiPickerHost", false).OfType<ElementHost>().FirstOrDefault();
if (_emojiPickerHost != null)
{
return;
}
_emojiPicker = new EmojiPicker();
_emojiPicker.Picked += (_, args) =>
{
_currentContainer.Emoji = args.Emoji;
_currentContainer.Invalidate();
};
_emojiPickerHost = new ElementHost
{
Dock = DockStyle.None,
Child = _emojiPicker,
Name = "EmojiPickerHost"
};
_parent.Controls.Add(_emojiPickerHost);
}
private void HideEmojiPicker()
{
_emojiPicker?.ShowPopup(false);
}
/// <summary>
/// Make sure we register the property changed, to manage the state of the picker
/// </summary>
protected override void Init()
{
base.Init();
PropertyChanged += OnPropertyChanged;
}
/// <summary>
/// Handle the state of the Emoji Picker
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">PropertyChangedEventArgs</param>
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!e.PropertyName.Equals(nameof(Selected)))
{
return;
}
if (!Selected)
{
HideEmojiPicker();
}
else if (Status == EditStatus.IDLE && _justCreated)
{
// Show picker just after creation
ShowEmojiPicker();
_justCreated = false;
}
}
protected override Image ComputeBitmap()
{
var iconSize = Math.Min(Bounds.Width, Bounds.Height);
if (iconSize <= 0)
{
return null;
}
var image = EmojiRenderer.GetBitmap(Emoji, iconSize);
if (RotationAngle != 0)
{
var newImage = image.Rotate(RotationAngle);
image.Dispose();
return newImage;
}
return image;
}
public ScaleOptions GetScaleOptions()
{
return ScaleOptions.Rational;
}
}
}

View file

@ -0,0 +1,123 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
*
* 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.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using Greenshot.Base.Core;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
namespace Greenshot.Editor.Drawing.Emoji
{
/// <summary>
/// This will render Emoji
/// </summary>
internal static class EmojiRenderer
{
private static readonly FontCollection TwemojiFontCollection = new();
private static readonly Lazy<FontFamily> TwemojiFontFamily = new(() =>
{
var twemojiFontFile = Path.Combine(EnvironmentInfo.GetApplicationFolder(), "Twemoji.Mozilla.ttf");
if (!File.Exists(twemojiFontFile))
{
throw new FileNotFoundException($"Can't find {twemojiFontFile}, bad installation?");
}
using var fileStream = new FileStream(twemojiFontFile, FileMode.Open, FileAccess.Read);
TwemojiFontCollection.Add(fileStream);
TwemojiFontCollection.TryGet("Twemoji Mozilla", out var fontFamily);
return fontFamily;
});
public static Image<Rgba32> GetImage(string emoji, int iconSize)
{
var image = new Image<Rgba32>(iconSize, iconSize);
RenderEmoji(emoji, iconSize, image);
return image;
}
private static void RenderEmoji(string emoji, int iconSize, Image image)
{
var fontFamily = TwemojiFontFamily.Value;
var font = fontFamily.CreateFont(iconSize * 0.95f, FontStyle.Regular);
var verticalOffset = font.Size * 0.045f;
var textOptions = new RichTextOptions(font)
{
Origin = new PointF(iconSize / 2.0f, iconSize / 2.0f + verticalOffset),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
image.Mutate(x => x.DrawText(textOptions, emoji, Color.Black));
}
public static System.Drawing.Image GetBitmap(string emoji, int iconSize)
{
int width = iconSize;
int height = iconSize;
var bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
try
{
unsafe
{
var image = Image.WrapMemory<Bgra32>((void*)bitmapData.Scan0, width: width, height: height);
RenderEmoji(emoji, iconSize, image);
}
}
finally
{
bitmap.UnlockBits(bitmapData);
}
return bitmap;
}
public static System.Windows.Media.Imaging.BitmapSource GetBitmapSource(string emoji, int iconSize)
{
var pixelFormat = System.Windows.Media.PixelFormats.Bgra32;
int width = iconSize;
int height = iconSize;
int stride = (width * pixelFormat.BitsPerPixel + 7) / 8;
byte[] pixels = new byte[stride * height];
var image = Image.WrapMemory<Bgra32>(byteMemory: pixels, width: width, height: height);
RenderEmoji(emoji, iconSize, image);
var source = System.Windows.Media.Imaging.BitmapSource.Create(pixelWidth: width, pixelHeight: height, dpiX: 96, dpiY: 96, pixelFormat: pixelFormat, palette: null, pixels: pixels, stride: stride);
source.Freeze();
return source;
}
}
}

Binary file not shown.

View file

@ -181,6 +181,12 @@ namespace Greenshot.Editor.Drawing
/// <param name="matrix"></param>
public override void Transform(Matrix matrix)
{
if (_image == null)
{
base.Transform(matrix);
return;
}
int rotateAngle = CalculateAngle(matrix);
// we currently assume only one transformation has been made.
if (rotateAngle != 0)

View file

@ -1,4 +1,4 @@
/*
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
@ -40,6 +40,7 @@ using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Drawing.Adorners;
using Greenshot.Editor.Configuration;
using Greenshot.Editor.Drawing.Emoji;
using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers;
using Greenshot.Editor.Memento;
@ -798,6 +799,9 @@ namespace Greenshot.Editor.Drawing
case DrawingModes.None:
_undrawnElement = null;
break;
case DrawingModes.Emoji:
_undrawnElement = new EmojiContainer(this, "🙂");
break;
}
if (_undrawnElement != null)
@ -852,6 +856,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)

View file

@ -1,4 +1,4 @@
/*
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
@ -22,8 +22,10 @@
using Greenshot.Base.Controls;
using Greenshot.Editor.Controls;
using Greenshot.Editor.Drawing;
using Greenshot.Editor.Drawing.Emoji;
namespace Greenshot.Editor.Forms {
namespace Greenshot.Editor.Forms
{
partial class ImageEditorForm {
/// <summary>
/// Designer variable used to keep track of non-visual components.
@ -69,6 +71,7 @@ namespace Greenshot.Editor.Forms {
this.btnText = new GreenshotToolStripButton();
this.btnSpeechBubble = new GreenshotToolStripButton();
this.btnStepLabel = new GreenshotToolStripButton();
this.btnEmoji = new GreenshotToolStripButton();
this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator();
this.btnHighlight = new GreenshotToolStripButton();
this.btnObfuscate = new GreenshotToolStripButton();
@ -336,6 +339,7 @@ namespace Greenshot.Editor.Forms {
this.btnText,
this.btnSpeechBubble,
this.btnStepLabel,
this.btnEmoji,
this.toolStripSeparator14,
this.btnHighlight,
this.btnObfuscate,
@ -446,6 +450,16 @@ namespace Greenshot.Editor.Forms {
this.btnStepLabel.Name = "btnStepLabel";
this.btnStepLabel.Click += new System.EventHandler(this.BtnStepLabelClick);
//
// btnStepEmoji
//
this.btnEmoji.CheckOnClick = true;
this.btnEmoji.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.btnEmoji.Image = EmojiRenderer.GetBitmap("🙂", 32);
this.btnEmoji.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btnEmoji.Text = "Emoji (M)";
this.btnEmoji.Name = "btnEmoji";
this.btnEmoji.Click += new System.EventHandler(this.BtnEmojiClick);
//
// toolStripSeparator14
//
this.toolStripSeparator14.Name = "toolStripSeparator14";
@ -1976,6 +1990,7 @@ namespace Greenshot.Editor.Forms {
private GreenshotToolStripButton btnText;
private GreenshotToolStripButton btnSpeechBubble;
private GreenshotToolStripButton btnStepLabel;
private GreenshotToolStripButton btnEmoji;
private GreenshotToolStripMenuItem drawLineToolStripMenuItem;
private GreenshotToolStripButton btnLine;
private GreenshotToolStripButton btnSettings;

View file

@ -27,6 +27,7 @@ using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Dapplo.Windows.Common.Extensions;
using Dapplo.Windows.Common.Structs;
@ -44,6 +45,7 @@ using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Forms;
using Greenshot.Editor.Configuration;
using Greenshot.Editor.Controls.Emoji;
using Greenshot.Editor.Destinations;
using Greenshot.Editor.Drawing;
using Greenshot.Editor.Drawing.Fields;
@ -142,6 +144,9 @@ namespace Greenshot.Editor.Forms
private void Initialize(ISurface surface, bool outputMade)
{
// Compute emojis in background
EmojiData.Load();
EditorList.Add(this);
//
@ -285,7 +290,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};
@ -631,6 +636,9 @@ namespace Greenshot.Editor.Forms
case DrawingModes.Path:
SetButtonChecked(btnFreehand);
break;
case DrawingModes.Emoji:
SetButtonChecked(btnEmoji);
break;
}
}
@ -707,6 +715,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;
@ -1023,6 +1037,9 @@ namespace Greenshot.Editor.Forms
case Keys.C:
BtnCropClick(sender, e);
break;
case Keys.M:
BtnEmojiClick(sender, e);
break;
}
}
else if (e.Modifiers.Equals(Keys.Control))

View file

@ -7,6 +7,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Greenshot.Base\Greenshot.Base.csproj" />
@ -84,4 +87,11 @@
<DependentUpon>ImageEditorForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Drawing\Emoji\Twemoji.Mozilla.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>Twemoji.Mozilla.ttf</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
</Project>

View file

@ -202,7 +202,7 @@ namespace Greenshot.Editor.Helpers
{
// scaled rectangle (ratio) would be taller than original
// keep width and tweak height to maintain aspect ratio
newSize = newSize.ChangeWidth(selectedSize.Width / originalRatio * flippedRatioSign);
newSize = newSize.ChangeHeight(selectedSize.Width / originalRatio * flippedRatioSign);
}
return newSize;

View file

@ -1,21 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29728.190
# Visual Studio Version 17
VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}"
ProjectSection(ProjectDependencies) = postProject
{92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}
{1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0}
{19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B}
{25C870BE-22BB-4CB8-B274-95DC481F53A7} = {25C870BE-22BB-4CB8-B274-95DC481F53A7}
{47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB}
{697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B}
{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}
{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}
{92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}
{9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B}
{9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A}
{C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9}
{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}
{697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B}
{47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB}
{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}
{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}
{1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0}
{C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Base", "Greenshot.Base\Greenshot.Base.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}"
@ -52,6 +53,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Editor", "Greenshot.Editor\Greenshot.Editor.csproj", "{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greenshot.BuildTasks", "Greenshot.BuildTasks\Greenshot.BuildTasks.csproj", "{25C870BE-22BB-4CB8-B274-95DC481F53A7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -172,6 +175,14 @@ Global
{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}.Release|Any CPU.Build.0 = Release|Any CPU
{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}.Release|x86.ActiveCfg = Release|Any CPU
{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}.Release|x86.Build.0 = Release|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Debug|x86.Build.0 = Debug|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Release|Any CPU.Build.0 = Release|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Release|x86.ActiveCfg = Release|Any CPU
{25C870BE-22BB-4CB8-B274-95DC481F53A7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -33,6 +33,7 @@
<ItemGroup>
<ProjectReference Include="..\Greenshot.Base\Greenshot.Base.csproj" />
<ProjectReference Include="..\Greenshot.Editor\Greenshot.Editor.csproj" />
<ProjectReference Include="..\Greenshot.BuildTasks\Greenshot.BuildTasks.csproj" ReferenceOutputAssembly="false" />
<FilesToHash Include="$(SolutionDir)$(SolutionName)\$(OutDir)\*" />
</ItemGroup>
@ -65,6 +66,12 @@
</Task>
</UsingTask>
<UsingTask TaskName="EmojiDataTask" TaskFactory="TaskHostFactory" AssemblyFile="..\Greenshot.BuildTasks\bin\$(Configuration)\$(TargetFramework)\Greenshot.BuildTasks.dll" />
<Target Name="GenerateEmojiTestTxtFile" BeforeTargets="BeforeBuild">
<EmojiDataTask EmojiTestTxtFile="..\Greenshot.Editor\Controls\Emoji\emoji-test.txt" OutputFilename="$(SolutionDir)$(SolutionName)\$(OutDir)\emojis.xml" />
</Target>
<Target Name="Generate hashes" BeforeTargets="PostBuildEvent">
<GetFileHash Files="@(FilesToHash)" Algorithm="SHA256" HashEncoding="hex">
<Output TaskParameter="Items" ItemName="FilesWithHashes" />

6
src/NuGet.config Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>