Fixing drag and drop of files, the container was not added to the surface. Also fixed opening things from the clipboard.

This commit is contained in:
Robin Krom 2022-02-09 23:37:38 +01:00
commit 2997671698
No known key found for this signature in database
GPG key ID: BCC01364F1371490
5 changed files with 295 additions and 40 deletions

View file

@ -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!
/// </summary>
/// <param name="dataObject"></param>
/// <returns>IEnumerable of Image</returns>
public static IEnumerable<IDrawableContainer> GetImages(IDataObject dataObject)
/// <returns>IEnumerable of Bitmap</returns>
public static IEnumerable<Bitmap> 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;
}
}
/// <summary>
/// Get all images (multiple if file names are available) from the dataObject
/// Returned images must be disposed by the calling code!
/// </summary>
/// <param name="dataObject"></param>
/// <returns>IEnumerable of IDrawableContainer</returns>
public static IEnumerable<IDrawableContainer> 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
/// </summary>
/// <param name="dataObject"></param>
/// <returns>Image or null</returns>
private static IDrawableContainer GetImage(IDataObject dataObject)
private static Bitmap GetImage(IDataObject dataObject)
{
if (dataObject == null) return null;
IDrawableContainer returnImage = null;
Bitmap returnImage = null;
IList<string> formats = GetFormats(dataObject);
string[] retrieveFormats;
@ -635,6 +713,113 @@ EndSelection:<<<<<<<4
return null;
}
/// <summary>
/// Get an IDrawableContainer from the IDataObject, don't check for FileDrop
/// </summary>
/// <param name="dataObject"></param>
/// <returns>Image or null</returns>
private static IDrawableContainer GetDrawable(IDataObject dataObject)
{
if (dataObject == null) return null;
IDrawableContainer returnImage = null;
IList<string> 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;
}
/// <summary>
/// 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
/// </summary>
/// <param name="format">string with the format</param>
/// <param name="dataObject">IDataObject</param>
/// <returns>Bitmap or null</returns>
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;
}
/// <summary>
/// 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
/// <param name="format">string with the format</param>
/// <param name="dataObject">IDataObject</param>
/// <returns>IDrawableContainer or null</returns>
private static IDrawableContainer GetImageForFormat(string format, IDataObject dataObject)
private static IDrawableContainer GetDrawableForFormat(string format, IDataObject dataObject)
{
IDrawableContainer drawableContainer = null;

View file

@ -84,5 +84,28 @@ namespace Greenshot.Base.Core.FileFormatHandlers
return fileFormatHandler.TryLoadDrawableFromStream(stream, extension, out drawableContainer, parentSurface);
}
/// <summary>
/// Try to load a Bitmap from the stream
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="extension">string</param>
/// <param name="bitmap">Bitmap out</param>
/// <returns>bool true if it was successful</returns>
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);
}
}
}

View file

@ -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;
}
/// <summary>
/// Download the uri to create a Bitmap
/// </summary>
/// <param name="url">Of an image</param>
/// <returns>Bitmap</returns>
public static Bitmap DownloadImage(string url)
{
var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{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;
}
/// <summary>
/// Helper method to create a web request with a lot of default settings
/// </summary>

View file

@ -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();
}
/// <summary>
@ -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
/// <param name="generateEvents">false to skip event generation</param>
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();
}
}

View file

@ -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<SvgDocument>(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;
}