diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs
index 0ab70e5b2..a87ac9071 100644
--- a/src/Greenshot.Base/Core/ClipboardHelper.cs
+++ b/src/Greenshot.Base/Core/ClipboardHelper.cs
@@ -494,7 +494,7 @@ EndSelection:<<<<<<<4
{
IDataObject clipboardData = GetDataObject();
// Return the first image
- foreach (Image clipboardImage in GetImages(clipboardData))
+ foreach (var clipboardImage in GetImages(clipboardData))
{
return clipboardImage;
}
@@ -507,11 +507,89 @@ EndSelection:<<<<<<<4
/// Returned images must be disposed by the calling code!
///
///
- /// IEnumerable of Image
- public static IEnumerable GetImages(IDataObject dataObject)
+ /// IEnumerable of Bitmap
+ public static IEnumerable GetImages(IDataObject dataObject)
{
// Get single image, this takes the "best" match
- IDrawableContainer singleImage = GetImage(dataObject);
+ Bitmap singleImage = GetImage(dataObject);
+ if (singleImage != null)
+ {
+ Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
+ yield return singleImage;
+ yield break;
+ }
+
+ var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
+
+ foreach (var fileData in IterateClipboardContent(dataObject))
+ {
+ var extension = Path.GetExtension(fileData.filename)?.ToLowerInvariant();
+ if (!supportedExtensions.Contains(extension))
+ {
+ continue;
+ }
+
+ Bitmap bitmap = null;
+
+ try
+ {
+ if (!FileFormatHandlerRegistry.TryLoadFromStream(fileData.stream, extension, out bitmap))
+ {
+ continue;
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Log.Error("Couldn't read file contents", ex);
+ continue;
+ }
+ finally
+ {
+ fileData.stream?.Dispose();
+ }
+ // If we get here, there is an image
+ yield return bitmap;
+ }
+
+ // check if files are supplied
+ foreach (string imageFile in GetImageFilenames(dataObject))
+ {
+ var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
+ if (!supportedExtensions.Contains(extension))
+ {
+ continue;
+ }
+
+ Bitmap bitmap = null;
+ using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
+ try
+ {
+ if (!FileFormatHandlerRegistry.TryLoadFromStream(fileStream, extension, out bitmap))
+ {
+ continue;
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error("Couldn't read file contents", ex);
+ continue;
+ }
+ // If we get here, there is an image
+ yield return bitmap;
+ }
+ }
+
+ ///
+ /// Get all images (multiple if file names are available) from the dataObject
+ /// Returned images must be disposed by the calling code!
+ ///
+ ///
+ /// IEnumerable of IDrawableContainer
+ public static IEnumerable GetDrawables(IDataObject dataObject)
+ {
+ // Get single image, this takes the "best" match
+ IDrawableContainer singleImage = GetDrawable(dataObject);
if (singleImage != null)
{
Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
@@ -585,11 +663,11 @@ EndSelection:<<<<<<<4
///
///
/// Image or null
- private static IDrawableContainer GetImage(IDataObject dataObject)
+ private static Bitmap GetImage(IDataObject dataObject)
{
if (dataObject == null) return null;
- IDrawableContainer returnImage = null;
+ Bitmap returnImage = null;
IList formats = GetFormats(dataObject);
string[] retrieveFormats;
@@ -635,6 +713,113 @@ EndSelection:<<<<<<<4
return null;
}
+ ///
+ /// Get an IDrawableContainer from the IDataObject, don't check for FileDrop
+ ///
+ ///
+ /// Image or null
+ private static IDrawableContainer GetDrawable(IDataObject dataObject)
+ {
+ if (dataObject == null) return null;
+
+ IDrawableContainer returnImage = null;
+ IList formats = GetFormats(dataObject);
+ string[] retrieveFormats;
+
+ // Found a weird bug, where PNG's from Outlook 2010 are clipped
+ // So I build some special logic to get the best format:
+ if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
+ {
+ // Outlook ??
+ Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
+ retrieveFormats = new[]
+ {
+ DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
+ DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
+ };
+ }
+ else
+ {
+ retrieveFormats = new[]
+ {
+ FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
+ FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
+ };
+ }
+
+ foreach (string currentFormat in retrieveFormats)
+ {
+ if (formats != null && formats.Contains(currentFormat))
+ {
+ Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
+ returnImage = GetDrawableForFormat(currentFormat, dataObject);
+ }
+ else
+ {
+ Log.DebugFormat("Couldn't find format {0}.", currentFormat);
+ }
+
+ if (returnImage != null)
+ {
+ return returnImage;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Helper method to try to get an Bitmap in the specified format from the dataObject
+ /// the DIB reader should solve some issues
+ /// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
+ ///
+ /// string with the format
+ /// IDataObject
+ /// Bitmap or null
+ private static Bitmap GetImageForFormat(string format, IDataObject dataObject)
+ {
+ Bitmap bitmap = null;
+
+ if (format == FORMAT_HTML)
+ {
+ var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
+ if (textObject != null)
+ {
+ var doc = new HtmlDocument();
+ doc.LoadHtml(textObject);
+ var imgNodes = doc.DocumentNode.SelectNodes("//img");
+ if (imgNodes != null)
+ {
+ foreach (var imgNode in imgNodes)
+ {
+ var srcAttribute = imgNode.Attributes["src"];
+ var imageUrl = srcAttribute.Value;
+ Log.Debug(imageUrl);
+ bitmap = NetworkHelper.DownloadImage(imageUrl);
+ if (bitmap != null)
+ {
+ return bitmap;
+ }
+ }
+ }
+ }
+ }
+
+ object clipboardObject = GetFromDataObject(dataObject, format);
+ var imageStream = clipboardObject as MemoryStream;
+ if (!IsValidStream(imageStream))
+ {
+ return clipboardObject as Bitmap;
+ }
+
+ // From here, imageStream is a valid stream
+ if (!FileFormatHandlerRegistry.TryLoadFromStream(imageStream, format, out bitmap))
+ {
+ return bitmap;
+ }
+ return null;
+ }
+
///
/// Helper method to try to get an IDrawableContainer in the specified format from the dataObject
/// the DIB reader should solve some issues
@@ -643,7 +828,7 @@ EndSelection:<<<<<<<4
/// string with the format
/// IDataObject
/// IDrawableContainer or null
- private static IDrawableContainer GetImageForFormat(string format, IDataObject dataObject)
+ private static IDrawableContainer GetDrawableForFormat(string format, IDataObject dataObject)
{
IDrawableContainer drawableContainer = null;
diff --git a/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs
index 0dded0b55..47603fa2a 100644
--- a/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs
+++ b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerRegistry.cs
@@ -84,5 +84,28 @@ namespace Greenshot.Base.Core.FileFormatHandlers
return fileFormatHandler.TryLoadDrawableFromStream(stream, extension, out drawableContainer, parentSurface);
}
+
+ ///
+ /// Try to load a Bitmap from the stream
+ ///
+ /// Stream
+ /// string
+ /// Bitmap out
+ /// bool true if it was successful
+ public static bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
+ {
+ var fileFormatHandler = FileFormatHandlers
+ .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
+ .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension))
+ .FirstOrDefault();
+
+ if (fileFormatHandler == null)
+ {
+ bitmap = null;
+ return false;
+ }
+
+ return fileFormatHandler.TryLoadFromStream(stream, extension, out bitmap);
+ }
}
}
diff --git a/src/Greenshot.Base/Core/NetworkHelper.cs b/src/Greenshot.Base/Core/NetworkHelper.cs
index 23427ce0d..02797ed8d 100644
--- a/src/Greenshot.Base/Core/NetworkHelper.cs
+++ b/src/Greenshot.Base/Core/NetworkHelper.cs
@@ -24,7 +24,6 @@ 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;
@@ -145,6 +144,62 @@ namespace Greenshot.Base.Core
return null;
}
+ ///
+ /// Download the uri to create a Bitmap
+ ///
+ /// Of an image
+ /// Bitmap
+ public static Bitmap DownloadImage(string url)
+ {
+ var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
+
+ var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})");
+ var match = imageUrlRegex.Match(url);
+ try
+ {
+ using var memoryStream = GetAsMemoryStream(url);
+ try
+ {
+ if (FileFormatHandlerRegistry.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
+ {
+ return bitmap;
+ }
+ }
+ catch (Exception)
+ {
+ // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
+ string content;
+ using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
+ {
+ content = streamReader.ReadLine();
+ }
+
+ if (string.IsNullOrEmpty(content))
+ {
+ throw;
+ }
+
+ match = imageUrlRegex.Match(content);
+ if (!match.Success)
+ {
+ throw;
+ }
+
+ using var memoryStream2 = GetAsMemoryStream(match.Value);
+ if (FileFormatHandlerRegistry.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
+ {
+ return bitmap;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error("Problem downloading the image from: " + url, e);
+ }
+
+ return null;
+ }
+
///
/// Helper method to create a web request with a lot of default settings
///
diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs
index d39276992..049748cd1 100644
--- a/src/Greenshot.Editor/Drawing/Surface.cs
+++ b/src/Greenshot.Editor/Drawing/Surface.cs
@@ -935,7 +935,7 @@ namespace Greenshot.Editor.Drawing
}
}
- foreach (var drawableContainer in ClipboardHelper.GetImages(e.Data))
+ foreach (var drawableContainer in ClipboardHelper.GetDrawables(e.Data))
{
drawableContainer.Left = mouse.X;
drawableContainer.Top = mouse.Y;
@@ -987,13 +987,11 @@ namespace Greenshot.Editor.Drawing
{
//create a blank bitmap the same size as original
Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty);
- if (newBitmap != null)
- {
- // Make undoable
- MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
- SetImage(newBitmap, false);
- Invalidate();
- }
+ if (newBitmap == null) return;
+ // Make undoable
+ MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
+ SetImage(newBitmap, false);
+ Invalidate();
}
///
@@ -2057,12 +2055,13 @@ namespace Greenshot.Editor.Drawing
{
Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
- foreach (var drawableContainer in ClipboardHelper.GetImages(clipboard))
+ foreach (var drawableContainer in ClipboardHelper.GetDrawables(clipboard))
{
if (drawableContainer == null) continue;
DeselectAllElements();
drawableContainer.Left = pasteLocation.X;
drawableContainer.Top = pasteLocation.Y;
+ AddElement(drawableContainer);
SelectElement(drawableContainer);
pasteLocation.X += 10;
pasteLocation.Y += 10;
@@ -2206,24 +2205,23 @@ namespace Greenshot.Editor.Drawing
/// false to skip event generation
public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true)
{
- if (!selectedElements.Contains(container))
- {
- selectedElements.Add(container);
- container.Selected = true;
- FieldAggregator.BindElement(container);
- if (generateEvents && _movingElementChanged != null)
- {
- SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
- {
- Elements = selectedElements
- };
- _movingElementChanged(this, eventArgs);
- }
+ if (selectedElements.Contains(container)) return;
- if (invalidate)
+ selectedElements.Add(container);
+ container.Selected = true;
+ FieldAggregator.BindElement(container);
+ if (generateEvents && _movingElementChanged != null)
+ {
+ SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
{
- container.Invalidate();
- }
+ Elements = selectedElements
+ };
+ _movingElementChanged(this, eventArgs);
+ }
+
+ if (invalidate)
+ {
+ container.Invalidate();
}
}
diff --git a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs
index 17c3eb542..3cc04d681 100644
--- a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs
+++ b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs
@@ -22,10 +22,8 @@
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.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
@@ -73,20 +71,16 @@ namespace Greenshot.Editor.FileFormatHandlers
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
{
var svgDocument = SvgDocument.Open(stream);
- int width = (int)svgDocument.ViewBox.Width;
- int height = (int)svgDocument.ViewBox.Height;
try
{
- bitmap = ImageHelper.CreateEmpty(width, height, PixelFormat.Format32bppArgb, Color.Transparent);
- svgDocument.Draw(bitmap);
+ bitmap = svgDocument.Draw();
return true;
}
catch (Exception ex)
{
Log.Error("Can't load SVG", ex);
}
-
bitmap = null;
return false;
}