mirror of
https://github.com/greenshot/greenshot
synced 2025-08-21 22:13:23 -07:00
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:
parent
eb9bbb8937
commit
2997671698
5 changed files with 295 additions and 40 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue