Work in progress, making the clipboard & drag/drop work again. SvgContainer seems to work, added MetaFileFormatHandler & MetafileContainer for the EMF/WMF file formats.

This commit is contained in:
Robin Krom 2022-02-09 22:00:17 +01:00
commit eb9bbb8937
No known key found for this signature in database
GPG key ID: BCC01364F1371490
22 changed files with 611 additions and 326 deletions

View file

@ -34,6 +34,7 @@ using Greenshot.Base.Core.Enums;
using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using log4net; using log4net;
@ -300,13 +301,14 @@ EndSelection:<<<<<<<4
return true; return true;
} }
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
foreach (var fileData in IterateClipboardContent(dataObject)) foreach (var fileData in IterateClipboardContent(dataObject))
{ {
try try
{ {
using (ImageHelper.FromStream(fileData)) var extension = Path.GetExtension(fileData.filename)?.ToLowerInvariant();
if (supportedExtensions.Contains(extension))
{ {
// If we get here, there is an image
return true; return true;
} }
} }
@ -316,7 +318,7 @@ EndSelection:<<<<<<<4
} }
finally finally
{ {
fileData?.Dispose(); fileData.stream?.Dispose();
} }
} }
@ -328,6 +330,7 @@ EndSelection:<<<<<<<4
var imageStream = clipboardContent as MemoryStream; var imageStream = clipboardContent as MemoryStream;
if (IsValidStream(imageStream)) if (IsValidStream(imageStream))
{ {
// TODO: How to check if we support "just a stream"?
using (ImageHelper.FromStream(imageStream)) using (ImageHelper.FromStream(imageStream))
{ {
// If we get here, there is an image // If we get here, there is an image
@ -374,8 +377,8 @@ EndSelection:<<<<<<<4
/// Iterate the clipboard content /// Iterate the clipboard content
/// </summary> /// </summary>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>IEnumerable{MemoryStream}</returns> /// <returns>IEnumerable{(MemoryStream,string)}</returns>
private static IEnumerable<MemoryStream> IterateClipboardContent(IDataObject dataObject) private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject)
{ {
var fileDescriptors = AvailableFileDescriptors(dataObject); var fileDescriptors = AvailableFileDescriptors(dataObject);
if (fileDescriptors == null) yield break; if (fileDescriptors == null) yield break;
@ -414,8 +417,8 @@ EndSelection:<<<<<<<4
/// </summary> /// </summary>
/// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param> /// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>IEnumerable{MemoryStream}</returns> /// <returns>IEnumerable{(MemoryStream stream, string filename)}</returns>
private static IEnumerable<MemoryStream> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject) private static IEnumerable<(MemoryStream stream, string filename)> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
{ {
if (fileDescriptors == null) if (fileDescriptors == null)
{ {
@ -446,7 +449,7 @@ EndSelection:<<<<<<<4
if (fileData?.Length > 0) if (fileData?.Length > 0)
{ {
fileData.Position = 0; fileData.Position = 0;
yield return fileData; yield return (fileData, fileDescriptor.FileName);
} }
fileIndex++; fileIndex++;
@ -505,56 +508,75 @@ EndSelection:<<<<<<<4
/// </summary> /// </summary>
/// <param name="dataObject"></param> /// <param name="dataObject"></param>
/// <returns>IEnumerable of Image</returns> /// <returns>IEnumerable of Image</returns>
public static IEnumerable<Image> GetImages(IDataObject dataObject) public static IEnumerable<IDrawableContainer> GetImages(IDataObject dataObject)
{ {
// Get single image, this takes the "best" match // Get single image, this takes the "best" match
Image singleImage = GetImage(dataObject); IDrawableContainer singleImage = GetImage(dataObject);
if (singleImage != null) if (singleImage != null)
{ {
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
yield return singleImage; yield return singleImage;
yield break;
} }
else
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
foreach (var fileData in IterateClipboardContent(dataObject))
{ {
foreach (var fileData in IterateClipboardContent(dataObject)) var extension = Path.GetExtension(fileData.filename)?.ToLowerInvariant();
if (!supportedExtensions.Contains(extension))
{ {
Image image; continue;
try }
IDrawableContainer drawableContainer = null;
try
{
if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(fileData.stream, extension, out drawableContainer))
{ {
image = ImageHelper.FromStream(fileData);
}
catch (Exception ex)
{
Log.Error("Couldn't read file contents", ex);
continue; continue;
} }
finally
{
fileData?.Dispose();
}
// If we get here, there is an image
yield return image;
}
// check if files are supplied }
foreach (string imageFile in GetImageFilenames(dataObject)) catch (Exception ex)
{ {
Image returnImage = null; Log.Error("Couldn't read file contents", ex);
try continue;
{ }
returnImage = ImageHelper.LoadImage(imageFile); finally
} {
catch (Exception streamImageEx) fileData.stream?.Dispose();
{ }
Log.Error("Problem retrieving Image from clipboard.", streamImageEx); // If we get here, there is an image
} yield return drawableContainer;
}
if (returnImage != null) // check if files are supplied
foreach (string imageFile in GetImageFilenames(dataObject))
{
var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
if (!supportedExtensions.Contains(extension))
{
continue;
}
IDrawableContainer drawableContainer = null;
using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
try
{
if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(fileStream, extension, out drawableContainer))
{ {
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); continue;
yield return returnImage;
} }
} }
catch (Exception ex)
{
Log.Error("Couldn't read file contents", ex);
continue;
}
// If we get here, there is an image
yield return drawableContainer;
} }
} }
@ -563,51 +585,50 @@ EndSelection:<<<<<<<4
/// </summary> /// </summary>
/// <param name="dataObject"></param> /// <param name="dataObject"></param>
/// <returns>Image or null</returns> /// <returns>Image or null</returns>
private static Image GetImage(IDataObject dataObject) private static IDrawableContainer GetImage(IDataObject dataObject)
{ {
Image returnImage = null; if (dataObject == null) return null;
if (dataObject != null)
{
IList<string> formats = GetFormats(dataObject);
string[] retrieveFormats;
// Found a weird bug, where PNG's from Outlook 2010 are clipped IDrawableContainer returnImage = null;
// So I build some special logic to get the best format: IList<string> formats = GetFormats(dataObject);
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) 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[]
{ {
// Outlook ?? DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
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..."); DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
retrieveFormats = new[] };
{ }
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, else
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML {
}; 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 = GetImageForFormat(currentFormat, dataObject);
} }
else else
{ {
retrieveFormats = new[] Log.DebugFormat("Couldn't find format {0}.", currentFormat);
{
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 (returnImage != null)
{ {
if (formats != null && formats.Contains(currentFormat)) return returnImage;
{
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
returnImage = GetImageForFormat(currentFormat, dataObject);
}
else
{
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
}
if (returnImage != null)
{
return returnImage;
}
} }
} }
@ -615,15 +636,17 @@ EndSelection:<<<<<<<4
} }
/// <summary> /// <summary>
/// Helper method to try to get an image in the specified format from the dataObject /// Helper method to try to get an IDrawableContainer in the specified format from the dataObject
/// the DIB reader should solve some issues /// the DIB reader should solve some issues
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591 /// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
/// </summary> /// </summary>
/// <param name="format">string with the format</param> /// <param name="format">string with the format</param>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>Image or null</returns> /// <returns>IDrawableContainer or null</returns>
private static Image GetImageForFormat(string format, IDataObject dataObject) private static IDrawableContainer GetImageForFormat(string format, IDataObject dataObject)
{ {
IDrawableContainer drawableContainer = null;
if (format == FORMAT_HTML) if (format == FORMAT_HTML)
{ {
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
@ -639,10 +662,10 @@ EndSelection:<<<<<<<4
var srcAttribute = imgNode.Attributes["src"]; var srcAttribute = imgNode.Attributes["src"];
var imageUrl = srcAttribute.Value; var imageUrl = srcAttribute.Value;
Log.Debug(imageUrl); Log.Debug(imageUrl);
var image = NetworkHelper.DownloadImage(imageUrl); drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl);
if (image != null) if (drawableContainer != null)
{ {
return image; return drawableContainer;
} }
} }
} }
@ -653,110 +676,29 @@ EndSelection:<<<<<<<4
var imageStream = clipboardObject as MemoryStream; var imageStream = clipboardObject as MemoryStream;
if (!IsValidStream(imageStream)) if (!IsValidStream(imageStream))
{ {
// TODO: add "HTML Format" support here... // TODO: add text based, like "HTML Format" support here...
// TODO: solve the issue that we do not have a factory for the ImageContainer
/*var image = clipboardObject as Image;
if (image != null)
{
return new ImageContainer(this)
{
Image = image,
Left = x,
Top = y
};
}
return clipboardObject as Image; return clipboardObject as Image;
*/
return null;
} }
if (CoreConfig.EnableSpecialDIBClipboardReader) // From here, imageStream is a valid stream
if (!FileFormatHandlerRegistry.TryLoadDrawableFromStream(imageStream, format, out drawableContainer))
{ {
if (format == FORMAT_17 || format == DataFormats.Dib) return drawableContainer;
{
Log.Info("Found DIB stream, trying to process it.");
try
{
if (imageStream != null)
{
byte[] dibBuffer = new byte[imageStream.Length];
_ = imageStream.Read(dibBuffer, 0, dibBuffer.Length);
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADERV5>(dibBuffer);
if (!infoHeader.IsDibV5)
{
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
uint infoHeaderSize = infoHeader.biSize;
int fileSize = (int) (fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
var fileHeader = new BITMAPFILEHEADER
{
bfType = BITMAPFILEHEADER.BM,
bfSize = fileSize,
bfReserved1 = 0,
bfReserved2 = 0,
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4)
};
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
using var bitmapStream = new MemoryStream();
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
bitmapStream.Seek(0, SeekOrigin.Begin);
var image = ImageHelper.FromStream(bitmapStream);
if (image != null)
{
return image;
}
}
else
{
Log.Info("Using special DIBV5 / Format17 format reader");
// CF_DIBV5
IntPtr gcHandle = IntPtr.Zero;
try
{
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
gcHandle = GCHandle.ToIntPtr(handle);
return
new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
-(int) (infoHeader.biSizeImage / infoHeader.biHeight),
infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels +
(infoHeader.biHeight - 1) * (int) (infoHeader.biSizeImage / infoHeader.biHeight))
);
}
catch (Exception ex)
{
Log.Error("Problem retrieving Format17 from clipboard.", ex);
}
finally
{
if (gcHandle == IntPtr.Zero)
{
GCHandle.FromIntPtr(gcHandle).Free();
}
}
}
}
}
catch (Exception dibEx)
{
Log.Error("Problem retrieving DIB from clipboard.", dibEx);
}
}
} }
else
{
Log.Info("Skipping special DIB format reader as it's disabled in the configuration.");
}
try
{
if (imageStream != null)
{
imageStream.Seek(0, SeekOrigin.Begin);
var tmpImage = ImageHelper.FromStream(imageStream);
if (tmpImage != null)
{
Log.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
return tmpImage;
}
}
}
catch (Exception streamImageEx)
{
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
}
return null; return null;
} }
@ -1132,16 +1074,14 @@ EndSelection:<<<<<<<4
public static IEnumerable<string> GetImageFilenames(IDataObject dataObject) public static IEnumerable<string> GetImageFilenames(IDataObject dataObject)
{ {
string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop); string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop);
if (dropFileNames != null && dropFileNames.Length > 0) if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty<string>();
{
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList(); var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
return dropFileNames return dropFileNames
.Where(filename => !string.IsNullOrEmpty(filename)) .Where(filename => !string.IsNullOrEmpty(filename))
.Where(Path.HasExtension) .Where(Path.HasExtension)
.Where(filename => supportedExtensions.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); .Where(filename => supportedExtensions.Contains(Path.GetExtension(filename)));
}
return Enumerable.Empty<string>();
} }
/// <summary> /// <summary>

View file

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
namespace Greenshot.Base.Core.FileFormatHandlers
{
public abstract class AbstractFileFormatHandler
{
/// <summary>
/// Make sure we handle the input extension always the same, by "normalizing" it
/// </summary>
/// <param name="extension">string</param>
/// <returns>string</returns>
protected string NormalizeExtension(string extension)
{
if (string.IsNullOrEmpty(extension))
{
return null;
}
extension = extension.ToLowerInvariant();
return !extension.StartsWith(".") ? $".{extension}" : extension;
}
}
}

View file

@ -24,6 +24,7 @@ using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Base.Core.FileFormatHandlers
{ {
@ -31,13 +32,6 @@ namespace Greenshot.Base.Core.FileFormatHandlers
{ {
public static IList<IFileFormatHandler> FileFormatHandlers { get; } = new List<IFileFormatHandler>(); public static IList<IFileFormatHandler> FileFormatHandlers { get; } = new List<IFileFormatHandler>();
static FileFormatHandlerRegistry()
{
FileFormatHandlers.Add(new IconFileFormatHandler());
FileFormatHandlers.Add(new GreenshotFileFormatHandler());
FileFormatHandlers.Add(new DefaultFileFormatHandler());
}
public static IEnumerable<string> ExtensionsFor(FileFormatHandlerActions fileFormatHandlerAction) public static IEnumerable<string> ExtensionsFor(FileFormatHandlerActions fileFormatHandlerAction)
{ {
return FileFormatHandlers.SelectMany(ffh => ffh.SupportedExtensions(fileFormatHandlerAction)).Distinct(); return FileFormatHandlers.SelectMany(ffh => ffh.SupportedExtensions(fileFormatHandlerAction)).Distinct();
@ -66,5 +60,29 @@ namespace Greenshot.Base.Core.FileFormatHandlers
return fileFormatHandler.TrySaveToStream(bitmap, destination, extension); return fileFormatHandler.TrySaveToStream(bitmap, destination, extension);
} }
/// <summary>
/// Try to load a drawable container from the stream
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="extension">string</param>
/// <param name="drawableContainer">IDrawableContainer out</param>
/// <param name="parentSurface">ISurface</param>
/// <returns>bool true if it was successful</returns>
public static bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parentSurface = null)
{
var fileFormatHandler = FileFormatHandlers
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadDrawableFromStream, extension))
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadDrawableFromStream, extension))
.FirstOrDefault();
if (fileFormatHandler == null)
{
drawableContainer = null;
return false;
}
return fileFormatHandler.TryLoadDrawableFromStream(stream, extension, out drawableContainer, parentSurface);
}
} }
} }

View file

@ -1320,7 +1320,7 @@ namespace Greenshot.Base.Core
} }
// If no pixelformat is supplied // If no pixelformat is supplied
if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) if (targetFormat is PixelFormat.DontCare or PixelFormat.Undefined)
{ {
if (SupportsPixelFormat(sourceImage.PixelFormat)) if (SupportsPixelFormat(sourceImage.PixelFormat))
{ {

View file

@ -31,6 +31,7 @@ using System.Text.RegularExpressions;
using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using log4net; using log4net;
@ -89,25 +90,13 @@ namespace Greenshot.Base.Core
} }
/// <summary> /// <summary>
/// Download the uri to Bitmap /// Download the uri to build an IDrawableContainer
/// </summary> /// </summary>
/// <param name="url">Of an image</param> /// <param name="url">Of an image</param>
/// <returns>Bitmap</returns> /// <returns>IDrawableContainer</returns>
public static Image DownloadImage(string url) public static IDrawableContainer DownloadImageAsDrawableContainer(string url)
{ {
var extensions = new StringBuilder(); var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
foreach (var extension in supportedExtensions)
{
if (string.IsNullOrEmpty(extension))
{
continue;
}
extensions.AppendFormat(@"\.{0}|", extension);
}
extensions.Length--;
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})"); var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
var match = imageUrlRegex.Match(url); var match = imageUrlRegex.Match(url);
@ -116,7 +105,10 @@ namespace Greenshot.Base.Core
using var memoryStream = GetAsMemoryStream(url); using var memoryStream = GetAsMemoryStream(url);
try try
{ {
return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); if (FileFormatHandlerRegistry.TryLoadDrawableFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer))
{
return drawableContainer;
}
} }
catch (Exception) catch (Exception)
{ {
@ -139,7 +131,10 @@ namespace Greenshot.Base.Core
} }
using var memoryStream2 = GetAsMemoryStream(match.Value); using var memoryStream2 = GetAsMemoryStream(match.Value);
return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); if (FileFormatHandlerRegistry.TryLoadDrawableFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var drawableContainer))
{
return drawableContainer;
}
} }
} }
catch (Exception e) catch (Exception e)

View file

@ -30,7 +30,14 @@ namespace Greenshot.Base.Interfaces.Drawing
{ {
public interface IDrawableContainer : INotifyPropertyChanged, IDisposable public interface IDrawableContainer : INotifyPropertyChanged, IDisposable
{ {
/// <summary>
/// The parent surface where this IDrawableContainer is on
/// </summary>
ISurface Parent { get; set; } ISurface Parent { get; set; }
/// <summary>
/// Is this IDrawableContainer selected on the surface
/// </summary>
bool Selected { get; set; } bool Selected { get; set; }
int Left { get; set; } int Left { get; set; }
@ -54,15 +61,25 @@ namespace Greenshot.Base.Interfaces.Drawing
bool HasFilters { get; } bool HasFilters { get; }
EditStatus Status { get; set; } EditStatus Status { get; set; }
void Invalidate(); void Invalidate();
bool ClickableAt(int x, int y); bool ClickableAt(int x, int y);
void MoveBy(int x, int y); void MoveBy(int x, int y);
void Transform(Matrix matrix); void Transform(Matrix matrix);
bool HandleMouseDown(int x, int y); bool HandleMouseDown(int x, int y);
void HandleMouseUp(int x, int y); void HandleMouseUp(int x, int y);
bool HandleMouseMove(int x, int y); bool HandleMouseMove(int x, int y);
bool InitContent(); bool InitContent();
void MakeBoundsChangeUndoable(bool allowMerge); void MakeBoundsChangeUndoable(bool allowMerge);
EditStatus DefaultEditMode { get; } EditStatus DefaultEditMode { get; }
/// <summary> /// <summary>

View file

@ -89,8 +89,8 @@ namespace Greenshot.Base.Interfaces
/// <param name="stream">Stream</param> /// <param name="stream">Stream</param>
/// <param name="extension">string</param> /// <param name="extension">string</param>
/// <param name="drawableContainer">IDrawableContainer out</param> /// <param name="drawableContainer">IDrawableContainer out</param>
/// <param name="parent">ISurface</param> /// <param name="parentSurface">ISurface</param>
/// <returns>bool true if it was successful</returns> /// <returns>bool true if it was successful</returns>
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent); public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parentSurface = null);
} }
} }

View file

@ -61,6 +61,11 @@ namespace Greenshot.Editor.Drawing
Load(filename); Load(filename);
} }
public IconContainer(ISurface parent, Stream stream) : base(parent)
{
Load(stream);
}
public Icon Icon public Icon Icon
{ {
set set
@ -100,6 +105,18 @@ namespace Greenshot.Editor.Drawing
Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
} }
public void Load(Stream iconStream)
{
if (iconStream == null)
{
return;
}
using Icon fileIcon = new Icon(iconStream);
Icon = fileIcon;
Log.Debug("Loaded stream: with resolution: " + Height + "," + Width);
}
public override void Draw(Graphics graphics, RenderMode rm) public override void Draw(Graphics graphics, RenderMode rm)
{ {
if (icon == null) if (icon == null)

View file

@ -0,0 +1,71 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: https://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 <https://www.gnu.org/licenses/>.
*/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Greenshot.Base.Core;
using Greenshot.Base.Interfaces;
using Svg;
namespace Greenshot.Editor.Drawing
{
/// <summary>
/// This provides a resizable SVG container, redrawing the SVG in the size the container takes.
/// </summary>
[Serializable]
public class MetafileContainer : VectorGraphicsContainer
{
private readonly Metafile _metafile;
public MetafileContainer(Metafile metafile, ISurface parent) : base(parent)
{
_metafile = metafile;
Size = new Size(metafile.Width/4, metafile.Height/4);
}
protected override Image ComputeBitmap()
{
var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent);
var dstRect = new Rectangle(0, 0, Width, Height);
using (Graphics graphics = Graphics.FromImage(image))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(_metafile, dstRect);
}
if (RotationAngle == 0) return image;
var newImage = image.Rotate(RotationAngle);
image.Dispose();
return newImage;
}
public override bool HasDefaultSize => true;
public override Size DefaultSize => new Size(_metafile.Width, _metafile.Height);
}
}

View file

@ -49,7 +49,6 @@ namespace Greenshot.Editor.Drawing
public sealed class Surface : Control, ISurface, INotifyPropertyChanged public sealed class Surface : Control, ISurface, INotifyPropertyChanged
{ {
private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface));
public static int Count;
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
// Property to identify the Surface ID // Property to identify the Surface ID
@ -207,7 +206,7 @@ namespace Greenshot.Editor.Drawing
[NonSerialized] private IDrawableContainer _undrawnElement; [NonSerialized] private IDrawableContainer _undrawnElement;
/// <summary> /// <summary>
/// the cropcontainer, when cropping this is set, do not serialize /// the crop container, when cropping this is set, do not serialize
/// </summary> /// </summary>
[NonSerialized] private IDrawableContainer _cropContainer; [NonSerialized] private IDrawableContainer _cropContainer;
@ -467,7 +466,6 @@ namespace Greenshot.Editor.Drawing
public Surface() public Surface()
{ {
_fieldAggregator = new FieldAggregator(this); _fieldAggregator = new FieldAggregator(this);
Count++;
_elements = new DrawableContainerList(_uniqueId); _elements = new DrawableContainerList(_uniqueId);
selectedElements = new DrawableContainerList(_uniqueId); selectedElements = new DrawableContainerList(_uniqueId);
LOG.Debug("Creating surface!"); LOG.Debug("Creating surface!");
@ -550,7 +548,6 @@ namespace Greenshot.Editor.Drawing
{ {
if (disposing) if (disposing)
{ {
Count--;
LOG.Debug("Disposing surface!"); LOG.Debug("Disposing surface!");
if (_buffer != null) if (_buffer != null)
{ {
@ -927,20 +924,23 @@ namespace Greenshot.Editor.Drawing
// Test if it's an url and try to download the image so we have it in the original form // Test if it's an url and try to download the image so we have it in the original form
if (possibleUrl != null && possibleUrl.StartsWith("http")) if (possibleUrl != null && possibleUrl.StartsWith("http"))
{ {
using Image image = NetworkHelper.DownloadImage(possibleUrl); var drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(possibleUrl);
if (image != null) if (drawableContainer != null)
{ {
AddImageContainer(image, mouse.X, mouse.Y); drawableContainer.Left = Location.X;
drawableContainer.Top = Location.Y;
AddElement(drawableContainer);
return; return;
} }
} }
} }
foreach (Image image in ClipboardHelper.GetImages(e.Data)) foreach (var drawableContainer in ClipboardHelper.GetImages(e.Data))
{ {
AddImageContainer(image, mouse.X, mouse.Y); drawableContainer.Left = mouse.X;
drawableContainer.Top = mouse.Y;
AddElement(drawableContainer);
mouse.Offset(10, 10); mouse.Offset(10, 10);
image.Dispose();
} }
} }
@ -2057,17 +2057,15 @@ namespace Greenshot.Editor.Drawing
{ {
Point pasteLocation = GetPasteLocation(0.1f, 0.1f); Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) foreach (var drawableContainer in ClipboardHelper.GetImages(clipboard))
{ {
if (clipboardImage != null) if (drawableContainer == null) continue;
{ DeselectAllElements();
DeselectAllElements(); drawableContainer.Left = pasteLocation.X;
IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); drawableContainer.Top = pasteLocation.Y;
SelectElement(container); SelectElement(drawableContainer);
clipboardImage.Dispose(); pasteLocation.X += 10;
pasteLocation.X += 10; pasteLocation.Y += 10;
pasteLocation.Y += 10;
}
} }
} }
else if (ClipboardHelper.ContainsText(clipboard)) else if (ClipboardHelper.ContainsText(clipboard))

View file

@ -21,7 +21,6 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging;
using Greenshot.Base.Core; using Greenshot.Base.Core;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Svg; using Svg;
@ -44,14 +43,19 @@ namespace Greenshot.Editor.Drawing
protected override Image ComputeBitmap() protected override Image ComputeBitmap()
{ {
var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppRgb, Color.Transparent); //var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent);
_svgDocument.Draw(image); var image = _svgDocument.Draw(Width, Height);
if (RotationAngle == 0) return image; if (RotationAngle == 0) return image;
var newImage = image.Rotate(RotationAngle); var newImage = image.Rotate(RotationAngle);
image.Dispose(); image.Dispose();
return newImage; return newImage;
} }
public override bool HasDefaultSize => true;
public override Size DefaultSize => new Size((int)_svgDocument.Width, (int)_svgDocument.Height);
} }
} }

View file

@ -22,9 +22,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Core;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
@ -78,6 +76,7 @@ namespace Greenshot.Editor.Drawing
base.Dispose(disposing); base.Dispose(disposing);
} }
/// <inheritdoc cref="IDrawableContainer"/>
public override void Transform(Matrix matrix) public override void Transform(Matrix matrix)
{ {
RotationAngle += CalculateAngle(matrix); RotationAngle += CalculateAngle(matrix);
@ -88,34 +87,26 @@ namespace Greenshot.Editor.Drawing
base.Transform(matrix); base.Transform(matrix);
} }
/// <inheritdoc cref="IDrawableContainer"/>
public override void Draw(Graphics graphics, RenderMode rm) public override void Draw(Graphics graphics, RenderMode rm)
{ {
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
if (_cachedImage != null && _cachedImage.Size != Bounds.Size) if (_cachedImage != null && _cachedImage.Size != Bounds.Size)
{ {
ResetCachedBitmap(); ResetCachedBitmap();
} }
_cachedImage ??= ComputeBitmap(); _cachedImage ??= ComputeBitmap();
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(_cachedImage, Bounds); graphics.DrawImage(_cachedImage, Bounds);
} }
protected virtual Image ComputeBitmap() protected abstract Image ComputeBitmap();
{
var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppRgb, Color.Transparent);
if (RotationAngle == 0) return image;
var newImage = image.Rotate(RotationAngle);
image.Dispose();
return newImage;
}
private void ResetCachedBitmap() private void ResetCachedBitmap()
{ {

View file

@ -29,6 +29,11 @@ namespace Greenshot.Editor
public static void Initialize() public static void Initialize()
{ {
FileFormatHandlerRegistry.FileFormatHandlers.Add(new SvgFileFormatHandler()); FileFormatHandlerRegistry.FileFormatHandlers.Add(new SvgFileFormatHandler());
FileFormatHandlerRegistry.FileFormatHandlers.Add(new DefaultFileFormatHandler());
FileFormatHandlerRegistry.FileFormatHandlers.Add(new DibFileFormatHandler());
FileFormatHandlerRegistry.FileFormatHandlers.Add(new GreenshotFileFormatHandler());
FileFormatHandlerRegistry.FileFormatHandlers.Add(new IconFileFormatHandler());
FileFormatHandlerRegistry.FileFormatHandlers.Add(new MetaFileFormatHandler());
} }
} }
} }

View file

@ -19,44 +19,36 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Greenshot.Base.Core;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Editor.FileFormatHandlers
{ {
/// <summary> /// <summary>
/// This is the default .NET bitmap file format handler /// This is the default .NET bitmap file format handler
/// </summary> /// </summary>
public class DefaultFileFormatHandler : IFileFormatHandler public class DefaultFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private static readonly string [] OurExtensions = { "png", "bmp", "gif", "jpg", "jpeg", "tiff", "tif" }; private static readonly string [] OurExtensions = { ".png", ".bmp", ".gif", ".jpg", ".jpeg", ".tiff", ".tif" };
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction) public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
{
return Enumerable.Empty<string>();
}
return OurExtensions; return OurExtensions;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension) public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream) return OurExtensions.Contains(NormalizeExtension(extension));
{
return false;
}
return OurExtensions.Contains(extension?.ToLowerInvariant());
} }
/// <inheritdoc /> /// <inheritdoc />
@ -68,15 +60,15 @@ namespace Greenshot.Base.Core.FileFormatHandlers
/// <inheritdoc /> /// <inheritdoc />
public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension) public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension)
{ {
ImageFormat imageFormat = extension?.ToLowerInvariant() switch ImageFormat imageFormat = NormalizeExtension(extension) switch
{ {
"png" => ImageFormat.Png, ".png" => ImageFormat.Png,
"bmp" => ImageFormat.Bmp, ".bmp" => ImageFormat.Bmp,
"gif" => ImageFormat.Gif, ".gif" => ImageFormat.Gif,
"jpg" => ImageFormat.Jpeg, ".jpg" => ImageFormat.Jpeg,
"jpeg" => ImageFormat.Jpeg, ".jpeg" => ImageFormat.Jpeg,
"tiff" => ImageFormat.Tiff, ".tiff" => ImageFormat.Tiff,
"tif" => ImageFormat.Tiff, ".tif" => ImageFormat.Tiff,
_ => null _ => null
}; };
@ -97,9 +89,20 @@ namespace Greenshot.Base.Core.FileFormatHandlers
} }
/// <inheritdoc /> /// <inheritdoc />
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface) public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface = null)
{ {
throw new NotImplementedException(); if (TryLoadFromStream(stream, extension, out var bitmap))
{
var imageContainer = new ImageContainer(surface)
{
Image = bitmap
};
drawableContainer = imageContainer;
return true;
}
drawableContainer = null;
return true;
} }
} }
} }

View file

@ -26,40 +26,36 @@ using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Greenshot.Base.Core;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using Greenshot.Editor.Drawing;
using log4net;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Editor.FileFormatHandlers
{ {
/// <summary> /// <summary>
/// This handles creating a DIB (Device Independent Bitmap) on the clipboard /// This handles creating a DIB (Device Independent Bitmap) on the clipboard
/// </summary> /// </summary>
public class DibFileFormatHandler : IFileFormatHandler public class DibFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private const double DpiToPelsPerMeter = 39.3701; private const double DpiToPelsPerMeter = 39.3701;
private static readonly string [] OurExtensions = { "dib" }; private static readonly ILog Log = LogManager.GetLogger(typeof(DibFileFormatHandler));
private static readonly string [] OurExtensions = { ".dib", ".format17" };
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction) public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
{
return Enumerable.Empty<string>();
}
return OurExtensions; return OurExtensions;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension) public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{ {
if (string.IsNullOrEmpty(extension) || fileFormatHandlerAction != FileFormatHandlerActions.SaveToStream) extension = NormalizeExtension(extension);
{ return OurExtensions.Contains(extension);
return false;
}
return OurExtensions.Contains(extension.ToLowerInvariant());
} }
/// <inheritdoc /> /// <inheritdoc />
@ -79,13 +75,79 @@ namespace Greenshot.Base.Core.FileFormatHandlers
/// <inheritdoc /> /// <inheritdoc />
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
{ {
throw new NotImplementedException(); byte[] dibBuffer = new byte[stream.Length];
_ = stream.Read(dibBuffer, 0, dibBuffer.Length);
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADERV5>(dibBuffer);
if (!infoHeader.IsDibV5)
{
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
uint infoHeaderSize = infoHeader.biSize;
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
var fileHeader = new BITMAPFILEHEADER
{
bfType = BITMAPFILEHEADER.BM,
bfSize = fileSize,
bfReserved1 = 0,
bfReserved2 = 0,
bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4)
};
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
using var bitmapStream = new MemoryStream();
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
bitmapStream.Seek(0, SeekOrigin.Begin);
bitmap = ImageHelper.FromStream(bitmapStream) as Bitmap;
return true;
}
Log.Info("Using special DIBV5 / Format17 format reader");
// CF_DIBV5
IntPtr gcHandle = IntPtr.Zero;
try
{
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
gcHandle = GCHandle.ToIntPtr(handle);
bitmap = new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
-(int)(infoHeader.biSizeImage / infoHeader.biHeight),
infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels +
(infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight))
);
}
catch (Exception ex)
{
Log.Error("Problem retrieving Format17 from clipboard.", ex);
bitmap = null;
}
finally
{
if (gcHandle == IntPtr.Zero)
{
GCHandle.FromIntPtr(gcHandle).Free();
}
}
return true;
} }
/// <inheritdoc /> /// <inheritdoc />
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface) public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface = null)
{ {
throw new NotImplementedException(); if (TryLoadFromStream(stream, extension, out var bitmap))
{
var imageContainer = new ImageContainer(surface)
{
Image = bitmap
};
drawableContainer = imageContainer;
return true;
}
drawableContainer = null;
return true;
} }

View file

@ -24,14 +24,16 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Greenshot.Base.Core;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Editor.FileFormatHandlers
{ {
public class GreenshotFileFormatHandler : IFileFormatHandler public class GreenshotFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private static readonly string[] OurExtensions = { "greenshot" }; private static readonly string[] OurExtensions = { ".greenshot" };
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction) public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
@ -51,8 +53,12 @@ namespace Greenshot.Base.Core.FileFormatHandlers
{ {
return false; return false;
} }
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{
return false;
}
return OurExtensions.Contains(extension?.ToLowerInvariant()); return OurExtensions.Contains(NormalizeExtension(extension));
} }
@ -75,7 +81,7 @@ namespace Greenshot.Base.Core.FileFormatHandlers
return true; return true;
} }
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent) public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent = null)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View file

@ -25,25 +25,28 @@ using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Greenshot.Base.Core;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
using log4net; using log4net;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Editor.FileFormatHandlers
{ {
/// <summary> /// <summary>
/// THis is the default .NET bitmap file format handler /// THis is the default .NET bitmap file format handler
/// </summary> /// </summary>
public class IconFileFormatHandler : IFileFormatHandler public class IconFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper));
private static readonly string[] OurExtensions = { "ico" }; private static readonly string[] OurExtensions = { ".ico" };
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction) public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream) if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{ {
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
@ -54,12 +57,12 @@ namespace Greenshot.Base.Core.FileFormatHandlers
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension) public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream) if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{ {
return false; return false;
} }
return OurExtensions.Contains(extension?.ToLowerInvariant()); return OurExtensions.Contains(NormalizeExtension(extension));
} }
/// <inheritdoc /> /// <inheritdoc />
@ -76,7 +79,7 @@ namespace Greenshot.Base.Core.FileFormatHandlers
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
{ {
var startingPosition = stream.Seek(0, SeekOrigin.Current); _ = stream.Seek(0, SeekOrigin.Current);
// Icon logic, try to get the Vista icon, else the biggest possible // Icon logic, try to get the Vista icon, else the biggest possible
try try
@ -113,10 +116,20 @@ namespace Greenshot.Base.Core.FileFormatHandlers
} }
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent) public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface = null)
{ {
// TODO: Implement this if (TryLoadFromStream(stream, extension, out var bitmap))
throw new NotImplementedException(); {
var imageContainer = new ImageContainer(surface)
{
Image = bitmap
};
drawableContainer = imageContainer;
return true;
}
drawableContainer = null;
return true;
} }
/// <summary> /// <summary>

View file

@ -0,0 +1,108 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
*
* For more information see: https://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 <https://www.gnu.org/licenses/>.
*/
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;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.FileFormatHandlers
{
/// <summary>
/// This handles the Windows metafile files
/// </summary>
public class MetaFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{
private static readonly string [] OurExtensions = { ".wmf", ".emf" };
/// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
{
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{
return Enumerable.Empty<string>();
}
return OurExtensions;
}
/// <inheritdoc />
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{
return false;
}
return OurExtensions.Contains(NormalizeExtension(extension));
}
/// <inheritdoc />
public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{
return int.MaxValue;
}
/// <inheritdoc />
public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension)
{
return false;
}
/// <inheritdoc />
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
{
try
{
if (Image.FromStream(stream, true, true) is Metafile metaFile)
{
bitmap = ImageHelper.Clone(metaFile, PixelFormat.Format32bppArgb);
return true;
}
}
catch
{
// Ignore
}
bitmap = null;
return false;
}
/// <inheritdoc />
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface surface = null)
{
if (Image.FromStream(stream, true, true) is Metafile metaFile)
{
drawableContainer = new MetafileContainer(metaFile, surface);
return true;
}
drawableContainer = null;
return false;
}
}
}

View file

@ -27,7 +27,7 @@ using System.Linq;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
namespace Greenshot.Base.Core.FileFormatHandlers namespace Greenshot.Editor.FileFormatHandlers
{ {
/// <summary> /// <summary>
/// This can be an ImageSharp implementation /// This can be an ImageSharp implementation

View file

@ -26,6 +26,7 @@ using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Greenshot.Base.Core; using Greenshot.Base.Core;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing; using Greenshot.Editor.Drawing;
@ -37,15 +38,15 @@ namespace Greenshot.Editor.FileFormatHandlers
/// <summary> /// <summary>
/// This handled the loading of SVG images to the editor /// This handled the loading of SVG images to the editor
/// </summary> /// </summary>
public class SvgFileFormatHandler : IFileFormatHandler public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler));
private static readonly string[] OurExtensions = { "svg" }; private static readonly string[] OurExtensions = { ".svg" };
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction) public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream) if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{ {
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
@ -56,12 +57,12 @@ namespace Greenshot.Editor.FileFormatHandlers
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension) public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
{ {
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream) if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
{ {
return false; return false;
} }
return OurExtensions.Contains(extension); return OurExtensions.Contains(NormalizeExtension(extension));
} }
/// <inheritdoc /> /// <inheritdoc />
public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension) public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension)
@ -96,9 +97,14 @@ namespace Greenshot.Editor.FileFormatHandlers
return false; return false;
} }
public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent) public bool TryLoadDrawableFromStream(Stream stream, string extension, out IDrawableContainer drawableContainer, ISurface parent = null)
{ {
var svgDocument = SvgDocument.Open<SvgDocument>(stream); var svgDocument = SvgDocument.Open<SvgDocument>(stream);
if (svgDocument == null)
{
drawableContainer = null;
return false;
}
drawableContainer = new SvgContainer(svgDocument, parent); drawableContainer = new SvgContainer(svgDocument, parent);
return true; return true;
} }

View file

@ -1,4 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<None Include="Languages\language*.xml"> <None Include="Languages\language*.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View file

@ -389,6 +389,7 @@ namespace Greenshot.Helpers
HandleCapture(); HandleCapture();
break; break;
case CaptureMode.Clipboard: case CaptureMode.Clipboard:
// TODO: Fix getting image vs. drawablecontainer
Image clipboardImage = ClipboardHelper.GetImage(); Image clipboardImage = ClipboardHelper.GetImage();
if (clipboardImage != null) if (clipboardImage != null)
{ {