This commit is contained in:
Benji Shohet 2025-07-30 20:28:31 +03:00 committed by GitHub
commit bd2c73a596
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 72 additions and 27 deletions

View file

@ -1,13 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<!-- Including language XML files to copy to the output directory for localization. -->
<ItemGroup>
<None Include="Languages\language*.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<!-- Adding NuGet package references required by the project. -->
<ItemGroup>
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" version="7.1.2" />
</ItemGroup>
<!-- Adding project references/dependencies for the project. -->
<ItemGroup>
<ProjectReference Include="..\Greenshot.Base\Greenshot.Base.csproj" />
</ItemGroup>

View file

@ -43,6 +43,10 @@ namespace Greenshot.Plugin.Win10
private readonly string _imageFilePath;
/// <summary>
/// Initializes a new instance of the ToastNotificationService class.
/// If the program was started by a toast notification, logs this information.
/// </summary>
public ToastNotificationService()
{
if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
@ -80,12 +84,12 @@ namespace Greenshot.Plugin.Win10
}
/// <summary>
/// This creates the actual toast
/// Creates and displays the actual toast notification with the specified message and parameters.
/// </summary>
/// <param name="message">string</param>
/// <param name="timeout">TimeSpan until the toast timeouts</param>
/// <param name="onClickAction">Action called when clicked</param>
/// <param name="onClosedAction">Action called when the toast is closed</param>
/// <param name="message">The string message to display in the toast notification.</param>
/// <param name="timeout">TimeSpan until the toast timeouts or should stay on screen, or null for the default duration.</param>
/// <param name="onClickAction">Action called when clicked, or null for no action.</param>
/// <param name="onClosedAction">Action called when the toast is closed, or null for no action.</param>
private void ShowMessage(string message, TimeSpan? timeout = default, Action onClickAction = null, Action onClosedAction = null)
{
// Do not inform the user if this is disabled
@ -210,7 +214,7 @@ namespace Greenshot.Plugin.Win10
}
/// <summary>
/// Factory method, helping with checking if the notification service is even available
/// Factory method, helping with checking if the notification service is even available - Creates a new instance of the ToastNotificationService class, if supported on the current system.
/// </summary>
/// <returns>ToastNotificationService</returns>
public static ToastNotificationService Create()

View file

@ -29,6 +29,9 @@ namespace Greenshot.Plugin.Win10
[IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")]
public class Win10Configuration : IniSection
{
/// <summary>
/// Gets or sets a value indicating whether OCR should be run automatically on every capture.
/// </summary>
[IniProperty("AlwaysRunOCROnCapture", Description = "Determines if OCR is run automatically on every capture", DefaultValue = "False")]
public bool AlwaysRunOCROnCapture { get; set; }
}

View file

@ -41,7 +41,10 @@ namespace Greenshot.Plugin.Win10
/// </summary>
public class Win10OcrProvider : IOcrProvider
{
// Log for debugging and information
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider));
// Minimum width and height for the OCR to work correctly
private const int MinWidth = 130;
private const int MinHeight = 130;
@ -50,7 +53,10 @@ namespace Greenshot.Plugin.Win10
/// </summary>
public Win10OcrProvider()
{
// Get available languages from the OCR engine and log them
var languages = OcrEngine.AvailableRecognizerLanguages;
// Log all available languages for OCR.
foreach (var language in languages)
{
Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag);
@ -64,19 +70,26 @@ namespace Greenshot.Plugin.Win10
/// <returns>OcrResult sync</returns>
public async Task<OcrInformation> DoOcrAsync(ISurface surface)
{
// Will contain the result of the OCR process
OcrInformation result;
// Using a memory stream to handle the image
using (var imageStream = new MemoryStream())
{
// We only want the background
// Output settings for the image before OCR process
var outputSettings = new SurfaceOutputSettings(OutputFormat.png, 0, true)
{
ReduceColors = true,
SaveBackgroundOnly = true
};
// Force Grayscale output
// Force Grayscale output to the image
outputSettings.Effects.Add(new GrayscaleEffect());
// If the surface is smaller than the minimum dimensions, resize it
if (surface.Image.Width < MinWidth || surface.Image.Height < MinHeight)
{
// Calculate dimensions to add
int addedWidth = MinWidth - surface.Image.Width;
if (addedWidth < 0)
{
@ -95,13 +108,18 @@ namespace Greenshot.Plugin.Win10
{
addedHeight /= 2;
}
// Add a resize effect to the image
IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight);
outputSettings.Effects.Add(effect);
}
// Save the surface to the stream and reset position
ImageIO.SaveToStream(surface, imageStream, outputSettings);
imageStream.Position = 0;
// Create a random access stream from the memory stream
var randomAccessStream = imageStream.AsRandomAccessStream();
// Perform OCR on the stream
result = await DoOcrAsync(randomAccessStream);
}
@ -158,8 +176,10 @@ namespace Greenshot.Plugin.Win10
{
var result = new OcrInformation();
// Iterate over all lines in the OCR result
foreach (var ocrLine in ocrResult.Lines)
{
// Create a new line and add it to the result
var line = new Line(ocrLine.Words.Count)
{
Text = ocrLine.Text
@ -167,12 +187,16 @@ namespace Greenshot.Plugin.Win10
result.Lines.Add(line);
// Loop through each word in the line and process it.
for (var index = 0; index < ocrLine.Words.Count; index++)
{
var ocrWord = ocrLine.Words[index];
// Create the bounding rectangle for the word
var location = new NativeRect((int) ocrWord.BoundingRect.X, (int) ocrWord.BoundingRect.Y,
(int) ocrWord.BoundingRect.Width, (int) ocrWord.BoundingRect.Height);
// Add the word to the line
var word = line.Words[index];
word.Text = ocrWord.Text;
word.Bounds = location;

View file

@ -62,23 +62,32 @@ namespace Greenshot.Plugin.Win10
/// <returns>true if plugin is initialized, false if not (doesn't show)</returns>
public bool Initialize()
{
// Here we check if the build version of Windows is actually what we support
if (!WindowsVersion.IsWindows10BuildOrLater(17763))
try
{
Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion);
// Here we check if the build version of Windows is actually what we support
if (!WindowsVersion.IsWindows10BuildOrLater(17763))
{
Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion);
return false;
}
SimpleServiceProvider.Current.AddService<INotificationService>(ToastNotificationService.Create());
// Set this as IOcrProvider
SimpleServiceProvider.Current.AddService<IOcrProvider>(new Win10OcrProvider());
// Add the processor
SimpleServiceProvider.Current.AddService<IProcessor>(new Win10OcrProcessor());
// Add the destinations
SimpleServiceProvider.Current.AddService<IDestination>(new Win10OcrDestination());
SimpleServiceProvider.Current.AddService<IDestination>(new Win10ShareDestination());
return true;
}
catch (Exception e)
{
Log.Error("Failed to initialize Win10Plugin. Error: " + e.ToString(), e);
return false;
}
SimpleServiceProvider.Current.AddService<INotificationService>(ToastNotificationService.Create());
// Set this as IOcrProvider
SimpleServiceProvider.Current.AddService<IOcrProvider>(new Win10OcrProvider());
// Add the processor
SimpleServiceProvider.Current.AddService<IProcessor>(new Win10OcrProcessor());
// Add the destinations
SimpleServiceProvider.Current.AddService<IDestination>(new Win10OcrDestination());
SimpleServiceProvider.Current.AddService<IDestination>(new Win10ShareDestination());
return true;
}
public void Shutdown()