diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index ac830c0f2..c3c2a9805 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -301,8 +301,8 @@ EndSelection:<<<<<<<4 { return true; } - - var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); foreach (var fileData in IterateClipboardContent(dataObject)) { try @@ -520,7 +520,8 @@ EndSelection:<<<<<<<4 yield break; } - var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); foreach (var fileData in IterateClipboardContent(dataObject)) { @@ -534,7 +535,7 @@ EndSelection:<<<<<<<4 try { - if (!FileFormatHandlerRegistry.TryLoadFromStream(fileData.stream, extension, out bitmap)) + if (!fileFormatHandlers.TryLoadFromStream(fileData.stream, extension, out bitmap)) { continue; } @@ -566,7 +567,7 @@ EndSelection:<<<<<<<4 using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read); try { - if (!FileFormatHandlerRegistry.TryLoadFromStream(fileStream, extension, out bitmap)) + if (!fileFormatHandlers.TryLoadFromStream(fileStream, extension, out bitmap)) { continue; } @@ -597,8 +598,8 @@ EndSelection:<<<<<<<4 yield return singleImage; yield break; } - - var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); foreach (var fileData in IterateClipboardContent(dataObject)) { @@ -612,7 +613,7 @@ EndSelection:<<<<<<<4 try { - if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(fileData.stream, extension, out drawableContainer)) + if (!fileFormatHandlers.TryLoadDrawableFromStream(fileData.stream, extension, out drawableContainer)) { continue; } @@ -644,7 +645,7 @@ EndSelection:<<<<<<<4 using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read); try { - if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(fileStream, extension, out drawableContainer)) + if (!fileFormatHandlers.TryLoadDrawableFromStream(fileStream, extension, out drawableContainer)) { continue; } @@ -812,9 +813,10 @@ EndSelection:<<<<<<<4 { return clipboardObject as Bitmap; } + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); // From here, imageStream is a valid stream - if (!FileFormatHandlerRegistry.TryLoadFromStream(imageStream, format, out bitmap)) + if (!fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap)) { return bitmap; } @@ -880,8 +882,9 @@ EndSelection:<<<<<<<4 } // From here, imageStream is a valid stream + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); - if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(imageStream, format, out drawableContainer)) + if (!fileFormatHandlers.TryLoadDrawableFromStream(imageStream, format, out drawableContainer)) { return drawableContainer; } @@ -995,8 +998,9 @@ EndSelection:<<<<<<<4 { // Create the stream for the clipboard dibStream = new MemoryStream(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); - if (!FileFormatHandlerRegistry.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib)) + if (!fileFormatHandlers.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib)) { dibStream.Dispose(); dibStream = null; @@ -1261,8 +1265,9 @@ EndSelection:<<<<<<<4 { string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop); if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); - var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList(); return dropFileNames .Where(filename => !string.IsNullOrEmpty(filename)) .Where(Path.HasExtension) diff --git a/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs similarity index 70% rename from src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs rename to src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs index 0bfb5fc0e..d6310692d 100644 --- a/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs +++ b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs @@ -31,10 +31,8 @@ namespace Greenshot.Base.Core.FileFormatHandlers /// /// This is the registry where all IFileFormatHandler are registered and can be used /// - public static class FileFormatHandlerRegistry + public static class FileFormatHandlerExtensions { - public static IList FileFormatHandlers { get; } = new List(); - /// /// Make sure we handle the input extension always the same, by "normalizing" it /// @@ -52,13 +50,14 @@ namespace Greenshot.Base.Core.FileFormatHandlers } /// - /// + /// Return the extensions that the provided IFileFormatHandlers can accept for the specified action /// + /// IEnumerable{IFileFormatHandler} /// /// - public static IEnumerable ExtensionsFor(FileFormatHandlerActions fileFormatHandlerAction) + public static IEnumerable ExtensionsFor(this IEnumerable fileFormatHandlers, FileFormatHandlerActions fileFormatHandlerAction) { - return FileFormatHandlers.Where(ffh => ffh.SupportedExtensions.ContainsKey(fileFormatHandlerAction)).SelectMany(ffh => ffh.SupportedExtensions[fileFormatHandlerAction]).Distinct(); + return fileFormatHandlers.Where(ffh => ffh.SupportedExtensions.ContainsKey(fileFormatHandlerAction)).SelectMany(ffh => ffh.SupportedExtensions[fileFormatHandlerAction]).Distinct(); } /// @@ -79,76 +78,87 @@ namespace Greenshot.Base.Core.FileFormatHandlers /// Find all the IFileFormatHandler which support the action for the supplied extension. /// Take the first, to call the TrySaveToStream on. /// + /// IEnumerable{IFileFormatHandler} /// Bitmap /// Stream /// string + /// ISurface /// bool - public static bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null) + public static bool TrySaveToStream(this IEnumerable fileFormatHandlers, Bitmap bitmap, Stream destination, string extension, ISurface surface = null) { extension = NormalizeExtension(extension); - var fileFormatHandler = FileFormatHandlers + var saveFileFormatHandlers = fileFormatHandlers .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) - .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)) - .FirstOrDefault(); + .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)).ToList(); - if (fileFormatHandler == null) + if (!saveFileFormatHandlers.Any()) { return false; } - return fileFormatHandler.TrySaveToStream(bitmap, destination, extension, surface); + foreach (var fileFormatHandler in saveFileFormatHandlers) + { + if (fileFormatHandler.TrySaveToStream(bitmap, destination, extension, surface)) + { + return true; + } + } + + return false; } /// /// Try to load a drawable container from the stream /// + /// IEnumerable{IFileFormatHandler} /// Stream /// string /// IDrawableContainer out /// ISurface /// bool true if it was successful - public static bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parentSurface = null) + public static bool TryLoadDrawableFromStream(this IEnumerable fileFormatHandlers, Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parentSurface = null) { extension = NormalizeExtension(extension); - var fileFormatHandler = FileFormatHandlers + var loadfileFormatHandler = fileFormatHandlers .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadDrawableFromStream, extension)) .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadDrawableFromStream, extension)) .FirstOrDefault(); - if (fileFormatHandler == null) + if (loadfileFormatHandler == null) { drawableContainer = null; return false; } - return fileFormatHandler.TryLoadDrawableFromStream(stream, extension, out drawableContainer, parentSurface); + return loadfileFormatHandler.TryLoadDrawableFromStream(stream, extension, out drawableContainer, parentSurface); } /// /// Try to load a Bitmap from the stream /// + /// IEnumerable{IFileFormatHandler} /// Stream /// string /// Bitmap out /// bool true if it was successful - public static bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + public static bool TryLoadFromStream(this IEnumerable fileFormatHandlers, Stream stream, string extension, out Bitmap bitmap) { extension = NormalizeExtension(extension); - var fileFormatHandler = FileFormatHandlers + var loadFileFormatHandler = fileFormatHandlers .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)) .FirstOrDefault(); - if (fileFormatHandler == null) + if (loadFileFormatHandler == null) { bitmap = null; return false; } - return fileFormatHandler.TryLoadFromStream(stream, extension, out bitmap); + return loadFileFormatHandler.TryLoadFromStream(stream, extension, out bitmap); } } } diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index b16c0b514..da5e45de4 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -1711,8 +1711,8 @@ namespace Greenshot.Base.Core // As we are if a different stream, which starts at 0, change the starting position startingPosition = 0; } - - foreach (var fileFormatHandler in FileFormatHandlerRegistry.FileFormatHandlers + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + foreach (var fileFormatHandler in fileFormatHandlers .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension))) { diff --git a/src/Greenshot.Base/Core/ImageOutput.cs b/src/Greenshot.Base/Core/ImageOutput.cs index d7ca816d0..9a8695b0d 100644 --- a/src/Greenshot.Base/Core/ImageOutput.cs +++ b/src/Greenshot.Base/Core/ImageOutput.cs @@ -135,8 +135,8 @@ namespace Greenshot.Base.Core targetStream = memoryStream; } - - if (!FileFormatHandlerRegistry.TrySaveToStream(imageToSave as Bitmap, targetStream, outputSettings.Format.ToString(), surface)) + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + if (!fileFormatHandlers.TrySaveToStream(imageToSave as Bitmap, targetStream, outputSettings.Format.ToString(), surface)) { return; } diff --git a/src/Greenshot.Base/Core/NetworkHelper.cs b/src/Greenshot.Base/Core/NetworkHelper.cs index 02797ed8d..e12a63712 100644 --- a/src/Greenshot.Base/Core/NetworkHelper.cs +++ b/src/Greenshot.Base/Core/NetworkHelper.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; @@ -95,7 +96,8 @@ namespace Greenshot.Base.Core /// IDrawableContainer public static IDrawableContainer DownloadImageAsDrawableContainer(string url) { - var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); var match = imageUrlRegex.Match(url); @@ -104,7 +106,7 @@ namespace Greenshot.Base.Core using var memoryStream = GetAsMemoryStream(url); try { - if (FileFormatHandlerRegistry.TryLoadDrawableFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer)) + if (fileFormatHandlers.TryLoadDrawableFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer)) { return drawableContainer; } @@ -130,7 +132,7 @@ namespace Greenshot.Base.Core } using var memoryStream2 = GetAsMemoryStream(match.Value); - if (FileFormatHandlerRegistry.TryLoadDrawableFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer)) + if (fileFormatHandlers.TryLoadDrawableFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer)) { return drawableContainer; } @@ -151,7 +153,9 @@ namespace Greenshot.Base.Core /// Bitmap public static Bitmap DownloadImage(string url) { - var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + + var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); var match = imageUrlRegex.Match(url); @@ -160,7 +164,7 @@ namespace Greenshot.Base.Core using var memoryStream = GetAsMemoryStream(url); try { - if (FileFormatHandlerRegistry.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) + if (fileFormatHandlers.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) { return bitmap; } @@ -186,7 +190,7 @@ namespace Greenshot.Base.Core } using var memoryStream2 = GetAsMemoryStream(match.Value); - if (FileFormatHandlerRegistry.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) + if (fileFormatHandlers.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) { return bitmap; } diff --git a/src/Greenshot.Base/Core/SimpleServiceProvider.cs b/src/Greenshot.Base/Core/SimpleServiceProvider.cs index bff814540..084f5b1fd 100644 --- a/src/Greenshot.Base/Core/SimpleServiceProvider.cs +++ b/src/Greenshot.Base/Core/SimpleServiceProvider.cs @@ -10,22 +10,19 @@ namespace Greenshot.Base.Core /// public class SimpleServiceProvider : IServiceLocator { - private readonly Dictionary> _services = new Dictionary>(); + private readonly Dictionary> _services = new(); public static IServiceLocator Current { get; } = new SimpleServiceProvider(); - public IEnumerable GetAllInstances() + public IReadOnlyList GetAllInstances() { var typeOfService = typeof(TService); if (!_services.TryGetValue(typeOfService, out var results)) { - yield break; + return Array.Empty(); } - foreach (TService result in results) - { - yield return result; - } + return results.Cast().ToArray(); } public TService GetInstance() diff --git a/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs b/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs index 037ee0aff..934d8fb4d 100644 --- a/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs +++ b/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs @@ -61,9 +61,9 @@ namespace Greenshot.Base.Interfaces /// Bitmap /// Stream /// extension - /// ISurface + /// ISurface with the elements for those file types which can store a surface (.greenshot) /// bool true if it was successful - public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface); + public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null); /// /// diff --git a/src/Greenshot.Base/Interfaces/IServiceLocator.cs b/src/Greenshot.Base/Interfaces/IServiceLocator.cs index c22e3463b..5cf1fb529 100644 --- a/src/Greenshot.Base/Interfaces/IServiceLocator.cs +++ b/src/Greenshot.Base/Interfaces/IServiceLocator.cs @@ -32,7 +32,7 @@ namespace Greenshot.Base.Interfaces /// /// Service to find /// IEnumerable{TService} - IEnumerable GetAllInstances(); + IReadOnlyList GetAllInstances(); /// /// Get the only instance of the specified service diff --git a/src/Greenshot.Editor/EditorInitialize.cs b/src/Greenshot.Editor/EditorInitialize.cs index 0fed52da7..c1ee27db8 100644 --- a/src/Greenshot.Editor/EditorInitialize.cs +++ b/src/Greenshot.Editor/EditorInitialize.cs @@ -19,7 +19,8 @@ * along with this program. If not, see . */ -using Greenshot.Base.Core.FileFormatHandlers; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Editor.FileFormatHandlers; namespace Greenshot.Editor @@ -28,19 +29,22 @@ namespace Greenshot.Editor { public static void Initialize() { - // All generic things, like gif, png, jpg etc. - FileFormatHandlerRegistry.FileFormatHandlers.Add(new DefaultFileFormatHandler()); - FileFormatHandlerRegistry.FileFormatHandlers.Add(new GreenshotFileFormatHandler()); - // For .svg support - FileFormatHandlerRegistry.FileFormatHandlers.Add(new SvgFileFormatHandler()); - // For clipboard support - FileFormatHandlerRegistry.FileFormatHandlers.Add(new DibFileFormatHandler()); - // .ico - FileFormatHandlerRegistry.FileFormatHandlers.Add(new IconFileFormatHandler()); - // EMF & WMF - FileFormatHandlerRegistry.FileFormatHandlers.Add(new MetaFileFormatHandler()); - // JPG XR - FileFormatHandlerRegistry.FileFormatHandlers.Add(new WmpFileFormatHandler()); + SimpleServiceProvider.Current.AddService( + // All generic things, like gif, png, jpg etc. + new DefaultFileFormatHandler(), + // Greenshot format + new GreenshotFileFormatHandler(), + // For .svg support + new SvgFileFormatHandler(), + // For clipboard support + new DibFileFormatHandler(), + // .ico + new IconFileFormatHandler(), + // EMF & WMF + new MetaFileFormatHandler(), + // JPG XR + new WpfFileFormatHandler() + ); } } } diff --git a/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs index d36f68a9d..d5dc39e14 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs @@ -19,15 +19,16 @@ * along with this program. If not, see . */ +using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using Greenshot.Base.Core; -using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; +using log4net; namespace Greenshot.Editor.FileFormatHandlers { @@ -36,6 +37,7 @@ namespace Greenshot.Editor.FileFormatHandlers /// public class DefaultFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler { + private static readonly ILog Log = LogManager.GetLogger(typeof(DefaultFileFormatHandler)); private readonly List _ourExtensions = new() { ".png", ".bmp", ".gif", ".jpg", ".jpeg", ".tiff", ".tif" }; private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); public DefaultFileFormatHandler() @@ -85,8 +87,20 @@ namespace Greenshot.Editor.FileFormatHandlers { // Set that this file was written by Greenshot nonAlphaImage.AddTag(); + } + catch (Exception ex) + { + Log.Warn("Couldn't set 'software used' tag on image.", ex); + } + + try + { nonAlphaImage.Save(destination, imageEncoder, parameters); } + catch (Exception ex) + { + Log.Error("Couldn't save image: ", ex); + } finally { nonAlphaImage.Dispose(); @@ -105,9 +119,20 @@ namespace Greenshot.Editor.FileFormatHandlers /// public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) { - using var tmpImage = Image.FromStream(stream, true, true); - bitmap = ImageHelper.Clone(tmpImage, PixelFormat.Format32bppArgb); - return true; + try + { + using var tmpImage = Image.FromStream(stream, true, true); + bitmap = ImageHelper.Clone(tmpImage, PixelFormat.DontCare); + + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load image: ", ex); + } + + bitmap = null; + return false; } } } diff --git a/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs index 353665cd1..abfb507f7 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs @@ -28,11 +28,13 @@ using System.Reflection; using System.Text; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; +using log4net; namespace Greenshot.Editor.FileFormatHandlers { public class GreenshotFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler { + private static readonly ILog Log = LogManager.GetLogger(typeof(GreenshotFileFormatHandler)); private readonly List _ourExtensions = new() { ".greenshot" }; public GreenshotFileFormatHandler() { @@ -43,23 +45,88 @@ namespace Greenshot.Editor.FileFormatHandlers public override bool TrySaveToStream(Bitmap bitmap, Stream stream, string extension, ISurface surface = null) { - bitmap.Save(stream, ImageFormat.Png); - using MemoryStream tmpStream = new MemoryStream(); - long bytesWritten = surface.SaveElementsToStream(tmpStream); - using BinaryWriter writer = new BinaryWriter(tmpStream); - writer.Write(bytesWritten); - Version v = Assembly.GetExecutingAssembly().GetName().Version; - byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); - writer.Write(marker); - tmpStream.WriteTo(stream); - return true; + if (surface == null) + { + return false; + } + + try + { + bitmap.Save(stream, ImageFormat.Png); + using MemoryStream tmpStream = new MemoryStream(); + long bytesWritten = surface.SaveElementsToStream(tmpStream); + using BinaryWriter writer = new BinaryWriter(tmpStream); + writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); + writer.Write(marker); + tmpStream.WriteTo(stream); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't save surface as .greenshot: ", ex); + } + + return false; } public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) { - var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); - bitmap = (Bitmap)surface.GetImageForExport(); - return true; + try + { + var surface = LoadSurface(stream); + bitmap = (Bitmap)surface.GetImageForExport(); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load .greenshot: ", ex); + } + bitmap = null; + return false; + } + + private ISurface LoadSurface(Stream surfaceFileStream) + { + var returnSurface = SimpleServiceProvider.Current.GetInstance>().Invoke(); + Bitmap captureBitmap; + + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded capture from .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + captureBitmap = ImageHelper.Clone(tmpImage) as Bitmap; + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (var streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + using BinaryReader reader = new BinaryReader(surfaceFileStream); + long bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } + + if (captureBitmap != null) + { + returnSurface.Image = captureBitmap; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", captureBitmap.Width, captureBitmap.Height, captureBitmap.PixelFormat, captureBitmap.HorizontalResolution, captureBitmap.VerticalResolution); + } + + return returnSurface; } } } diff --git a/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs index 7ac00027e..6963266a2 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs @@ -23,7 +23,6 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Linq; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; diff --git a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs index 07f2cdf0a..0a7938c8d 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs @@ -70,13 +70,20 @@ namespace Greenshot.Editor.FileFormatHandlers public override bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent = null) { - var svgDocument = SvgDocument.Open(stream); - if (svgDocument == null) + try { - drawableContainer = null; - return false; + var svgDocument = SvgDocument.Open(stream); + if (svgDocument != null) + { + drawableContainer = new SvgContainer(svgDocument, parent); + return true; + } } - drawableContainer = new SvgContainer(svgDocument, parent); + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + drawableContainer = null; return true; } } diff --git a/src/Greenshot.Editor/FileFormatHandlers/WmpFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs similarity index 76% rename from src/Greenshot.Editor/FileFormatHandlers/WmpFileFormatHandler.cs rename to src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs index 898ca3763..00393e166 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/WmpFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs @@ -19,24 +19,27 @@ * along with this program. If not, see . */ +using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows.Media.Imaging; using Greenshot.Base.Interfaces; using Greenshot.Base.Core; +using log4net; namespace Greenshot.Editor.FileFormatHandlers { /// - /// This is the System.Windows.Media.Imaging (WPF) file format handler + /// This is the System.Windows.Media.Imaging (WPF) file format handler, which uses WIC /// - public class WmpFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + public class WpfFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler { + private static readonly ILog Log = LogManager.GetLogger(typeof(WpfFileFormatHandler)); private List LoadFromStreamExtensions { get; } = new() { ".jxr", ".wdp", ".wmp", ".heic", ".heif" }; private List SaveToStreamExtensions { get; } = new() { ".jxr" }; - public WmpFileFormatHandler() + public WpfFileFormatHandler() { SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = LoadFromStreamExtensions; SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = LoadFromStreamExtensions; @@ -57,8 +60,9 @@ namespace Greenshot.Editor.FileFormatHandlers jpegXrEncoder.Save(destination); return true; } - catch + catch (Exception ex) { + Log.Error("Couldn't save image as JPEG XR: ", ex); return false; } } @@ -66,10 +70,20 @@ namespace Greenshot.Editor.FileFormatHandlers /// public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) { - var bitmapDecoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None); - var bitmapSource = bitmapDecoder.Frames[0]; - bitmap = bitmapSource.ToBitmap(); - return true; + try + { + var bitmapDecoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None); + var bitmapSource = bitmapDecoder.Frames[0]; + bitmap = bitmapSource.ToBitmap(); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load image: ", ex); + } + + bitmap = null; + return false; } } } diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index 4e56c7881..7e69629c7 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -937,7 +937,8 @@ namespace Greenshot.Forms private void CaptureFile(IDestination destination = null) { - var extensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).Select(e => $"*{e}").ToList(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var extensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).Select(e => $"*{e}").ToList(); var openFileDialog = new OpenFileDialog { diff --git a/src/Greenshot/GreenshotMain.cs b/src/Greenshot/GreenshotMain.cs index 0e4b9bd92..adb936976 100644 --- a/src/Greenshot/GreenshotMain.cs +++ b/src/Greenshot/GreenshotMain.cs @@ -20,6 +20,7 @@ */ using System; +using System.Drawing.Imaging; using System.Globalization; using System.Net; using System.Reflection;