mirror of
https://github.com/greenshot/greenshot
synced 2025-08-22 06:23:24 -07:00
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:
parent
a074162ea5
commit
eb9bbb8937
22 changed files with 611 additions and 326 deletions
|
@ -34,6 +34,7 @@ using Greenshot.Base.Core.Enums;
|
|||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
|
@ -300,13 +301,14 @@ EndSelection:<<<<<<<4
|
|||
return true;
|
||||
}
|
||||
|
||||
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
foreach (var fileData in IterateClipboardContent(dataObject))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +318,7 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
finally
|
||||
{
|
||||
fileData?.Dispose();
|
||||
fileData.stream?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,6 +330,7 @@ EndSelection:<<<<<<<4
|
|||
var imageStream = clipboardContent as MemoryStream;
|
||||
if (IsValidStream(imageStream))
|
||||
{
|
||||
// TODO: How to check if we support "just a stream"?
|
||||
using (ImageHelper.FromStream(imageStream))
|
||||
{
|
||||
// If we get here, there is an image
|
||||
|
@ -374,8 +377,8 @@ EndSelection:<<<<<<<4
|
|||
/// Iterate the clipboard content
|
||||
/// </summary>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>IEnumerable{MemoryStream}</returns>
|
||||
private static IEnumerable<MemoryStream> IterateClipboardContent(IDataObject dataObject)
|
||||
/// <returns>IEnumerable{(MemoryStream,string)}</returns>
|
||||
private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject)
|
||||
{
|
||||
var fileDescriptors = AvailableFileDescriptors(dataObject);
|
||||
if (fileDescriptors == null) yield break;
|
||||
|
@ -414,8 +417,8 @@ EndSelection:<<<<<<<4
|
|||
/// </summary>
|
||||
/// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>IEnumerable{MemoryStream}</returns>
|
||||
private static IEnumerable<MemoryStream> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
|
||||
/// <returns>IEnumerable{(MemoryStream stream, string filename)}</returns>
|
||||
private static IEnumerable<(MemoryStream stream, string filename)> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
|
||||
{
|
||||
if (fileDescriptors == null)
|
||||
{
|
||||
|
@ -446,7 +449,7 @@ EndSelection:<<<<<<<4
|
|||
if (fileData?.Length > 0)
|
||||
{
|
||||
fileData.Position = 0;
|
||||
yield return fileData;
|
||||
yield return (fileData, fileDescriptor.FileName);
|
||||
}
|
||||
|
||||
fileIndex++;
|
||||
|
@ -505,56 +508,75 @@ EndSelection:<<<<<<<4
|
|||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <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
|
||||
Image singleImage = GetImage(dataObject);
|
||||
IDrawableContainer singleImage = GetImage(dataObject);
|
||||
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 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;
|
||||
try
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
try
|
||||
{
|
||||
returnImage = ImageHelper.LoadImage(imageFile);
|
||||
}
|
||||
catch (Exception streamImageEx)
|
||||
{
|
||||
Log.Error("Problem retrieving Image from clipboard.", streamImageEx);
|
||||
}
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fileData.stream?.Dispose();
|
||||
}
|
||||
// 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);
|
||||
yield return returnImage;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImage(IDataObject dataObject)
|
||||
private static IDrawableContainer GetImage(IDataObject dataObject)
|
||||
{
|
||||
Image returnImage = null;
|
||||
if (dataObject != null)
|
||||
{
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
string[] retrieveFormats;
|
||||
if (dataObject == null) return null;
|
||||
|
||||
// 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))
|
||||
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[]
|
||||
{
|
||||
// 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
|
||||
};
|
||||
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 = GetImageForFormat(currentFormat, dataObject);
|
||||
}
|
||||
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
|
||||
};
|
||||
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
||||
foreach (string currentFormat in retrieveFormats)
|
||||
if (returnImage != null)
|
||||
{
|
||||
if (formats != null && formats.Contains(currentFormat))
|
||||
{
|
||||
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;
|
||||
}
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -615,15 +636,17 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
|
||||
/// <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
|
||||
/// 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>Image or null</returns>
|
||||
private static Image GetImageForFormat(string format, IDataObject dataObject)
|
||||
/// <returns>IDrawableContainer or null</returns>
|
||||
private static IDrawableContainer GetImageForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
IDrawableContainer drawableContainer = null;
|
||||
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
|
@ -639,10 +662,10 @@ EndSelection:<<<<<<<4
|
|||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
var image = NetworkHelper.DownloadImage(imageUrl);
|
||||
if (image != null)
|
||||
drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl);
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return image;
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,110 +676,29 @@ EndSelection:<<<<<<<4
|
|||
var imageStream = clipboardObject as MemoryStream;
|
||||
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 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return drawableContainer;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1132,16 +1074,14 @@ EndSelection:<<<<<<<4
|
|||
public static IEnumerable<string> GetImageFilenames(IDataObject dataObject)
|
||||
{
|
||||
string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop);
|
||||
if (dropFileNames != null && dropFileNames.Length > 0)
|
||||
{
|
||||
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
|
||||
return dropFileNames
|
||||
.Where(filename => !string.IsNullOrEmpty(filename))
|
||||
.Where(Path.HasExtension)
|
||||
.Where(filename => supportedExtensions.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1)));
|
||||
}
|
||||
if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty<string>();
|
||||
|
||||
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
|
||||
return dropFileNames
|
||||
.Where(filename => !string.IsNullOrEmpty(filename))
|
||||
.Where(Path.HasExtension)
|
||||
.Where(filename => supportedExtensions.Contains(Path.GetExtension(filename)));
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ using System.Drawing;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
{
|
||||
|
@ -31,13 +32,6 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
{
|
||||
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)
|
||||
{
|
||||
return FileFormatHandlers.SelectMany(ffh => ffh.SupportedExtensions(fileFormatHandlerAction)).Distinct();
|
||||
|
@ -66,5 +60,29 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1320,7 +1320,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
// If no pixelformat is supplied
|
||||
if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat)
|
||||
if (targetFormat is PixelFormat.DontCare or PixelFormat.Undefined)
|
||||
{
|
||||
if (SupportsPixelFormat(sourceImage.PixelFormat))
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@ using System.Text.RegularExpressions;
|
|||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
|
||||
|
@ -89,25 +90,13 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download the uri to Bitmap
|
||||
/// Download the uri to build an IDrawableContainer
|
||||
/// </summary>
|
||||
/// <param name="url">Of an image</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Image DownloadImage(string url)
|
||||
/// <returns>IDrawableContainer</returns>
|
||||
public static IDrawableContainer DownloadImageAsDrawableContainer(string url)
|
||||
{
|
||||
var extensions = new StringBuilder();
|
||||
var supportedExtensions = FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
|
||||
foreach (var extension in supportedExtensions)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
extensions.AppendFormat(@"\.{0}|", extension);
|
||||
}
|
||||
|
||||
extensions.Length--;
|
||||
var extensions = string.Join("|", FileFormatHandlerRegistry.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
|
||||
|
||||
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||
var match = imageUrlRegex.Match(url);
|
||||
|
@ -116,7 +105,10 @@ namespace Greenshot.Base.Core
|
|||
using var memoryStream = GetAsMemoryStream(url);
|
||||
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)
|
||||
{
|
||||
|
@ -139,7 +131,10 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -30,7 +30,14 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
{
|
||||
public interface IDrawableContainer : INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The parent surface where this IDrawableContainer is on
|
||||
/// </summary>
|
||||
ISurface Parent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this IDrawableContainer selected on the surface
|
||||
/// </summary>
|
||||
bool Selected { get; set; }
|
||||
|
||||
int Left { get; set; }
|
||||
|
@ -54,15 +61,25 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
bool HasFilters { get; }
|
||||
|
||||
EditStatus Status { get; set; }
|
||||
|
||||
void Invalidate();
|
||||
|
||||
bool ClickableAt(int x, int y);
|
||||
|
||||
void MoveBy(int x, int y);
|
||||
|
||||
void Transform(Matrix matrix);
|
||||
|
||||
bool HandleMouseDown(int x, int y);
|
||||
|
||||
void HandleMouseUp(int x, int y);
|
||||
|
||||
bool HandleMouseMove(int x, int y);
|
||||
|
||||
bool InitContent();
|
||||
|
||||
void MakeBoundsChangeUndoable(bool allowMerge);
|
||||
|
||||
EditStatus DefaultEditMode { get; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -89,8 +89,8 @@ namespace Greenshot.Base.Interfaces
|
|||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</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>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,11 @@ namespace Greenshot.Editor.Drawing
|
|||
Load(filename);
|
||||
}
|
||||
|
||||
public IconContainer(ISurface parent, Stream stream) : base(parent)
|
||||
{
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
public Icon Icon
|
||||
{
|
||||
set
|
||||
|
@ -100,6 +105,18 @@ namespace Greenshot.Editor.Drawing
|
|||
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)
|
||||
{
|
||||
if (icon == null)
|
||||
|
|
71
src/Greenshot.Editor/Drawing/MetafileContainer.cs
Normal file
71
src/Greenshot.Editor/Drawing/MetafileContainer.cs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -49,7 +49,6 @@ namespace Greenshot.Editor.Drawing
|
|||
public sealed class Surface : Control, ISurface, INotifyPropertyChanged
|
||||
{
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface));
|
||||
public static int Count;
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
// Property to identify the Surface ID
|
||||
|
@ -207,7 +206,7 @@ namespace Greenshot.Editor.Drawing
|
|||
[NonSerialized] private IDrawableContainer _undrawnElement;
|
||||
|
||||
/// <summary>
|
||||
/// the cropcontainer, when cropping this is set, do not serialize
|
||||
/// the crop container, when cropping this is set, do not serialize
|
||||
/// </summary>
|
||||
[NonSerialized] private IDrawableContainer _cropContainer;
|
||||
|
||||
|
@ -467,7 +466,6 @@ namespace Greenshot.Editor.Drawing
|
|||
public Surface()
|
||||
{
|
||||
_fieldAggregator = new FieldAggregator(this);
|
||||
Count++;
|
||||
_elements = new DrawableContainerList(_uniqueId);
|
||||
selectedElements = new DrawableContainerList(_uniqueId);
|
||||
LOG.Debug("Creating surface!");
|
||||
|
@ -550,7 +548,6 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
Count--;
|
||||
LOG.Debug("Disposing surface!");
|
||||
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
|
||||
if (possibleUrl != null && possibleUrl.StartsWith("http"))
|
||||
{
|
||||
using Image image = NetworkHelper.DownloadImage(possibleUrl);
|
||||
if (image != null)
|
||||
var drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(possibleUrl);
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
AddImageContainer(image, mouse.X, mouse.Y);
|
||||
drawableContainer.Left = Location.X;
|
||||
drawableContainer.Top = Location.Y;
|
||||
AddElement(drawableContainer);
|
||||
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);
|
||||
image.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2057,17 +2057,15 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
|
||||
|
||||
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
|
||||
foreach (var drawableContainer in ClipboardHelper.GetImages(clipboard))
|
||||
{
|
||||
if (clipboardImage != null)
|
||||
{
|
||||
DeselectAllElements();
|
||||
IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y);
|
||||
SelectElement(container);
|
||||
clipboardImage.Dispose();
|
||||
pasteLocation.X += 10;
|
||||
pasteLocation.Y += 10;
|
||||
}
|
||||
if (drawableContainer == null) continue;
|
||||
DeselectAllElements();
|
||||
drawableContainer.Left = pasteLocation.X;
|
||||
drawableContainer.Top = pasteLocation.Y;
|
||||
SelectElement(drawableContainer);
|
||||
pasteLocation.X += 10;
|
||||
pasteLocation.Y += 10;
|
||||
}
|
||||
}
|
||||
else if (ClipboardHelper.ContainsText(clipboard))
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Svg;
|
||||
|
@ -44,14 +43,19 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
protected override Image ComputeBitmap()
|
||||
{
|
||||
var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppRgb, Color.Transparent);
|
||||
//var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent);
|
||||
|
||||
var image = _svgDocument.Draw(Width, Height);
|
||||
|
||||
_svgDocument.Draw(image);
|
||||
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((int)_svgDocument.Width, (int)_svgDocument.Height);
|
||||
}
|
||||
}
|
|
@ -22,9 +22,7 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
|
||||
|
@ -78,6 +76,7 @@ namespace Greenshot.Editor.Drawing
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
public override void Transform(Matrix matrix)
|
||||
{
|
||||
RotationAngle += CalculateAngle(matrix);
|
||||
|
@ -88,13 +87,9 @@ namespace Greenshot.Editor.Drawing
|
|||
base.Transform(matrix);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
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)
|
||||
{
|
||||
ResetCachedBitmap();
|
||||
|
@ -102,20 +97,16 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
_cachedImage ??= ComputeBitmap();
|
||||
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
|
||||
graphics.DrawImage(_cachedImage, Bounds);
|
||||
}
|
||||
|
||||
protected virtual 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;
|
||||
|
||||
}
|
||||
protected abstract Image ComputeBitmap();
|
||||
|
||||
private void ResetCachedBitmap()
|
||||
{
|
||||
|
|
|
@ -29,6 +29,11 @@ namespace Greenshot.Editor
|
|||
public static void Initialize()
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,44 +19,36 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the default .NET bitmap file format handler
|
||||
/// </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 />
|
||||
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
return OurExtensions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return OurExtensions.Contains(extension?.ToLowerInvariant());
|
||||
return OurExtensions.Contains(NormalizeExtension(extension));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -68,15 +60,15 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
/// <inheritdoc />
|
||||
public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension)
|
||||
{
|
||||
ImageFormat imageFormat = extension?.ToLowerInvariant() switch
|
||||
ImageFormat imageFormat = NormalizeExtension(extension) switch
|
||||
{
|
||||
"png" => ImageFormat.Png,
|
||||
"bmp" => ImageFormat.Bmp,
|
||||
"gif" => ImageFormat.Gif,
|
||||
"jpg" => ImageFormat.Jpeg,
|
||||
"jpeg" => ImageFormat.Jpeg,
|
||||
"tiff" => ImageFormat.Tiff,
|
||||
"tif" => ImageFormat.Tiff,
|
||||
".png" => ImageFormat.Png,
|
||||
".bmp" => ImageFormat.Bmp,
|
||||
".gif" => ImageFormat.Gif,
|
||||
".jpg" => ImageFormat.Jpeg,
|
||||
".jpeg" => ImageFormat.Jpeg,
|
||||
".tiff" => ImageFormat.Tiff,
|
||||
".tif" => ImageFormat.Tiff,
|
||||
_ => null
|
||||
};
|
||||
|
||||
|
@ -97,9 +89,20 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,40 +26,36 @@ using System.Drawing.Imaging;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Editor.Drawing;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This handles creating a DIB (Device Independent Bitmap) on the clipboard
|
||||
/// </summary>
|
||||
public class DibFileFormatHandler : IFileFormatHandler
|
||||
public class DibFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
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 />
|
||||
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
return OurExtensions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension) || fileFormatHandlerAction != FileFormatHandlerActions.SaveToStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return OurExtensions.Contains(extension.ToLowerInvariant());
|
||||
extension = NormalizeExtension(extension);
|
||||
return OurExtensions.Contains(extension);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -79,13 +75,79 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
/// <inheritdoc />
|
||||
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 />
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -24,14 +24,16 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.Interfaces;
|
||||
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 />
|
||||
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
|
||||
|
@ -51,8 +53,12 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
|
@ -25,25 +25,28 @@ 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;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// THis is the default .NET bitmap file format handler
|
||||
/// </summary>
|
||||
public class IconFileFormatHandler : IFileFormatHandler
|
||||
public class IconFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper));
|
||||
|
||||
private static readonly string[] OurExtensions = { "ico" };
|
||||
private static readonly string[] OurExtensions = { ".ico" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
@ -54,12 +57,12 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
/// <inheritdoc />
|
||||
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return OurExtensions.Contains(extension?.ToLowerInvariant());
|
||||
return OurExtensions.Contains(NormalizeExtension(extension));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -76,7 +79,7 @@ namespace Greenshot.Base.Core.FileFormatHandlers
|
|||
|
||||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
108
src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs
Normal file
108
src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ using System.Linq;
|
|||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This can be an ImageSharp implementation
|
|
@ -26,6 +26,7 @@ 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;
|
||||
|
@ -37,15 +38,15 @@ namespace Greenshot.Editor.FileFormatHandlers
|
|||
/// <summary>
|
||||
/// This handled the loading of SVG images to the editor
|
||||
/// </summary>
|
||||
public class SvgFileFormatHandler : IFileFormatHandler
|
||||
public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper));
|
||||
private static readonly string[] OurExtensions = { "svg" };
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler));
|
||||
private static readonly string[] OurExtensions = { ".svg" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> SupportedExtensions(FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
@ -56,12 +57,12 @@ namespace Greenshot.Editor.FileFormatHandlers
|
|||
/// <inheritdoc />
|
||||
public bool Supports(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.LoadDrawableFromStream)
|
||||
if (fileFormatHandlerAction == FileFormatHandlerActions.SaveToStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return OurExtensions.Contains(extension);
|
||||
return OurExtensions.Contains(NormalizeExtension(extension));
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
|
@ -96,9 +97,14 @@ namespace Greenshot.Editor.FileFormatHandlers
|
|||
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);
|
||||
if (svgDocument == null)
|
||||
{
|
||||
drawableContainer = null;
|
||||
return false;
|
||||
}
|
||||
drawableContainer = new SvgContainer(svgDocument, parent);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Languages\language*.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
|
@ -389,6 +389,7 @@ namespace Greenshot.Helpers
|
|||
HandleCapture();
|
||||
break;
|
||||
case CaptureMode.Clipboard:
|
||||
// TODO: Fix getting image vs. drawablecontainer
|
||||
Image clipboardImage = ClipboardHelper.GetImage();
|
||||
if (clipboardImage != null)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue