diff --git a/NuGet.Config b/NuGet.Config
index 28aaeb53d..3eef61ce6 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -13,5 +13,6 @@
+
\ No newline at end of file
diff --git a/src/Greenshot.Addon.LegacyEditor/EditorFactory.cs b/src/Greenshot.Addon.LegacyEditor/EditorFactory.cs
index 0b5670aa9..79b6afc03 100644
--- a/src/Greenshot.Addon.LegacyEditor/EditorFactory.cs
+++ b/src/Greenshot.Addon.LegacyEditor/EditorFactory.cs
@@ -21,7 +21,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Greenshot.Addon.LegacyEditor.Forms;
-using Greenshot.Addons.Core;
using Greenshot.Addons.Interfaces;
using Greenshot.Addons.Interfaces.Forms;
@@ -38,13 +37,10 @@ namespace Greenshot.Addon.LegacyEditor
public EditorFactory(
IEditorConfiguration editorConfiguration,
- Func imageEditorFactory,
- Func surfaceExportFactory)
+ Func imageEditorFactory)
{
_editorConfiguration = editorConfiguration;
_imageEditorFactory = imageEditorFactory;
- // Factory for surface objects
- ImageOutput.SurfaceFactory = surfaceExportFactory;
}
///
diff --git a/src/Greenshot.Addons/AddonsModule.cs b/src/Greenshot.Addons/AddonsModule.cs
index d0249db4f..f6d88b465 100644
--- a/src/Greenshot.Addons/AddonsModule.cs
+++ b/src/Greenshot.Addons/AddonsModule.cs
@@ -28,6 +28,8 @@ using Greenshot.Addons.Controls;
using Greenshot.Addons.Core;
using Greenshot.Addons.Resources;
using Greenshot.Addons.ViewModels;
+using Greenshot.Gfx;
+using Greenshot.Gfx.Formats;
namespace Greenshot.Addons
{
@@ -96,6 +98,16 @@ namespace Greenshot.Addons
.SingleInstance()
.AutoActivate();
+ builder
+ .RegisterType()
+ .As()
+ .SingleInstance()
+ .AutoActivate()
+ .OnActivated(args =>
+ {
+ BitmapHelper.StreamConverters["greenshot"] = args.Instance;
+ });
+
base.Load(builder);
}
}
diff --git a/src/Greenshot.Addons/Core/GreenshotFormatReader.cs b/src/Greenshot.Addons/Core/GreenshotFormatReader.cs
new file mode 100644
index 000000000..988e066d3
--- /dev/null
+++ b/src/Greenshot.Addons/Core/GreenshotFormatReader.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Greenshot.Addons.Interfaces;
+using Greenshot.Gfx;
+using Greenshot.Gfx.Formats;
+
+namespace Greenshot.Addons.Core
+{
+ public class GreenshotFormatReader : IImageFormatReader
+ {
+ private readonly Func _surfaceFactory;
+
+ public GreenshotFormatReader(Func surfaceFactory)
+ {
+ _surfaceFactory = surfaceFactory;
+ ImageOutput.SurfaceFactory = surfaceFactory;
+ }
+
+ public IEnumerable SupportedFormats { get; } = new[] { "greenshot" };
+
+ public IBitmapWithNativeSupport Read(Stream stream, string extension = null)
+ {
+ // TODO: Create surface from stream
+ var surface = _surfaceFactory();
+ surface.LoadElementsFromStream(stream);
+ return surface.GetBitmapForExport();
+ }
+ }
+}
diff --git a/src/Greenshot.Addons/Core/ImageOutput.cs b/src/Greenshot.Addons/Core/ImageOutput.cs
index 67763651b..8dbe78d3a 100644
--- a/src/Greenshot.Addons/Core/ImageOutput.cs
+++ b/src/Greenshot.Addons/Core/ImageOutput.cs
@@ -62,16 +62,6 @@ namespace Greenshot.Addons.Core
private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131;
private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile);
- static ImageOutput()
- {
- BitmapHelper.StreamConverters["greenshot"] = (stream, s) =>
- {
- // TODO: Create surface from stream
- var surface = SurfaceFactory();
- surface.LoadElementsFromStream(stream);
- return surface.GetBitmapForExport();
- };
- }
///
/// This is a factory method to create a surface, set from the Greenshot main project
@@ -390,7 +380,7 @@ namespace Greenshot.Addons.Core
// We create a copy of the bitmap, so everything else can be disposed
surfaceFileStream.Position = 0;
- var fileImage = BitmapHelper.FromStreamReader(surfaceFileStream, ".greenshot");
+ var fileImage = BitmapHelper.FromStream(surfaceFileStream, ".greenshot");
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
const int markerSize = 14;
diff --git a/src/Greenshot.Gfx/BitmapHelper.cs b/src/Greenshot.Gfx/BitmapHelper.cs
index 0ec362e6f..079b7e42f 100644
--- a/src/Greenshot.Gfx/BitmapHelper.cs
+++ b/src/Greenshot.Gfx/BitmapHelper.cs
@@ -32,6 +32,7 @@ using Dapplo.Windows.Dpi;
using Greenshot.Gfx.Effects;
using Greenshot.Gfx.Extensions;
using Greenshot.Gfx.FastBitmap;
+using Greenshot.Gfx.Formats;
using Greenshot.Gfx.Structs;
namespace Greenshot.Gfx
@@ -44,91 +45,10 @@ namespace Greenshot.Gfx
private const int ExifOrientationId = 0x0112;
private static readonly LogSource Log = new LogSource();
- ///
- /// A function which usage image.fromstream
- ///
- public static readonly Func FromStreamReader = (stream, s) =>
- {
- using (var tmpImage = Image.FromStream(stream, true, true))
- {
- if (!(tmpImage is Bitmap bitmap))
- {
- return null;
- }
- Log.Debug().WriteLine("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", bitmap.Width, bitmap.Height, bitmap.PixelFormat);
- return bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
- }
- };
-
- static BitmapHelper()
- {
- // Fallback
- StreamConverters[""] = FromStreamReader;
-
- StreamConverters["gif"] = FromStreamReader;
- StreamConverters["bmp"] = FromStreamReader;
- StreamConverters["jpg"] = FromStreamReader;
- StreamConverters["jpeg"] = FromStreamReader;
- StreamConverters["png"] = FromStreamReader;
- StreamConverters["wmf"] = FromStreamReader;
- StreamConverters["svg"] = (stream, s) =>
- {
- stream.Position = 0;
- try
- {
- return SvgBitmap.FromStream(stream);
- }
- catch (Exception ex)
- {
- Log.Error().WriteLine(ex, "Can't load SVG");
- }
- return null;
- };
-
- StreamConverters["ico"] = (stream, extension) =>
- {
- // Icon logic, try to get the Vista icon, else the biggest possible
- try
- {
- using (var tmpBitmap = stream.ExtractVistaIcon())
- {
- if (tmpBitmap != null)
- {
- return tmpBitmap.CloneBitmap(PixelFormat.Format32bppArgb);
- }
- }
- }
- catch (Exception vistaIconException)
- {
- Log.Warn().WriteLine(vistaIconException, "Can't read icon");
- }
- try
- {
- // No vista icon, try normal icon
- stream.Position = 0;
- // We create a copy of the bitmap, so everything else can be disposed
- using (var tmpIcon = new Icon(stream, new Size(1024, 1024)))
- {
- using (var tmpImage = tmpIcon.ToBitmap())
- {
- return tmpImage.CloneBitmap(PixelFormat.Format32bppArgb);
- }
- }
- }
- catch (Exception iconException)
- {
- Log.Warn().WriteLine(iconException, "Can't read icon");
- }
-
- stream.Position = 0;
- return FromStreamReader(stream, extension);
- };
- }
-
///
/// This defines all available bitmap reader functions, registered to an "extension" is called with a stream to a IBitmap.
///
- public static IDictionary> StreamConverters { get; } = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ public static IDictionary StreamConverters { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
///
/// Make sure the image is orientated correctly
@@ -403,48 +323,6 @@ namespace Greenshot.Gfx
return fileBitmap;
}
- ///
- /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
- /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
- ///
- /// Stream with the icon information
- /// Bitmap with the Vista Icon (256x256)
- private static IBitmapWithNativeSupport ExtractVistaIcon(this Stream iconStream)
- {
- const int sizeIconDir = 6;
- const int sizeIconDirEntry = 16;
- IBitmapWithNativeSupport bmpPngExtracted = null;
- try
- {
- var srcBuf = new byte[iconStream.Length];
- iconStream.Read(srcBuf, 0, (int) iconStream.Length);
- int iCount = BitConverter.ToInt16(srcBuf, 4);
- for (var iIndex = 0; iIndex < iCount; iIndex++)
- {
- int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
- int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
- if (iWidth != 0 || iHeight != 0)
- {
- continue;
- }
- var iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
- var iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
- using (var destStream = new MemoryStream())
- {
- destStream.Write(srcBuf, iImageOffset, iImageSize);
- destStream.Seek(0, SeekOrigin.Begin);
- bmpPngExtracted = BitmapWrapper.FromBitmap(new Bitmap(destStream)); // This is PNG! :)
- }
- break;
- }
- }
- catch
- {
- return null;
- }
- return bmpPngExtracted;
- }
-
///
/// Apply the effect to the bitmap
///
@@ -893,17 +771,10 @@ namespace Greenshot.Gfx
}
IBitmapWithNativeSupport returnBitmap = null;
- if (StreamConverters.TryGetValue(extension ?? "", out var converter))
+ if (StreamConverters.TryGetValue(extension ?? "", out var reader))
{
- returnBitmap = converter(stream, extension);
+ returnBitmap = reader.Read(stream, extension);
}
- if (returnBitmap != null || converter == FromStreamReader)
- {
- return returnBitmap;
- }
- // Fallback to default converter
- stream.Position = 0;
- returnBitmap = FromStreamReader(stream, extension);
return returnBitmap;
}
diff --git a/src/Greenshot.Gfx/Formats/GenericGdiFormatReader.cs b/src/Greenshot.Gfx/Formats/GenericGdiFormatReader.cs
new file mode 100644
index 000000000..b6e0cf84c
--- /dev/null
+++ b/src/Greenshot.Gfx/Formats/GenericGdiFormatReader.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using Dapplo.Log;
+
+namespace Greenshot.Gfx.Formats
+{
+ ///
+ /// This implements a IImageFormatReader with the help of Gdi
+ ///
+ public class GenericGdiFormatReader : IImageFormatReader
+ {
+ private static readonly LogSource Log = new LogSource();
+
+ ///
+ public IEnumerable SupportedFormats { get; } = new []{ "","gif", "bmp", "jpg", "jpeg", "png", "wmf" };
+
+ ///
+ public IBitmapWithNativeSupport Read(Stream stream, string extension = null)
+ {
+ using (var tmpImage = Image.FromStream(stream, true, true))
+ {
+ if (!(tmpImage is Bitmap bitmap))
+ {
+ return null;
+ }
+ Log.Debug().WriteLine("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", bitmap.Width, bitmap.Height, bitmap.PixelFormat);
+ return bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
+ }
+ }
+ }
+}
diff --git a/src/Greenshot.Gfx/Formats/IImageFormatReader.cs b/src/Greenshot.Gfx/Formats/IImageFormatReader.cs
new file mode 100644
index 000000000..61cf48193
--- /dev/null
+++ b/src/Greenshot.Gfx/Formats/IImageFormatReader.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Greenshot.Gfx.Formats
+{
+ ///
+ /// Implement this interface to add reading a format to Greenshot
+ ///
+ public interface IImageFormatReader
+ {
+ ///
+ /// This returns all the formats the reader supports
+ ///
+ IEnumerable SupportedFormats { get; }
+ ///
+ /// This reads a IBitmapWithNativeSupport from a stream
+ ///
+ /// Stream
+ /// string
+ /// IBitmapWithNativeSupport
+ IBitmapWithNativeSupport Read(Stream stream, string extension = null);
+ }
+}
diff --git a/src/Greenshot.Gfx/Formats/IcoFormatReader.cs b/src/Greenshot.Gfx/Formats/IcoFormatReader.cs
new file mode 100644
index 000000000..e927e738a
--- /dev/null
+++ b/src/Greenshot.Gfx/Formats/IcoFormatReader.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using Dapplo.Log;
+
+namespace Greenshot.Gfx.Formats
+{
+ ///
+ /// This implements a IImageFormatReader which reads .ico files
+ ///
+ public class IcoFormatReader : IImageFormatReader
+ {
+ private static readonly LogSource Log = new LogSource();
+ private readonly GenericGdiFormatReader _genericGdiFormatReader;
+
+ public IcoFormatReader(GenericGdiFormatReader genericGdiFormatReader)
+ {
+ _genericGdiFormatReader = genericGdiFormatReader;
+ }
+ ///
+ public IEnumerable SupportedFormats { get; } = new []{ "ico" };
+
+ ///
+ public IBitmapWithNativeSupport Read(Stream stream, string extension = null)
+ {
+ // Icon logic, try to get the Vista icon, else the biggest possible
+ try
+ {
+ using (var tmpBitmap = ExtractVistaIcon(stream))
+ {
+ if (tmpBitmap != null)
+ {
+ return tmpBitmap.CloneBitmap(PixelFormat.Format32bppArgb);
+ }
+ }
+ }
+ catch (Exception vistaIconException)
+ {
+ Log.Warn().WriteLine(vistaIconException, "Can't read icon");
+ }
+ try
+ {
+ // No vista icon, try normal icon
+ stream.Position = 0;
+ // We create a copy of the bitmap, so everything else can be disposed
+ using (var tmpIcon = new Icon(stream, new Size(1024, 1024)))
+ {
+ using (var tmpImage = tmpIcon.ToBitmap())
+ {
+ return tmpImage.CloneBitmap(PixelFormat.Format32bppArgb);
+ }
+ }
+ }
+ catch (Exception iconException)
+ {
+ Log.Warn().WriteLine(iconException, "Can't read icon");
+ }
+
+ stream.Position = 0;
+ return _genericGdiFormatReader.Read(stream, extension);
+ }
+
+
+ ///
+ /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
+ /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
+ ///
+ /// Stream with the icon information
+ /// Bitmap with the Vista Icon (256x256)
+ private static IBitmapWithNativeSupport ExtractVistaIcon(Stream iconStream)
+ {
+ const int sizeIconDir = 6;
+ const int sizeIconDirEntry = 16;
+ IBitmapWithNativeSupport bmpPngExtracted = null;
+ try
+ {
+ var srcBuf = new byte[iconStream.Length];
+ iconStream.Read(srcBuf, 0, (int)iconStream.Length);
+ int iCount = BitConverter.ToInt16(srcBuf, 4);
+ for (var iIndex = 0; iIndex < iCount; iIndex++)
+ {
+ int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
+ int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
+ if (iWidth != 0 || iHeight != 0)
+ {
+ continue;
+ }
+ var iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
+ var iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
+ using (var destStream = new MemoryStream())
+ {
+ destStream.Write(srcBuf, iImageOffset, iImageSize);
+ destStream.Seek(0, SeekOrigin.Begin);
+ bmpPngExtracted = BitmapWrapper.FromBitmap(new Bitmap(destStream)); // This is PNG! :)
+ }
+ break;
+ }
+ }
+ catch
+ {
+ return null;
+ }
+ return bmpPngExtracted;
+ }
+
+ }
+}
diff --git a/src/Greenshot.Gfx/Formats/SvgFormatReader.cs b/src/Greenshot.Gfx/Formats/SvgFormatReader.cs
new file mode 100644
index 000000000..f2f83874b
--- /dev/null
+++ b/src/Greenshot.Gfx/Formats/SvgFormatReader.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Dapplo.Log;
+
+namespace Greenshot.Gfx.Formats
+{
+ ///
+ /// This implements a IImageFormatReader which reads svg
+ ///
+ public class SvgFormatReader : IImageFormatReader
+ {
+ private static readonly LogSource Log = new LogSource();
+
+ ///
+ public IEnumerable SupportedFormats { get; } = new []{ "svg" };
+
+ ///
+ public IBitmapWithNativeSupport Read(Stream stream, string extension = null)
+ {
+ stream.Position = 0;
+ try
+ {
+ return SvgBitmap.FromStream(stream);
+ }
+ catch (Exception ex)
+ {
+ Log.Error().WriteLine(ex, "Can't load SVG");
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Greenshot.Gfx/GfxModule.cs b/src/Greenshot.Gfx/GfxModule.cs
new file mode 100644
index 000000000..6db89f62d
--- /dev/null
+++ b/src/Greenshot.Gfx/GfxModule.cs
@@ -0,0 +1,75 @@
+// Greenshot - a free and open source screenshot tool
+// Copyright (C) 2007-2019 Thomas Braun, Jens Klingen, Robin Krom
+//
+// For more information see: http://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 Autofac;
+using Dapplo.Addons;
+using Greenshot.Gfx;
+using Greenshot.Gfx.Formats;
+
+namespace Greenshot.Gfx
+{
+ ///
+ public class GfxModule : AddonModule
+ {
+ private void Register(IImageFormatReader reader)
+ {
+ foreach(var extension in reader.SupportedFormats)
+ {
+ BitmapHelper.StreamConverters[extension] = reader;
+ }
+ }
+
+ ///
+ protected override void Load(ContainerBuilder builder)
+ {
+ builder
+ .RegisterType()
+ .As()
+ .AsSelf()
+ .SingleInstance()
+ .AutoActivate()
+ .OnActivated(args =>
+ {
+ Register(args.Instance);
+ });
+
+ builder
+ .RegisterType()
+ .As()
+ .SingleInstance()
+ .AutoActivate()
+ .OnActivated(args =>
+ {
+ Register(args.Instance);
+ });
+
+ builder
+ .RegisterType()
+ .As()
+ .SingleInstance()
+ .AutoActivate()
+ .OnActivated(args =>
+ {
+ Register(args.Instance);
+ });
+
+ base.Load(builder);
+ }
+ }
+}