mirror of
https://github.com/greenshot/greenshot
synced 2025-08-20 21:43:24 -07:00
Merge branch 'release/1.3' into fix/379-preferences-window
# Conflicts: # src/Greenshot/Forms/SettingsForm.Designer.cs
This commit is contained in:
commit
1585d1c2ea
90 changed files with 2795 additions and 1340 deletions
|
@ -120,6 +120,7 @@ namespace Greenshot.Base.Controls
|
|||
|
||||
private void PrepareFilterOptions()
|
||||
{
|
||||
// TODO: Change to the FileFormatHandlerRegistry to look for all the supported extensions
|
||||
OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat));
|
||||
_filterOptions = new FilterOption[supportedImageFormats.Length];
|
||||
for (int i = 0; i < _filterOptions.Length; i++)
|
||||
|
@ -166,7 +167,7 @@ namespace Greenshot.Base.Controls
|
|||
// if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay
|
||||
if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn;
|
||||
// otherwise we just add the selected filter item's extension
|
||||
else return fn + "." + Extension;
|
||||
return fn + "." + Extension;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
|
|
@ -31,8 +31,10 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
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;
|
||||
|
@ -63,7 +65,8 @@ namespace Greenshot.Base.Core
|
|||
//private static readonly string FORMAT_HTML = "HTML Format";
|
||||
|
||||
// Template for the HTML Text on the clipboard
|
||||
// see: https://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx
|
||||
// see: https://msdn.microsoft.com/en-us/library/ms649015%28v=v
|
||||
// s.85%29.aspx
|
||||
// or: https://msdn.microsoft.com/en-us/library/Aa767917.aspx
|
||||
private const string HtmlClipboardString = @"Version:0.9
|
||||
StartHTML:<<<<<<<1
|
||||
|
@ -298,14 +301,15 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var fileData in IterateClipboardContent(dataObject))
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (ImageHelper.FromStream(fileData))
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (supportedExtensions.Contains(extension))
|
||||
{
|
||||
// If we get here, there is an image
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +319,7 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
finally
|
||||
{
|
||||
fileData?.Dispose();
|
||||
stream?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,7 +331,8 @@ EndSelection:<<<<<<<4
|
|||
var imageStream = clipboardContent as MemoryStream;
|
||||
if (IsValidStream(imageStream))
|
||||
{
|
||||
using (ImageHelper.FromStream(imageStream))
|
||||
// TODO: How to check if we support "just a stream"?
|
||||
using (ImageIO.FromStream(imageStream))
|
||||
{
|
||||
// If we get here, there is an image
|
||||
return true;
|
||||
|
@ -373,8 +378,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;
|
||||
|
@ -413,8 +418,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)
|
||||
{
|
||||
|
@ -445,7 +450,7 @@ EndSelection:<<<<<<<4
|
|||
if (fileData?.Length > 0)
|
||||
{
|
||||
fileData.Position = 0;
|
||||
yield return fileData;
|
||||
yield return (fileData, fileDescriptor.FileName);
|
||||
}
|
||||
|
||||
fileIndex++;
|
||||
|
@ -490,7 +495,7 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
IDataObject clipboardData = GetDataObject();
|
||||
// Return the first image
|
||||
foreach (Image clipboardImage in GetImages(clipboardData))
|
||||
foreach (var clipboardImage in GetImages(clipboardData))
|
||||
{
|
||||
return clipboardImage;
|
||||
}
|
||||
|
@ -503,57 +508,154 @@ EndSelection:<<<<<<<4
|
|||
/// Returned images must be disposed by the calling code!
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>IEnumerable of Image</returns>
|
||||
public static IEnumerable<Image> GetImages(IDataObject dataObject)
|
||||
/// <returns>IEnumerable of Bitmap</returns>
|
||||
public static IEnumerable<Bitmap> GetImages(IDataObject dataObject)
|
||||
{
|
||||
// Get single image, this takes the "best" match
|
||||
Image singleImage = GetImage(dataObject);
|
||||
Bitmap 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 fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
{
|
||||
foreach (var fileData in IterateClipboardContent(dataObject))
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
Image image;
|
||||
try
|
||||
{
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if files are supplied
|
||||
foreach (string imageFile in GetImageFilenames(dataObject))
|
||||
Bitmap bitmap = null;
|
||||
|
||||
try
|
||||
{
|
||||
Image returnImage = null;
|
||||
try
|
||||
if (!fileFormatHandlers.TryLoadFromStream(stream, extension, out bitmap))
|
||||
{
|
||||
returnImage = ImageHelper.LoadImage(imageFile);
|
||||
}
|
||||
catch (Exception streamImageEx)
|
||||
{
|
||||
Log.Error("Problem retrieving Image from clipboard.", streamImageEx);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (returnImage != null)
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Dispose();
|
||||
}
|
||||
// If we get here, there is an image
|
||||
yield return bitmap;
|
||||
}
|
||||
|
||||
// check if files are supplied
|
||||
foreach (string imageFile in GetImageFilenames(dataObject))
|
||||
{
|
||||
var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Bitmap bitmap = null;
|
||||
using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
try
|
||||
{
|
||||
if (!fileFormatHandlers.TryLoadFromStream(fileStream, extension, out bitmap))
|
||||
{
|
||||
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 bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all images (multiple if file names are available) from the dataObject
|
||||
/// Returned images must be disposed by the calling code!
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>IEnumerable of IDrawableContainer</returns>
|
||||
public static IEnumerable<IDrawableContainer> GetDrawables(IDataObject dataObject)
|
||||
{
|
||||
// Get single image, this takes the "best" match
|
||||
IDrawableContainer singleImage = GetDrawable(dataObject);
|
||||
if (singleImage != null)
|
||||
{
|
||||
Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
|
||||
yield return singleImage;
|
||||
yield break;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
{
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IEnumerable<IDrawableContainer> drawableContainers;
|
||||
try
|
||||
{
|
||||
drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(stream, extension);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Dispose();
|
||||
}
|
||||
// If we get here, there is an image
|
||||
foreach (var container in drawableContainers)
|
||||
{
|
||||
yield return container;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
IEnumerable<IDrawableContainer> drawableContainers;
|
||||
try
|
||||
{
|
||||
drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(fileStream, extension);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
// If we get here, there is an image
|
||||
foreach (var container in drawableContainers)
|
||||
{
|
||||
yield return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,51 +664,50 @@ EndSelection:<<<<<<<4
|
|||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImage(IDataObject dataObject)
|
||||
private static Bitmap 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))
|
||||
Bitmap 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,15 +715,72 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an image in the specified format from the dataObject
|
||||
/// Get an IDrawableContainer from the IDataObject, don't check for FileDrop
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static IDrawableContainer GetDrawable(IDataObject dataObject)
|
||||
{
|
||||
if (dataObject == null) return null;
|
||||
|
||||
IDrawableContainer returnImage = null;
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
string[] retrieveFormats;
|
||||
|
||||
// Found a weird bug, where PNG's from Outlook 2010 are clipped
|
||||
// So I build some special logic to get the best format:
|
||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
|
||||
{
|
||||
// Outlook ??
|
||||
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
|
||||
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
|
||||
FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
|
||||
foreach (string currentFormat in retrieveFormats)
|
||||
{
|
||||
if (formats != null && formats.Contains(currentFormat))
|
||||
{
|
||||
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
returnImage = GetDrawableForFormat(currentFormat, dataObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
||||
if (returnImage != null)
|
||||
{
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an Bitmap in the specified format from the dataObject
|
||||
/// the DIB reader should solve some issues
|
||||
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImageForFormat(string format, IDataObject dataObject)
|
||||
/// <returns>Bitmap or null</returns>
|
||||
private static Bitmap GetImageForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
Bitmap bitmap = null;
|
||||
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
|
@ -638,10 +796,10 @@ EndSelection:<<<<<<<4
|
|||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
var image = NetworkHelper.DownloadImage(imageUrl);
|
||||
if (image != null)
|
||||
bitmap = NetworkHelper.DownloadImage(imageUrl);
|
||||
if (bitmap != null)
|
||||
{
|
||||
return image;
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,111 +810,80 @@ EndSelection:<<<<<<<4
|
|||
var imageStream = clipboardObject as MemoryStream;
|
||||
if (!IsValidStream(imageStream))
|
||||
{
|
||||
// TODO: add "HTML Format" support here...
|
||||
return clipboardObject as Image;
|
||||
return clipboardObject as Bitmap;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
if (CoreConfig.EnableSpecialDIBClipboardReader)
|
||||
// From here, imageStream is a valid stream
|
||||
if (!fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap))
|
||||
{
|
||||
if (format == FORMAT_17 || format == DataFormats.Dib)
|
||||
return bitmap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an IDrawableContainer in the specified format from the dataObject
|
||||
/// the DIB reader should solve some issues
|
||||
/// 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>IDrawableContainer or null</returns>
|
||||
private static IDrawableContainer GetDrawableForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
IDrawableContainer drawableContainer = null;
|
||||
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
if (textObject != null)
|
||||
{
|
||||
Log.Info("Found DIB stream, trying to process it.");
|
||||
try
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(textObject);
|
||||
var imgNodes = doc.DocumentNode.SelectNodes("//img");
|
||||
if (imgNodes != null)
|
||||
{
|
||||
if (imageStream != null)
|
||||
foreach (var imgNode in imgNodes)
|
||||
{
|
||||
byte[] dibBuffer = new byte[imageStream.Length];
|
||||
_ = imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADERV5>(dibBuffer);
|
||||
if (!infoHeader.IsDibV5)
|
||||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl);
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||
var imageStream = clipboardObject as MemoryStream;
|
||||
if (!IsValidStream(imageStream))
|
||||
{
|
||||
if (imageStream != null)
|
||||
// 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)
|
||||
{
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
var tmpImage = ImageHelper.FromStream(imageStream);
|
||||
if (tmpImage != null)
|
||||
return new ImageContainer(this)
|
||||
{
|
||||
Log.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
|
||||
return tmpImage;
|
||||
}
|
||||
Image = image,
|
||||
Left = x,
|
||||
Top = y
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception streamImageEx)
|
||||
{
|
||||
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
|
||||
return clipboardObject as Image;
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
// From here, imageStream is a valid stream
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
return fileFormatHandlers.LoadDrawablesFromStream(imageStream, format).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -840,7 +967,7 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||
// Create the image which is going to be saved so we don't create it multiple times
|
||||
disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
||||
disposeImage = ImageIO.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
||||
try
|
||||
{
|
||||
// Create PNG stream
|
||||
|
@ -849,7 +976,7 @@ EndSelection:<<<<<<<4
|
|||
pngStream = new MemoryStream();
|
||||
// PNG works for e.g. Powerpoint
|
||||
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||
ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
|
||||
ImageIO.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
|
||||
pngStream.Seek(0, SeekOrigin.Begin);
|
||||
// Set the PNG stream
|
||||
dataObject.SetData(FORMAT_PNG, false, pngStream);
|
||||
|
@ -866,11 +993,18 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
// Create the stream for the clipboard
|
||||
dibStream = new MemoryStream();
|
||||
var dibBytes = ((Bitmap)imageToSave).ConvertToDib();
|
||||
dibStream.Write(dibBytes,0, dibBytes.Length);
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
// Set the DIB to the clipboard DataObject
|
||||
dataObject.SetData(DataFormats.Dib, false, dibStream);
|
||||
if (!fileFormatHandlers.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib))
|
||||
{
|
||||
dibStream.Dispose();
|
||||
dibStream = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the DIB to the clipboard DataObject
|
||||
dataObject.SetData(DataFormats.Dib, false, dibStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception dibEx)
|
||||
|
@ -924,7 +1058,7 @@ EndSelection:<<<<<<<4
|
|||
// Set the HTML
|
||||
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML))
|
||||
{
|
||||
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||
string tmpFile = ImageIO.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||
string html = GetHtmlString(surface, tmpFile);
|
||||
dataObject.SetText(html, TextDataFormat.Html);
|
||||
}
|
||||
|
@ -942,11 +1076,11 @@ EndSelection:<<<<<<<4
|
|||
// Check if we can use the previously used image
|
||||
if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed)
|
||||
{
|
||||
ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
|
||||
ImageIO.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings);
|
||||
ImageIO.SaveToStream(surface, tmpPngStream, pngOutputSettings);
|
||||
}
|
||||
|
||||
html = GetHtmlDataUrlString(surface, tmpPngStream);
|
||||
|
@ -1125,15 +1259,15 @@ EndSelection:<<<<<<<4
|
|||
public static IEnumerable<string> GetImageFilenames(IDataObject dataObject)
|
||||
{
|
||||
string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop);
|
||||
if (dropFileNames != null && dropFileNames.Length > 0)
|
||||
{
|
||||
return dropFileNames
|
||||
.Where(filename => !string.IsNullOrEmpty(filename))
|
||||
.Where(Path.HasExtension)
|
||||
.Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1)));
|
||||
}
|
||||
if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty<string>();
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
var supportedExtensions = fileFormatHandlers.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>
|
||||
|
|
36
src/Greenshot.Base/Core/Enums/ExifOrientations.cs
Normal file
36
src/Greenshot.Base/Core/Enums/ExifOrientations.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
{
|
||||
internal enum ExifOrientations : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
BottomRight = 3,
|
||||
BottomLeft = 4,
|
||||
LeftTop = 5,
|
||||
RightTop = 6,
|
||||
RightBottom = 7,
|
||||
LeftBottom = 8,
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ namespace Greenshot.Base.Core.Enums
|
|||
jpg,
|
||||
png,
|
||||
tiff,
|
||||
jxr,
|
||||
greenshot,
|
||||
ico
|
||||
}
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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.IO;
|
||||
using System.Linq;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the registry where all IFileFormatHandler are registered and can be used
|
||||
/// </summary>
|
||||
public static class FileFormatHandlerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Make sure we handle the input extension always the same, by "normalizing" it
|
||||
/// </summary>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>string</returns>
|
||||
public static string NormalizeExtension(string extension)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
extension = extension.ToLowerInvariant();
|
||||
return !extension.StartsWith(".") ? $".{extension}" : extension;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the extensions that the provided IFileFormatHandlers can accept for the specified action
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="fileFormatHandlerAction"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> ExtensionsFor(this IEnumerable<IFileFormatHandler> fileFormatHandlers, FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
return fileFormatHandlers.Where(ffh => ffh.SupportedExtensions.ContainsKey(fileFormatHandlerAction)).SelectMany(ffh => ffh.SupportedExtensions[fileFormatHandlerAction]).Distinct().OrderBy(e => e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to check if a certain IFileFormatHandler supports a certain action with a specific extension
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandler">IFileFormatHandler</param>
|
||||
/// <param name="fileFormatHandlerAction">FileFormatHandlerActions</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool Supports(this IFileFormatHandler fileFormatHandler, FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
return fileFormatHandler.SupportedExtensions.ContainsKey(fileFormatHandlerAction) && fileFormatHandler.SupportedExtensions[fileFormatHandlerAction].Contains(extension);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This wrapper method for TrySaveToStream will do:
|
||||
/// Find all the IFileFormatHandler which support the action for the supplied extension.
|
||||
/// Take the first, to call the TrySaveToStream on.
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <param name="destination">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool TrySaveToStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var saveFileFormatHandlers = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)).ToList();
|
||||
|
||||
if (!saveFileFormatHandlers.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var fileFormatHandler in saveFileFormatHandlers)
|
||||
{
|
||||
if (fileFormatHandler.TrySaveToStream(bitmap, destination, extension, surface))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a drawable container from the stream
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="parentSurface">ISurface</param>
|
||||
/// <returns>IEnumerable{IDrawableContainer}</returns>
|
||||
public static IEnumerable<IDrawableContainer> LoadDrawablesFromStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Stream stream, string extension, ISurface parentSurface = null)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var loadfileFormatHandler = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadDrawableFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadDrawableFromStream, extension))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (loadfileFormatHandler != null)
|
||||
{
|
||||
return loadfileFormatHandler.LoadDrawablesFromStream(stream, extension, parentSurface);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<IDrawableContainer>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a Bitmap from the stream
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="bitmap">Bitmap out</param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public static bool TryLoadFromStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var loadFileFormatHandler = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (loadFileFormatHandler == null)
|
||||
{
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return loadFileFormatHandler.TryLoadFromStream(stream, extension, out bitmap);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,7 +61,7 @@ namespace Greenshot.Base.Core
|
|||
float HorizontalResolution { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Unterlying image, or an on demand rendered version with different attributes as the original
|
||||
/// Underlying image, or an on demand rendered version with different attributes as the original
|
||||
/// </summary>
|
||||
Image Image { get; }
|
||||
}
|
||||
|
|
|
@ -24,28 +24,24 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Effects;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
using Brush = System.Drawing.Brush;
|
||||
using Color = System.Drawing.Color;
|
||||
using Matrix = System.Drawing.Drawing2D.Matrix;
|
||||
using Pen = System.Drawing.Pen;
|
||||
using PixelFormat = System.Drawing.Imaging.PixelFormat;
|
||||
using Point = System.Drawing.Point;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
internal enum ExifOrientations : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
BottomRight = 3,
|
||||
BottomLeft = 4,
|
||||
LeftTop = 5,
|
||||
RightTop = 6,
|
||||
RightBottom = 7,
|
||||
LeftBottom = 8,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description of ImageHelper.
|
||||
/// </summary>
|
||||
|
@ -55,83 +51,6 @@ namespace Greenshot.Base.Core
|
|||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const int ExifOrientationId = 0x0112;
|
||||
|
||||
static ImageHelper()
|
||||
{
|
||||
StreamConverters["greenshot"] = (stream, s) =>
|
||||
{
|
||||
var surface = SimpleServiceProvider.Current.GetInstance<Func<ISurface>>().Invoke();
|
||||
return surface.GetImageForExport();
|
||||
};
|
||||
|
||||
// Add a SVG converter
|
||||
StreamConverters["svg"] = (stream, s) =>
|
||||
{
|
||||
stream.Position = 0;
|
||||
try
|
||||
{
|
||||
return SvgImage.FromStream(stream).Image;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Can't load SVG", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
static Image DefaultConverter(Stream stream, string s)
|
||||
{
|
||||
stream.Position = 0;
|
||||
using var tmpImage = Image.FromStream(stream, true, true);
|
||||
Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
// Fallback
|
||||
StreamConverters[string.Empty] = DefaultConverter;
|
||||
StreamConverters["gif"] = DefaultConverter;
|
||||
StreamConverters["bmp"] = DefaultConverter;
|
||||
StreamConverters["jpg"] = DefaultConverter;
|
||||
StreamConverters["jpeg"] = DefaultConverter;
|
||||
StreamConverters["png"] = DefaultConverter;
|
||||
StreamConverters["wmf"] = DefaultConverter;
|
||||
|
||||
StreamConverters["ico"] = (stream, extension) =>
|
||||
{
|
||||
// Icon logic, try to get the Vista icon, else the biggest possible
|
||||
try
|
||||
{
|
||||
using Image tmpImage = ExtractVistaIcon(stream);
|
||||
if (tmpImage != null)
|
||||
{
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
}
|
||||
catch (Exception vistaIconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", vistaIconException);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// No vista icon, try normal icon
|
||||
stream.Position = 0;
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
using Icon tmpIcon = new Icon(stream, new Size(1024, 1024));
|
||||
using Image tmpImage = tmpIcon.ToBitmap();
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
catch (Exception iconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", iconException);
|
||||
}
|
||||
|
||||
stream.Position = 0;
|
||||
return DefaultConverter(stream, extension);
|
||||
};
|
||||
}
|
||||
|
||||
public static IDictionary<string, Func<Stream, string, Image>> StreamConverters { get; } = new Dictionary<string, Func<Stream, string, Image>>();
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the image is orientated correctly
|
||||
|
@ -371,127 +290,6 @@ namespace Greenshot.Base.Core
|
|||
return cropRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an image from file
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public static Image LoadImage(string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Image fileImage;
|
||||
Log.InfoFormat("Loading image from file {0}", filename);
|
||||
// Fixed lock problem Bug #3431881
|
||||
using (Stream imageFileStream = File.OpenRead(filename))
|
||||
{
|
||||
fileImage = FromStream(imageFileStream, Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return fileImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx
|
||||
/// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx
|
||||
/// </summary>
|
||||
/// <param name="iconStream">Stream with the icon information</param>
|
||||
/// <returns>Bitmap with the Vista Icon (256x256)</returns>
|
||||
private static Bitmap ExtractVistaIcon(Stream iconStream)
|
||||
{
|
||||
const int sizeIconDir = 6;
|
||||
const int sizeIconDirEntry = 16;
|
||||
Bitmap bmpPngExtracted = null;
|
||||
try
|
||||
{
|
||||
byte[] srcBuf = new byte[iconStream.Length];
|
||||
iconStream.Read(srcBuf, 0, (int) iconStream.Length);
|
||||
int iCount = BitConverter.ToInt16(srcBuf, 4);
|
||||
for (int iIndex = 0; iIndex < iCount; iIndex++)
|
||||
{
|
||||
int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
|
||||
int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
|
||||
if (iWidth == 0 && iHeight == 0)
|
||||
{
|
||||
int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
|
||||
int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
|
||||
using MemoryStream destStream = new MemoryStream();
|
||||
destStream.Write(srcBuf, iImageOffset, iImageSize);
|
||||
destStream.Seek(0, SeekOrigin.Begin);
|
||||
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return bmpPngExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx
|
||||
/// </summary>
|
||||
/// <param name="location">The file (EXE or DLL) to get the icon from</param>
|
||||
/// <param name="index">Index of the icon</param>
|
||||
/// <param name="takeLarge">true if the large icon is wanted</param>
|
||||
/// <returns>Icon</returns>
|
||||
public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge)
|
||||
{
|
||||
Shell32.ExtractIconEx(location, index, out var large, out var small, 1);
|
||||
Icon returnIcon = null;
|
||||
bool isLarge = false;
|
||||
bool isSmall = false;
|
||||
try
|
||||
{
|
||||
if (takeLarge && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
else if (!IntPtr.Zero.Equals(small))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(small);
|
||||
isSmall = true;
|
||||
}
|
||||
else if (!IntPtr.Zero.Equals(large))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isLarge && !IntPtr.Zero.Equals(small))
|
||||
{
|
||||
User32.DestroyIcon(small);
|
||||
}
|
||||
|
||||
if (isSmall && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
User32.DestroyIcon(large);
|
||||
}
|
||||
}
|
||||
|
||||
return returnIcon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply the effect to the bitmap
|
||||
/// </summary>
|
||||
|
@ -563,8 +361,7 @@ namespace Greenshot.Base.Core
|
|||
/// <returns>Changed bitmap</returns>
|
||||
public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges)
|
||||
{
|
||||
Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution,
|
||||
sourceImage.VerticalResolution);
|
||||
Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
|
||||
using (var path = new GraphicsPath())
|
||||
{
|
||||
Random random = new Random();
|
||||
|
@ -1396,7 +1193,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))
|
||||
{
|
||||
|
@ -1517,10 +1314,10 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="height"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="backgroundColor">The color to fill with, or Color.Empty to take the default depending on the pixel format</param>
|
||||
/// <param name="horizontalResolution"></param>
|
||||
/// <param name="verticalResolution"></param>
|
||||
/// <param name="horizontalResolution">float</param>
|
||||
/// <param name="verticalResolution">float</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution)
|
||||
public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution = 96f, float verticalResolution = 96f)
|
||||
{
|
||||
// Create a new "clean" image
|
||||
Bitmap newImage = new Bitmap(width, height, format);
|
||||
|
@ -1711,98 +1508,106 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a Greenshot surface from a stream
|
||||
/// Rotate the image
|
||||
/// </summary>
|
||||
/// <param name="surfaceFileStream">Stream</param>
|
||||
/// <param name="returnSurface"></param>
|
||||
/// <returns>ISurface</returns>
|
||||
public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface)
|
||||
/// <param name="image">Input image</param>
|
||||
/// <param name="rotationAngle">Angle in degrees</param>
|
||||
/// <returns>Rotated image</returns>
|
||||
public static Image Rotate(this Image image, float rotationAngle)
|
||||
{
|
||||
Image fileImage;
|
||||
// Fixed problem that the bitmap stream is disposed... by Cloning the image
|
||||
// This also ensures the bitmap is correctly created
|
||||
var bitmap = CreateEmptyLike(image, Color.Transparent);
|
||||
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
surfaceFileStream.Position = 0;
|
||||
using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
|
||||
{
|
||||
Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
fileImage = Clone(tmpImage);
|
||||
}
|
||||
using var graphics = Graphics.FromImage(bitmap);
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
|
||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
||||
const int markerSize = 14;
|
||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
||||
using (StreamReader streamReader = new StreamReader(surfaceFileStream))
|
||||
{
|
||||
var greenshotMarker = streamReader.ReadToEnd();
|
||||
if (!greenshotMarker.StartsWith("Greenshot"))
|
||||
{
|
||||
throw new ArgumentException("Stream is not a Greenshot file!");
|
||||
}
|
||||
graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2);
|
||||
graphics.RotateTransform(rotationAngle);
|
||||
graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2);
|
||||
|
||||
Log.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
||||
const int filesizeLocation = 8 + markerSize;
|
||||
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
|
||||
using BinaryReader reader = new BinaryReader(surfaceFileStream);
|
||||
long bytesWritten = reader.ReadInt64();
|
||||
surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
|
||||
returnSurface.LoadElementsFromStream(surfaceFileStream);
|
||||
}
|
||||
graphics.DrawImage(image, new Point(0, 0));
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
returnSurface.Image = fileImage;
|
||||
Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return returnSurface;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an image from a stream, if an extension is supplied more formats are supported.
|
||||
/// Map a System.Drawing.Imaging.PixelFormat to a System.Windows.Media.PixelFormat
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension"></param>
|
||||
/// <returns>Image</returns>
|
||||
public static Image FromStream(Stream stream, string extension = null)
|
||||
/// <param name="pixelFormat">System.Drawing.Imaging.PixelFormat</param>
|
||||
/// <returns>System.Windows.Media.PixelFormat</returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static System.Windows.Media.PixelFormat Map(this PixelFormat pixelFormat) =>
|
||||
pixelFormat switch
|
||||
{
|
||||
PixelFormat.Format32bppArgb => PixelFormats.Bgra32,
|
||||
PixelFormat.Format24bppRgb => PixelFormats.Bgr24,
|
||||
PixelFormat.Format32bppRgb => PixelFormats.Bgr32,
|
||||
_ => throw new NotSupportedException($"Can't map {pixelFormat}.")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Map a System.Windows.Media.PixelFormat to a System.Drawing.Imaging.PixelFormat
|
||||
/// </summary>
|
||||
/// <param name="pixelFormat">System.Windows.Media.PixelFormat</param>
|
||||
/// <returns>System.Drawing.Imaging.PixelFormat</returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static PixelFormat Map(this System.Windows.Media.PixelFormat pixelFormat)
|
||||
{
|
||||
if (stream == null)
|
||||
if (pixelFormat == PixelFormats.Bgra32)
|
||||
{
|
||||
return null;
|
||||
return PixelFormat.Format32bppArgb;
|
||||
}
|
||||
if (pixelFormat == PixelFormats.Bgr24)
|
||||
{
|
||||
return PixelFormat.Format24bppRgb;
|
||||
}
|
||||
if (pixelFormat == PixelFormats.Bgr32)
|
||||
{
|
||||
return PixelFormat.Format32bppRgb;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
throw new NotSupportedException($"Can't map {pixelFormat}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a Bitmap to a BitmapSource
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <returns>BitmapSource</returns>
|
||||
public static BitmapSource ToBitmapSource(this Bitmap bitmap)
|
||||
{
|
||||
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
|
||||
BitmapSource bitmapSource;
|
||||
try
|
||||
{
|
||||
extension = extension.Replace(".", string.Empty);
|
||||
bitmapSource = BitmapSource.Create(
|
||||
bitmapData.Width, bitmapData.Height,
|
||||
bitmap.HorizontalResolution, bitmap.VerticalResolution,
|
||||
bitmap.PixelFormat.Map(), null,
|
||||
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
|
||||
}
|
||||
finally
|
||||
{
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
}
|
||||
|
||||
// Make sure we can try multiple times
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
stream.CopyTo(memoryStream);
|
||||
stream = memoryStream;
|
||||
}
|
||||
return bitmapSource;
|
||||
}
|
||||
|
||||
Image returnImage = null;
|
||||
if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter))
|
||||
{
|
||||
returnImage = converter(stream, extension);
|
||||
}
|
||||
/// <summary>
|
||||
/// Convert a BitmapSource to a Bitmap
|
||||
/// </summary>
|
||||
/// <param name="bitmapSource">BitmapSource</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap ToBitmap(this BitmapSource bitmapSource)
|
||||
{
|
||||
var pixelFormat = bitmapSource.Format.Map();
|
||||
|
||||
// Fallback
|
||||
if (returnImage == null)
|
||||
{
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
stream.Position = 0;
|
||||
using var tmpImage = Image.FromStream(stream, true, true);
|
||||
Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
return returnImage;
|
||||
Bitmap bitmap = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, pixelFormat);
|
||||
BitmapData data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, pixelFormat);
|
||||
bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,12 +20,11 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -33,20 +32,21 @@ using System.Text.RegularExpressions;
|
|||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Controls;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
using Encoder = System.Drawing.Imaging.Encoder;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ImageOutput.
|
||||
/// </summary>
|
||||
public static class ImageOutput
|
||||
public static class ImageIO
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageIO));
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131;
|
||||
private static readonly Cache<string, string> TmpFileCache = new Cache<string, string>(10 * 60 * 60, RemoveExpiredTmpFile);
|
||||
|
@ -54,7 +54,7 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Creates a PropertyItem (Metadata) to store with the image.
|
||||
/// For the possible ID's see: https://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx
|
||||
/// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that!
|
||||
/// This code uses Reflection to create a PropertyItem, although it's not advised it's not as stupid as having a image in the project so we can read a PropertyItem from that!
|
||||
/// </summary>
|
||||
/// <param name="id">ID</param>
|
||||
/// <param name="text">Text</param>
|
||||
|
@ -124,102 +124,21 @@ namespace Greenshot.Base.Core
|
|||
|
||||
try
|
||||
{
|
||||
var imageFormat = outputSettings.Format switch
|
||||
{
|
||||
OutputFormat.bmp => ImageFormat.Bmp,
|
||||
OutputFormat.gif => ImageFormat.Gif,
|
||||
OutputFormat.jpg => ImageFormat.Jpeg,
|
||||
OutputFormat.tiff => ImageFormat.Tiff,
|
||||
OutputFormat.ico => ImageFormat.Icon,
|
||||
_ => ImageFormat.Png
|
||||
};
|
||||
Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat);
|
||||
|
||||
// Check if we want to use a memory stream, to prevent issues with non seakable streams
|
||||
// Check if we want to use a memory stream, to prevent issues with non seekable streams
|
||||
// The save is made to the targetStream, this is directed to either the MemoryStream or the original
|
||||
Stream targetStream = stream;
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
useMemoryStream = true;
|
||||
Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
|
||||
Log.Warn("Using a memory stream prevent an issue with saving to a non seekable stream.");
|
||||
memoryStream = new MemoryStream();
|
||||
targetStream = memoryStream;
|
||||
}
|
||||
|
||||
if (Equals(imageFormat, ImageFormat.Jpeg))
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
if (!fileFormatHandlers.TrySaveToStream(imageToSave as Bitmap, targetStream, outputSettings.Format.ToString(), surface, outputSettings))
|
||||
{
|
||||
bool foundEncoder = false;
|
||||
foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders())
|
||||
{
|
||||
if (imageCodec.FormatID == imageFormat.Guid)
|
||||
{
|
||||
EncoderParameters parameters = new EncoderParameters(1)
|
||||
{
|
||||
Param =
|
||||
{
|
||||
[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality)
|
||||
}
|
||||
};
|
||||
// Removing transparency if it's not supported in the output
|
||||
if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
|
||||
{
|
||||
Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
|
||||
AddTag(nonAlphaImage);
|
||||
nonAlphaImage.Save(targetStream, imageCodec, parameters);
|
||||
nonAlphaImage.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddTag(imageToSave);
|
||||
imageToSave.Save(targetStream, imageCodec, parameters);
|
||||
}
|
||||
|
||||
foundEncoder = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundEncoder)
|
||||
{
|
||||
throw new ApplicationException("No JPG encoder found, this should not happen.");
|
||||
}
|
||||
}
|
||||
else if (Equals(imageFormat, ImageFormat.Icon))
|
||||
{
|
||||
// FEATURE-916: Added Icon support
|
||||
IList<Image> images = new List<Image>
|
||||
{
|
||||
imageToSave
|
||||
};
|
||||
WriteIcon(stream, images);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool needsDispose = false;
|
||||
// Removing transparency if it's not supported in the output
|
||||
if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
|
||||
{
|
||||
imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
|
||||
needsDispose = true;
|
||||
}
|
||||
|
||||
AddTag(imageToSave);
|
||||
// Added for OptiPNG
|
||||
bool processed = false;
|
||||
if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
processed = ProcessPngImageExternally(imageToSave, targetStream);
|
||||
}
|
||||
|
||||
if (!processed)
|
||||
{
|
||||
imageToSave.Save(targetStream, imageFormat);
|
||||
}
|
||||
|
||||
if (needsDispose)
|
||||
{
|
||||
imageToSave.Dispose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If we used a memory stream, we need to stream the memory stream to the original stream.
|
||||
|
@ -227,21 +146,6 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
memoryStream.WriteTo(stream);
|
||||
}
|
||||
|
||||
// Output the surface elements, size and marker to the stream
|
||||
if (outputSettings.Format != OutputFormat.greenshot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using MemoryStream tmpStream = new MemoryStream();
|
||||
long bytesWritten = surface.SaveElementsToStream(tmpStream);
|
||||
using BinaryWriter writer = new BinaryWriter(tmpStream);
|
||||
writer.Write(bytesWritten);
|
||||
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
|
||||
writer.Write(marker);
|
||||
tmpStream.WriteTo(stream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -249,89 +153,6 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream
|
||||
/// </summary>
|
||||
/// <param name="imageToProcess">Image to pass to the external process</param>
|
||||
/// <param name="targetStream">stream to write the processed image to</param>
|
||||
/// <returns></returns>
|
||||
private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream)
|
||||
{
|
||||
if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png");
|
||||
try
|
||||
{
|
||||
using (FileStream tmpStream = File.Create(tmpFileName))
|
||||
{
|
||||
Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName);
|
||||
imageToProcess.Save(tmpStream, ImageFormat.Png);
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand);
|
||||
}
|
||||
|
||||
ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand)
|
||||
{
|
||||
Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName),
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
using Process process = Process.Start(processStartInfo);
|
||||
if (process != null)
|
||||
{
|
||||
process.WaitForExit();
|
||||
if (process.ExitCode == 0)
|
||||
{
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length);
|
||||
Log.DebugFormat("Reading back tmp file: {0}", tmpFileName);
|
||||
}
|
||||
|
||||
byte[] processedImage = File.ReadAllBytes(tmpFileName);
|
||||
targetStream.Write(processedImage, 0, processedImage.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode);
|
||||
Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd());
|
||||
Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Error while processing PNG image: ", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(tmpFileName))
|
||||
{
|
||||
Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName);
|
||||
File.Delete(tmpFileName);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an image from a surface with the settings from the output settings applied
|
||||
/// </summary>
|
||||
|
@ -429,20 +250,18 @@ namespace Greenshot.Base.Core
|
|||
/// Add the greenshot property!
|
||||
/// </summary>
|
||||
/// <param name="imageToSave"></param>
|
||||
private static void AddTag(Image imageToSave)
|
||||
public static void AddTag(this Image imageToSave)
|
||||
{
|
||||
// Create meta-data
|
||||
PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot");
|
||||
if (softwareUsedPropertyItem != null)
|
||||
if (softwareUsedPropertyItem == null) return;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
imageToSave.SetPropertyItem(softwareUsedPropertyItem);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
|
||||
}
|
||||
imageToSave.SetPropertyItem(softwareUsedPropertyItem);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +282,7 @@ namespace Greenshot.Base.Core
|
|||
// Fixed lock problem Bug #3431881
|
||||
using (Stream surfaceFileStream = File.OpenRead(fullPath))
|
||||
{
|
||||
returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface);
|
||||
returnSurface = LoadGreenshotSurface(surfaceFileStream, returnSurface);
|
||||
}
|
||||
|
||||
if (returnSurface != null)
|
||||
|
@ -547,27 +366,25 @@ namespace Greenshot.Base.Core
|
|||
using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails))
|
||||
{
|
||||
DialogResult dialogResult = saveImageFileDialog.ShowDialog();
|
||||
if (dialogResult.Equals(DialogResult.OK))
|
||||
if (!dialogResult.Equals(DialogResult.OK)) return returnValue;
|
||||
try
|
||||
{
|
||||
try
|
||||
string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension;
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension));
|
||||
if (CoreConfig.OutputFilePromptQuality)
|
||||
{
|
||||
string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension;
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension));
|
||||
if (CoreConfig.OutputFilePromptQuality)
|
||||
{
|
||||
QualityDialog qualityDialog = new QualityDialog(outputSettings);
|
||||
qualityDialog.ShowDialog();
|
||||
}
|
||||
QualityDialog qualityDialog = new QualityDialog(outputSettings);
|
||||
qualityDialog.ShowDialog();
|
||||
}
|
||||
|
||||
// TODO: For now we always overwrite, should be changed
|
||||
Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
returnValue = fileNameWithExtension;
|
||||
IniConfig.Save();
|
||||
}
|
||||
catch (ExternalException)
|
||||
{
|
||||
MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error"));
|
||||
}
|
||||
// TODO: For now we always overwrite, should be changed
|
||||
Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
returnValue = fileNameWithExtension;
|
||||
IniConfig.Save();
|
||||
}
|
||||
catch (ExternalException)
|
||||
{
|
||||
MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,91 +526,218 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the images to the stream as icon
|
||||
/// Every image is resized to 256x256 (but the content maintains the aspect ratio)
|
||||
/// Load an image from file
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to write to</param>
|
||||
/// <param name="images">List of images</param>
|
||||
public static void WriteIcon(Stream stream, IList<Image> images)
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public static Image LoadImage(string filename)
|
||||
{
|
||||
var binaryWriter = new BinaryWriter(stream);
|
||||
//
|
||||
// ICONDIR structure
|
||||
//
|
||||
binaryWriter.Write((short) 0); // reserved
|
||||
binaryWriter.Write((short) 1); // image type (icon)
|
||||
binaryWriter.Write((short) images.Count); // number of images
|
||||
|
||||
IList<Size> imageSizes = new List<Size>();
|
||||
IList<MemoryStream> encodedImages = new List<MemoryStream>();
|
||||
foreach (var image in images)
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
// Pick the best fit
|
||||
var sizes = new[]
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Image fileImage;
|
||||
Log.InfoFormat("Loading image from file {0}", filename);
|
||||
// Fixed lock problem Bug #3431881
|
||||
using (Stream imageFileStream = File.OpenRead(filename))
|
||||
{
|
||||
fileImage = FromStream(imageFileStream, Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return fileImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx
|
||||
/// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx
|
||||
/// </summary>
|
||||
/// <param name="iconStream">Stream with the icon information</param>
|
||||
/// <returns>Bitmap with the Vista Icon (256x256)</returns>
|
||||
private static Bitmap ExtractVistaIcon(Stream iconStream)
|
||||
{
|
||||
const int sizeIconDir = 6;
|
||||
const int sizeIconDirEntry = 16;
|
||||
Bitmap bmpPngExtracted = null;
|
||||
try
|
||||
{
|
||||
byte[] srcBuf = new byte[iconStream.Length];
|
||||
iconStream.Read(srcBuf, 0, (int)iconStream.Length);
|
||||
int iCount = BitConverter.ToInt16(srcBuf, 4);
|
||||
for (int iIndex = 0; iIndex < iCount; iIndex++)
|
||||
{
|
||||
16, 32, 48
|
||||
};
|
||||
int size = 256;
|
||||
foreach (var possibleSize in sizes)
|
||||
{
|
||||
if (image.Width <= possibleSize && image.Height <= possibleSize)
|
||||
int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
|
||||
int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
|
||||
if (iWidth == 0 && iHeight == 0)
|
||||
{
|
||||
size = possibleSize;
|
||||
int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
|
||||
int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
|
||||
using MemoryStream destStream = new MemoryStream();
|
||||
destStream.Write(srcBuf, iImageOffset, iImageSize);
|
||||
destStream.Seek(0, SeekOrigin.Begin);
|
||||
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var imageStream = new MemoryStream();
|
||||
if (image.Width == size && image.Height == size)
|
||||
return bmpPngExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx
|
||||
/// </summary>
|
||||
/// <param name="location">The file (EXE or DLL) to get the icon from</param>
|
||||
/// <param name="index">Index of the icon</param>
|
||||
/// <param name="takeLarge">true if the large icon is wanted</param>
|
||||
/// <returns>Icon</returns>
|
||||
public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge)
|
||||
{
|
||||
Shell32.ExtractIconEx(location, index, out var large, out var small, 1);
|
||||
Icon returnIcon = null;
|
||||
bool isLarge = false;
|
||||
bool isSmall = false;
|
||||
try
|
||||
{
|
||||
if (takeLarge && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
clonedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(new Size(size, size));
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
else
|
||||
else if (!IntPtr.Zero.Equals(small))
|
||||
{
|
||||
// Resize to the specified size, first make sure the image is 32bpp
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null);
|
||||
resizedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(resizedImage.Size);
|
||||
returnIcon = Icon.FromHandle(small);
|
||||
isSmall = true;
|
||||
}
|
||||
else if (!IntPtr.Zero.Equals(large))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isLarge && !IntPtr.Zero.Equals(small))
|
||||
{
|
||||
User32.DestroyIcon(small);
|
||||
}
|
||||
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
encodedImages.Add(imageStream);
|
||||
if (isSmall && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
User32.DestroyIcon(large);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ICONDIRENTRY structure
|
||||
//
|
||||
const int iconDirSize = 6;
|
||||
const int iconDirEntrySize = 16;
|
||||
return returnIcon;
|
||||
}
|
||||
|
||||
var offset = iconDirSize + (images.Count * iconDirEntrySize);
|
||||
for (int i = 0; i < images.Count; i++)
|
||||
/// <summary>
|
||||
/// Create an image from a stream, if an extension is supplied more formats are supported.
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension"></param>
|
||||
/// <returns>Image</returns>
|
||||
public static Image FromStream(Stream stream, string extension = null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
var imageSize = imageSizes[i];
|
||||
// Write the width / height, 0 means 256
|
||||
binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width);
|
||||
binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height);
|
||||
binaryWriter.Write((byte) 0); // no pallete
|
||||
binaryWriter.Write((byte) 0); // reserved
|
||||
binaryWriter.Write((short) 0); // no color planes
|
||||
binaryWriter.Write((short) 32); // 32 bpp
|
||||
binaryWriter.Write((int) encodedImages[i].Length); // image data length
|
||||
binaryWriter.Write(offset);
|
||||
offset += (int) encodedImages[i].Length;
|
||||
return null;
|
||||
}
|
||||
|
||||
binaryWriter.Flush();
|
||||
//
|
||||
// Write image data
|
||||
//
|
||||
foreach (var encodedImage in encodedImages)
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
encodedImage.WriteTo(stream);
|
||||
encodedImage.Dispose();
|
||||
extension = extension.Replace(".", string.Empty);
|
||||
}
|
||||
|
||||
var startingPosition = stream.Position;
|
||||
|
||||
// Make sure we can try multiple times
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
stream.CopyTo(memoryStream);
|
||||
stream = memoryStream;
|
||||
// As we are if a different stream, which starts at 0, change the starting position
|
||||
startingPosition = 0;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
foreach (var fileFormatHandler in fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)))
|
||||
{
|
||||
stream.Seek(startingPosition, SeekOrigin.Begin);
|
||||
if (fileFormatHandler.TryLoadFromStream(stream, extension, out var bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a Greenshot surface from a stream
|
||||
/// </summary>
|
||||
/// <param name="surfaceFileStream">Stream</param>
|
||||
/// <param name="returnSurface"></param>
|
||||
/// <returns>ISurface</returns>
|
||||
public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface)
|
||||
{
|
||||
Image fileImage;
|
||||
// Fixed problem that the bitmap stream is disposed... by Cloning the image
|
||||
// This also ensures the bitmap is correctly created
|
||||
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
surfaceFileStream.Position = 0;
|
||||
using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
|
||||
{
|
||||
Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
fileImage = ImageHelper.Clone(tmpImage);
|
||||
}
|
||||
|
||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
||||
const int markerSize = 14;
|
||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
||||
using (StreamReader streamReader = new StreamReader(surfaceFileStream))
|
||||
{
|
||||
var greenshotMarker = streamReader.ReadToEnd();
|
||||
if (!greenshotMarker.StartsWith("Greenshot"))
|
||||
{
|
||||
throw new ArgumentException("Stream is not a Greenshot file!");
|
||||
}
|
||||
|
||||
Log.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
||||
const int filesizeLocation = 8 + markerSize;
|
||||
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
|
||||
using BinaryReader reader = new BinaryReader(surfaceFileStream);
|
||||
long bytesWritten = reader.ReadInt64();
|
||||
surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
|
||||
returnSurface.LoadElementsFromStream(surfaceFileStream);
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
returnSurface.Image = fileImage;
|
||||
Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return returnSurface;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrap an image, make it resizeable
|
||||
/// </summary>
|
||||
public class ImageWrapper : IImage
|
||||
{
|
||||
// Underlying image, is used to generate a resized version of it when needed
|
||||
private readonly Image _image;
|
||||
private Image _imageClone;
|
||||
|
||||
public ImageWrapper(Image image)
|
||||
{
|
||||
// Make sure the orientation is set correctly so Greenshot can process the image correctly
|
||||
ImageHelper.Orientate(image);
|
||||
_image = image;
|
||||
Width = _image.Width;
|
||||
Height = _image.Height;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_image.Dispose();
|
||||
_imageClone?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of the image, can be set to change
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the image, can be set to change.
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the image
|
||||
/// </summary>
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Pixelformat of the underlying image
|
||||
/// </summary>
|
||||
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||
|
||||
public float HorizontalResolution => Image.HorizontalResolution;
|
||||
public float VerticalResolution => Image.VerticalResolution;
|
||||
|
||||
public Image Image
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imageClone == null)
|
||||
{
|
||||
if (_image.Height == Height && _image.Width == Width)
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
}
|
||||
|
||||
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||
{
|
||||
return _imageClone;
|
||||
}
|
||||
|
||||
// Calculate new image clone
|
||||
_imageClone?.Dispose();
|
||||
_imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null);
|
||||
return _imageClone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,11 +24,14 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
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;
|
||||
|
||||
|
@ -87,24 +90,14 @@ 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();
|
||||
foreach (var extension in ImageHelper.StreamConverters.Keys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
extensions.AppendFormat(@"\.{0}|", extension);
|
||||
}
|
||||
|
||||
extensions.Length--;
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
|
||||
|
||||
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||
var match = imageUrlRegex.Match(url);
|
||||
|
@ -113,7 +106,12 @@ namespace Greenshot.Base.Core
|
|||
using var memoryStream = GetAsMemoryStream(url);
|
||||
try
|
||||
{
|
||||
return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null);
|
||||
var extension = match.Success ? match.Groups["extension"]?.Value : null;
|
||||
var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream, extension).FirstOrDefault();
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -136,7 +134,71 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
using var memoryStream2 = GetAsMemoryStream(match.Value);
|
||||
return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value);
|
||||
|
||||
var extension = match.Success ? match.Groups["extension"]?.Value : null;
|
||||
var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream2, extension).FirstOrDefault();
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Problem downloading the image from: " + url, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download the uri to create a Bitmap
|
||||
/// </summary>
|
||||
/// <param name="url">Of an image</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap DownloadImage(string url)
|
||||
{
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
|
||||
|
||||
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||
var match = imageUrlRegex.Match(url);
|
||||
try
|
||||
{
|
||||
using var memoryStream = GetAsMemoryStream(url);
|
||||
try
|
||||
{
|
||||
if (fileFormatHandlers.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
|
||||
string content;
|
||||
using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
|
||||
{
|
||||
content = streamReader.ReadLine();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
match = imageUrlRegex.Match(content);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
using var memoryStream2 = GetAsMemoryStream(match.Value);
|
||||
if (fileFormatHandlers.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -670,7 +732,7 @@ namespace Greenshot.Base.Core
|
|||
public string ToBase64String(Base64FormattingOptions formattingOptions)
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
ImageOutput.SaveToStream(_surface, stream, _outputSettings);
|
||||
ImageIO.SaveToStream(_surface, stream, _outputSettings);
|
||||
return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions);
|
||||
}
|
||||
|
||||
|
@ -682,7 +744,7 @@ namespace Greenshot.Base.Core
|
|||
public byte[] ToByteArray()
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
ImageOutput.SaveToStream(_surface, stream, _outputSettings);
|
||||
ImageIO.SaveToStream(_surface, stream, _outputSettings);
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
|
@ -698,7 +760,7 @@ namespace Greenshot.Base.Core
|
|||
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n";
|
||||
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
|
||||
ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings);
|
||||
ImageIO.SaveToStream(_surface, formDataStream, _outputSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -708,7 +770,7 @@ namespace Greenshot.Base.Core
|
|||
public void WriteToStream(Stream dataStream)
|
||||
{
|
||||
// Write the file data directly to the Stream, rather than serializing it to a string.
|
||||
ImageOutput.SaveToStream(_surface, dataStream, _outputSettings);
|
||||
ImageIO.SaveToStream(_surface, dataStream, _outputSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
try
|
||||
{
|
||||
using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons))
|
||||
using (Icon appIcon = ImageIO.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons))
|
||||
{
|
||||
if (appIcon != null)
|
||||
{
|
||||
|
|
|
@ -10,22 +10,19 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public class SimpleServiceProvider : IServiceLocator
|
||||
{
|
||||
private readonly Dictionary<Type, List<object>> _services = new Dictionary<Type, List<object>>();
|
||||
private readonly Dictionary<Type, IList<object>> _services = new();
|
||||
|
||||
public static IServiceLocator Current { get; } = new SimpleServiceProvider();
|
||||
|
||||
public IEnumerable<TService> GetAllInstances<TService>()
|
||||
public IReadOnlyList<TService> GetAllInstances<TService>()
|
||||
{
|
||||
var typeOfService = typeof(TService);
|
||||
if (!_services.TryGetValue(typeOfService, out var results))
|
||||
{
|
||||
yield break;
|
||||
return Array.Empty<TService>();
|
||||
}
|
||||
|
||||
foreach (TService result in results)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
return results.Cast<TService>().ToArray();
|
||||
}
|
||||
|
||||
public TService GetInstance<TService>()
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* 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.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using Svg;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an image look like of the SVG
|
||||
/// </summary>
|
||||
public sealed class SvgImage : IImage
|
||||
{
|
||||
private readonly SvgDocument _svgDocument;
|
||||
|
||||
private Image _imageClone;
|
||||
|
||||
/// <summary>
|
||||
/// Factory to create via a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <returns>IImage</returns>
|
||||
public static IImage FromStream(Stream stream)
|
||||
{
|
||||
return new SvgImage(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public SvgImage(Stream stream)
|
||||
{
|
||||
_svgDocument = SvgDocument.Open<SvgDocument>(stream);
|
||||
Height = (int) _svgDocument.ViewBox.Height;
|
||||
Width = (int) _svgDocument.ViewBox.Width;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of the image, can be set to change
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the image, can be set to change.
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the image
|
||||
/// </summary>
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Pixelformat of the underlying image
|
||||
/// </summary>
|
||||
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal resolution of the underlying image
|
||||
/// </summary>
|
||||
public float HorizontalResolution => Image.HorizontalResolution;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical resolution of the underlying image
|
||||
/// </summary>
|
||||
public float VerticalResolution => Image.VerticalResolution;
|
||||
|
||||
/// <summary>
|
||||
/// Underlying image, or an on demand rendered version with different attributes as the original
|
||||
/// </summary>
|
||||
public Image Image
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||
{
|
||||
return _imageClone;
|
||||
}
|
||||
|
||||
// Calculate new image clone
|
||||
_imageClone?.Dispose();
|
||||
_imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96);
|
||||
_svgDocument.Draw((Bitmap) _imageClone);
|
||||
return _imageClone;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_imageClone?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -782,7 +782,9 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public WindowStyleFlags WindowStyle
|
||||
{
|
||||
get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE);
|
||||
get => unchecked(
|
||||
(WindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE).ToInt64()
|
||||
);
|
||||
set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value));
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
33
src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs
Normal file
33
src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Drawing
|
||||
{
|
||||
public interface IFieldAggregator
|
||||
{
|
||||
void UnbindElement(IDrawableContainer dc);
|
||||
void BindElements(IDrawableContainerList dcs);
|
||||
void BindElement(IDrawableContainer dc);
|
||||
IField GetField(IFieldType fieldType);
|
||||
|
||||
event FieldChangedEventHandler FieldChanged;
|
||||
}
|
||||
}
|
88
src/Greenshot.Base/Interfaces/IFileFormatHandler.cs
Normal file
88
src/Greenshot.Base/Interfaces/IFileFormatHandler.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.IO;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The possible actions a IFileFormatHandler might support
|
||||
/// </summary>
|
||||
public enum FileFormatHandlerActions
|
||||
{
|
||||
SaveToStream,
|
||||
LoadFromStream,
|
||||
LoadDrawableFromStream
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface is for code to implement the loading and saving of certain file formats
|
||||
/// </summary>
|
||||
public interface IFileFormatHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Registry for all the extensions this IFileFormatHandler support
|
||||
/// </summary>
|
||||
IDictionary<FileFormatHandlerActions, IReadOnlyCollection<string>> SupportedExtensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Priority (from high int.MinValue, low int.MaxValue) of this IFileFormatHandler for the specified action and extension
|
||||
/// This should be used to sort the possible IFileFormatHandler
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlerAction">FileFormatHandlerActions</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>int specifying the priority for the action and extension</returns>
|
||||
public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension);
|
||||
|
||||
/// <summary>
|
||||
/// Try to save the specified bitmap to the stream in the format belonging to the extension
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <param name="destination">Stream</param>
|
||||
/// <param name="extension">extension</param>
|
||||
/// <param name="surface">ISurface with the elements for those file types which can store a surface (.greenshot)</param>
|
||||
/// <param name="surfaceOutputSettings">SurfaceOutputSettings</param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="extension"></param>
|
||||
/// <param name="bitmap"></param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap);
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a drawable container from the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="parentSurface">ISurface</param>
|
||||
/// <returns>IEnumerable{IDrawableContainer}</returns>
|
||||
public IEnumerable<IDrawableContainer> LoadDrawablesFromStream(Stream stream, string extension, ISurface parentSurface = null);
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace Greenshot.Base.Interfaces
|
|||
/// </summary>
|
||||
/// <typeparam name="TService">Service to find</typeparam>
|
||||
/// <returns>IEnumerable{TService}</returns>
|
||||
IEnumerable<TService> GetAllInstances<TService>();
|
||||
IReadOnlyList<TService> GetAllInstances<TService>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the only instance of the specified service
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Core;
|
||||
|
@ -201,5 +202,14 @@ namespace Greenshot.Base.Interfaces
|
|||
Rectangle ToImageCoordinates(Rectangle rc);
|
||||
|
||||
void MakeUndoable(IMemento memento, bool allowMerge);
|
||||
|
||||
IFieldAggregator FieldAggregator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This reverses a change of the background image
|
||||
/// </summary>
|
||||
/// <param name="previous">Image</param>
|
||||
/// <param name="matrix">Matrix</param>
|
||||
void UndoBackgroundChange(Image previous, Matrix matrix);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
/*
|
||||
* 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 Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Effects;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums
|
|||
public enum WindowStyleFlags : int
|
||||
{
|
||||
//WS_OVERLAPPED = 0x00000000,
|
||||
WS_POPUP = -2147483648,
|
||||
WS_POPUP = -2147483648, // 0x80000000
|
||||
WS_CHILD = 0x40000000,
|
||||
WS_MINIMIZE = 0x20000000,
|
||||
WS_VISIBLE = 0x10000000,
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace Greenshot.Base.UnmanagedHelpers
|
|||
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")]
|
||||
public static extern int GetWindowLong(IntPtr hWnd, int index);
|
||||
public static extern IntPtr GetWindowLong(IntPtr hWnd, int index);
|
||||
|
||||
[DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")]
|
||||
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
|
||||
|
@ -276,16 +276,14 @@ namespace Greenshot.Base.UnmanagedHelpers
|
|||
/// <param name="hWnd"></param>
|
||||
/// <param name="nIndex"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex)
|
||||
public static IntPtr GetWindowLongWrapper(IntPtr hWnd, int nIndex)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
{
|
||||
return GetWindowLongPtr(hWnd, nIndex).ToInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetWindowLong(hWnd, nIndex);
|
||||
return GetWindowLongPtr(hWnd, nIndex);
|
||||
}
|
||||
|
||||
return GetWindowLong(hWnd, nIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
|
||||
|
@ -43,7 +44,7 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6);
|
||||
|
||||
public ArrowContainer(Surface parent) : base(parent)
|
||||
public ArrowContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
using System.Drawing;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -32,7 +33,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
public class CropContainer : DrawableContainer
|
||||
{
|
||||
public CropContainer(Surface parent) : base(parent)
|
||||
public CropContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ using System.Drawing.Drawing2D;
|
|||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using log4net;
|
||||
|
||||
|
@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
protected Cursor cursor;
|
||||
|
||||
public CursorContainer(Surface parent) : base(parent)
|
||||
public CursorContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ namespace Greenshot.Editor.Drawing
|
|||
CreateDefaultAdorners();
|
||||
}
|
||||
|
||||
public CursorContainer(Surface parent, string filename) : this(parent)
|
||||
public CursorContainer(ISurface parent, string filename) : this(parent)
|
||||
{
|
||||
Load(filename);
|
||||
}
|
||||
|
|
|
@ -126,12 +126,17 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
}
|
||||
|
||||
[NonSerialized] internal Surface _parent;
|
||||
[NonSerialized] internal ISurface _parent;
|
||||
|
||||
public ISurface Parent
|
||||
{
|
||||
get => _parent;
|
||||
set => SwitchParent((Surface) value);
|
||||
set => SwitchParent(value);
|
||||
}
|
||||
|
||||
protected Surface InternalParent
|
||||
{
|
||||
get => (Surface)_parent;
|
||||
}
|
||||
|
||||
[NonSerialized] private TargetAdorner _targetAdorner;
|
||||
|
@ -277,7 +282,7 @@ namespace Greenshot.Editor.Drawing
|
|||
Height = Round(newBounds.Height);
|
||||
}
|
||||
|
||||
public DrawableContainer(Surface parent)
|
||||
public DrawableContainer(ISurface parent)
|
||||
{
|
||||
InitializeFields();
|
||||
_parent = parent;
|
||||
|
@ -505,7 +510,7 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
Invalidate();
|
||||
|
||||
// reset "workrbench" rectangle to current bounds
|
||||
// reset "workbench" rectangle to current bounds
|
||||
_boundsAfterResize.X = _boundsBeforeResize.Left;
|
||||
_boundsAfterResize.Y = _boundsBeforeResize.Top;
|
||||
_boundsAfterResize.Width = x - _boundsAfterResize.Left;
|
||||
|
@ -529,7 +534,7 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
}
|
||||
|
||||
protected virtual void SwitchParent(Surface newParent)
|
||||
protected virtual void SwitchParent(ISurface newParent)
|
||||
{
|
||||
if (newParent == Parent)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ using System;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing
|
|||
[Serializable()]
|
||||
public class EllipseContainer : DrawableContainer
|
||||
{
|
||||
public EllipseContainer(Surface parent) : base(parent)
|
||||
public EllipseContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace Greenshot.Editor.Drawing.Fields
|
|||
/// If the property values of the selected elements differ, the value of the last bound element wins.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class FieldAggregator : AbstractFieldHolder
|
||||
public sealed class FieldAggregator : AbstractFieldHolder, IFieldAggregator
|
||||
{
|
||||
private readonly IDrawableContainerList _boundContainers;
|
||||
private bool _internalUpdateRunning;
|
||||
|
@ -117,11 +117,10 @@ namespace Greenshot.Editor.Drawing.Fields
|
|||
|
||||
public void UnbindElement(IDrawableContainer dc)
|
||||
{
|
||||
if (_boundContainers.Contains(dc))
|
||||
{
|
||||
_boundContainers.Remove(dc);
|
||||
UpdateFromBoundElements();
|
||||
}
|
||||
if (!_boundContainers.Contains(dc)) return;
|
||||
|
||||
_boundContainers.Remove(dc);
|
||||
UpdateFromBoundElements();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
|
|
@ -23,6 +23,7 @@ using System;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -51,7 +52,7 @@ namespace Greenshot.Editor.Drawing
|
|||
MAGNIFICATION
|
||||
};
|
||||
|
||||
public FilterContainer(Surface parent) : base(parent)
|
||||
public FilterContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -50,7 +51,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public FreehandContainer(Surface parent) : base(parent)
|
||||
public FreehandContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Width = parent.Image.Width;
|
||||
Height = parent.Image.Height;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Drawing.Filters;
|
||||
|
@ -33,7 +34,7 @@ namespace Greenshot.Editor.Drawing
|
|||
[Serializable]
|
||||
public class HighlightContainer : FilterContainer
|
||||
{
|
||||
public HighlightContainer(Surface parent) : base(parent)
|
||||
public HighlightContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Drawing;
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using log4net;
|
||||
|
||||
|
@ -39,7 +40,7 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
protected Icon icon;
|
||||
|
||||
public IconContainer(Surface parent) : base(parent)
|
||||
public IconContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
@ -55,11 +56,16 @@ namespace Greenshot.Editor.Drawing
|
|||
CreateDefaultAdorners();
|
||||
}
|
||||
|
||||
public IconContainer(Surface parent, string filename) : base(parent)
|
||||
public IconContainer(ISurface parent, string filename) : base(parent)
|
||||
{
|
||||
Load(filename);
|
||||
}
|
||||
|
||||
public IconContainer(ISurface parent, Stream stream) : base(parent)
|
||||
{
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
public Icon Icon
|
||||
{
|
||||
set
|
||||
|
@ -99,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)
|
||||
|
|
|
@ -26,6 +26,7 @@ using System.IO;
|
|||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Effects;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using log4net;
|
||||
|
@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer));
|
||||
|
||||
private Image image;
|
||||
private Image _image;
|
||||
|
||||
/// <summary>
|
||||
/// This is the shadow version of the bitmap, rendered once to save performance
|
||||
|
@ -54,12 +55,12 @@ namespace Greenshot.Editor.Drawing
|
|||
/// </summary>
|
||||
[NonSerialized] private Point _shadowOffset = new Point(-1, -1);
|
||||
|
||||
public ImageContainer(Surface parent, string filename) : this(parent)
|
||||
public ImageContainer(ISurface parent, string filename) : this(parent)
|
||||
{
|
||||
Load(filename);
|
||||
}
|
||||
|
||||
public ImageContainer(Surface parent) : base(parent)
|
||||
public ImageContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
FieldChanged += BitmapContainer_OnFieldChanged;
|
||||
Init();
|
||||
|
@ -107,8 +108,8 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
else
|
||||
{
|
||||
Width = image.Width;
|
||||
Height = image.Height;
|
||||
Width = _image.Width;
|
||||
Height = _image.Height;
|
||||
if (_shadowBitmap != null)
|
||||
{
|
||||
Left += _shadowOffset.X;
|
||||
|
@ -124,13 +125,13 @@ namespace Greenshot.Editor.Drawing
|
|||
// Remove all current bitmaps
|
||||
DisposeImage();
|
||||
DisposeShadow();
|
||||
image = ImageHelper.Clone(value);
|
||||
_image = ImageHelper.Clone(value);
|
||||
bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
|
||||
CheckShadow(shadow);
|
||||
if (!shadow)
|
||||
{
|
||||
Width = image.Width;
|
||||
Height = image.Height;
|
||||
Width = _image.Width;
|
||||
Height = _image.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -140,7 +141,7 @@ namespace Greenshot.Editor.Drawing
|
|||
Top -= _shadowOffset.Y;
|
||||
}
|
||||
}
|
||||
get { return image; }
|
||||
get { return _image; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -162,8 +163,8 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
private void DisposeImage()
|
||||
{
|
||||
image?.Dispose();
|
||||
image = null;
|
||||
_image?.Dispose();
|
||||
_image = null;
|
||||
}
|
||||
|
||||
private void DisposeShadow()
|
||||
|
@ -186,9 +187,9 @@ namespace Greenshot.Editor.Drawing
|
|||
Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
|
||||
DisposeShadow();
|
||||
using var tmpMatrix = new Matrix();
|
||||
using (image)
|
||||
using (_image)
|
||||
{
|
||||
image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix);
|
||||
_image = ImageHelper.ApplyEffect(_image, new RotateEffect(rotateAngle), tmpMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,7 +209,8 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
// Always make sure ImageHelper.LoadBitmap results are disposed some time,
|
||||
// as we close the bitmap internally, we need to do it afterwards
|
||||
using (var tmpImage = ImageHelper.LoadImage(filename))
|
||||
// TODO: Replace with some other code, like the file format handler, or move it completely outside of this class
|
||||
using (var tmpImage = ImageIO.LoadImage(filename))
|
||||
{
|
||||
Image = tmpImage;
|
||||
}
|
||||
|
@ -228,7 +230,7 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
|
||||
using var matrix = new Matrix();
|
||||
_shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix);
|
||||
_shadowBitmap = ImageHelper.ApplyEffect(_image, new DropShadowEffect(), matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -238,7 +240,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <param name="rm"></param>
|
||||
public override void Draw(Graphics graphics, RenderMode rm)
|
||||
{
|
||||
if (image == null)
|
||||
if (_image == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -256,12 +258,12 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
else
|
||||
{
|
||||
graphics.DrawImage(image, Bounds);
|
||||
graphics.DrawImage(_image, Bounds);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasDefaultSize => true;
|
||||
|
||||
public override Size DefaultSize => image?.Size ?? new Size(32, 32);
|
||||
public override Size DefaultSize => _image?.Size ?? new Size(32, 32);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ using System;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Adorners;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
|
@ -36,7 +37,7 @@ namespace Greenshot.Editor.Drawing
|
|||
[Serializable()]
|
||||
public class LineContainer : DrawableContainer
|
||||
{
|
||||
public LineContainer(Surface parent) : base(parent)
|
||||
public LineContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
81
src/Greenshot.Editor/Drawing/MetafileContainer.cs
Normal file
81
src/Greenshot.Editor/Drawing/MetafileContainer.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_metafile?.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public override bool HasDefaultSize => true;
|
||||
|
||||
public override Size DefaultSize => new Size(_metafile.Width, _metafile.Height);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Drawing.Filters;
|
||||
|
@ -28,12 +29,12 @@ using Greenshot.Editor.Drawing.Filters;
|
|||
namespace Greenshot.Editor.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ObfuscateContainer.
|
||||
/// This is a FilterContainer for the obfuscator filters like blur and pixelate.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ObfuscateContainer : FilterContainer
|
||||
{
|
||||
public ObfuscateContainer(Surface parent) : base(parent)
|
||||
public ObfuscateContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ using System;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing
|
|||
[Serializable]
|
||||
public class RectangleContainer : DrawableContainer
|
||||
{
|
||||
public RectangleContainer(Surface parent) : base(parent)
|
||||
public RectangleContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Drawing;
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -64,8 +65,7 @@ namespace Greenshot.Editor.Drawing
|
|||
InitAdorner(Color.Green, _storedTargetGripperLocation);
|
||||
}
|
||||
|
||||
public SpeechbubbleContainer(Surface parent)
|
||||
: base(parent)
|
||||
public SpeechbubbleContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ using System.Drawing;
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -41,9 +42,9 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
private readonly bool _drawAsRectangle = false;
|
||||
|
||||
public StepLabelContainer(Surface parent) : base(parent)
|
||||
public StepLabelContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
parent.AddStepLabel(this);
|
||||
InternalParent?.AddStepLabel(this);
|
||||
InitContent();
|
||||
Init();
|
||||
}
|
||||
|
@ -72,11 +73,10 @@ namespace Greenshot.Editor.Drawing
|
|||
[OnSerializing]
|
||||
private void SetValuesOnSerializing(StreamingContext context)
|
||||
{
|
||||
if (Parent != null)
|
||||
{
|
||||
Number = ((Surface) Parent).CountStepLabels(this);
|
||||
_counterStart = ((Surface) Parent).CounterStart;
|
||||
}
|
||||
if (InternalParent == null) return;
|
||||
|
||||
Number = InternalParent.CountStepLabels(this);
|
||||
_counterStart = InternalParent.CounterStart;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -97,23 +97,23 @@ namespace Greenshot.Editor.Drawing
|
|||
/// Add the StepLabel to the parent
|
||||
/// </summary>
|
||||
/// <param name="newParent"></param>
|
||||
protected override void SwitchParent(Surface newParent)
|
||||
protected override void SwitchParent(ISurface newParent)
|
||||
{
|
||||
if (newParent == Parent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
((Surface) Parent)?.RemoveStepLabel(this);
|
||||
base.SwitchParent(newParent);
|
||||
if (newParent == null)
|
||||
if (newParent is not Surface newParentSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
InternalParent?.RemoveStepLabel(this);
|
||||
base.SwitchParent(newParent);
|
||||
|
||||
// Make sure the counter start is restored (this unfortunately happens multiple times... -> hack)
|
||||
newParent.CounterStart = _counterStart;
|
||||
newParent.AddStepLabel(this);
|
||||
newParentSurface.CounterStart = _counterStart;
|
||||
newParentSurface.AddStepLabel(this);
|
||||
}
|
||||
|
||||
public override Size DefaultSize => new Size(30, 30);
|
||||
|
@ -204,7 +204,7 @@ namespace Greenshot.Editor.Drawing
|
|||
EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
|
||||
}
|
||||
|
||||
float fontSize = Math.Min(Width, Height) / 1.4f;
|
||||
float fontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)) / 1.4f;
|
||||
using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name);
|
||||
using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
|
||||
TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -294,7 +293,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <summary>
|
||||
/// all elements on the surface, needed with serialization
|
||||
/// </summary>
|
||||
private FieldAggregator _fieldAggregator;
|
||||
private IFieldAggregator _fieldAggregator;
|
||||
|
||||
/// <summary>
|
||||
/// the cursor container, needed with serialization as we need a direct acces to it.
|
||||
|
@ -355,7 +354,7 @@ namespace Greenshot.Editor.Drawing
|
|||
/// The field aggregator is that which is used to have access to all the fields inside the currently selected elements.
|
||||
/// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
|
||||
/// </summary>
|
||||
public FieldAggregator FieldAggregator
|
||||
public IFieldAggregator FieldAggregator
|
||||
{
|
||||
get => _fieldAggregator;
|
||||
set => _fieldAggregator = value;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -913,6 +910,27 @@ namespace Greenshot.Editor.Drawing
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will help to fit the container to the surface
|
||||
/// </summary>
|
||||
/// <param name="drawableContainer">IDrawableContainer</param>
|
||||
private void FitContainer(IDrawableContainer drawableContainer)
|
||||
{
|
||||
double factor = 1;
|
||||
if (drawableContainer.Width > this.Width)
|
||||
{
|
||||
factor = drawableContainer.Width / (double)Width;
|
||||
}
|
||||
if (drawableContainer.Height > this.Height)
|
||||
{
|
||||
var otherFactor = drawableContainer.Height / (double)Height;
|
||||
factor = Math.Max(factor, otherFactor);
|
||||
}
|
||||
|
||||
drawableContainer.Width = (int)(drawableContainer.Width / factor);
|
||||
drawableContainer.Height = (int)(drawableContainer.Height / factor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the drag/drop
|
||||
/// </summary>
|
||||
|
@ -927,20 +945,25 @@ 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;
|
||||
FitContainer(drawableContainer);
|
||||
AddElement(drawableContainer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Image image in ClipboardHelper.GetImages(e.Data))
|
||||
foreach (var drawableContainer in ClipboardHelper.GetDrawables(e.Data))
|
||||
{
|
||||
AddImageContainer(image, mouse.X, mouse.Y);
|
||||
drawableContainer.Left = mouse.X;
|
||||
drawableContainer.Top = mouse.Y;
|
||||
FitContainer(drawableContainer);
|
||||
AddElement(drawableContainer);
|
||||
mouse.Offset(10, 10);
|
||||
image.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,13 +1010,11 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
//create a blank bitmap the same size as original
|
||||
Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty);
|
||||
if (newBitmap != null)
|
||||
{
|
||||
// Make undoable
|
||||
MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
|
||||
SetImage(newBitmap, false);
|
||||
Invalidate();
|
||||
}
|
||||
if (newBitmap == null) return;
|
||||
// Make undoable
|
||||
MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
|
||||
SetImage(newBitmap, false);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2057,17 +2078,16 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
|
||||
|
||||
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard))
|
||||
foreach (var drawableContainer in ClipboardHelper.GetDrawables(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;
|
||||
AddElement(drawableContainer);
|
||||
SelectElement(drawableContainer);
|
||||
pasteLocation.X += 10;
|
||||
pasteLocation.Y += 10;
|
||||
}
|
||||
}
|
||||
else if (ClipboardHelper.ContainsText(clipboard))
|
||||
|
@ -2208,24 +2228,23 @@ namespace Greenshot.Editor.Drawing
|
|||
/// <param name="generateEvents">false to skip event generation</param>
|
||||
public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true)
|
||||
{
|
||||
if (!selectedElements.Contains(container))
|
||||
{
|
||||
selectedElements.Add(container);
|
||||
container.Selected = true;
|
||||
FieldAggregator.BindElement(container);
|
||||
if (generateEvents && _movingElementChanged != null)
|
||||
{
|
||||
SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
|
||||
{
|
||||
Elements = selectedElements
|
||||
};
|
||||
_movingElementChanged(this, eventArgs);
|
||||
}
|
||||
if (selectedElements.Contains(container)) return;
|
||||
|
||||
if (invalidate)
|
||||
selectedElements.Add(container);
|
||||
container.Selected = true;
|
||||
FieldAggregator.BindElement(container);
|
||||
if (generateEvents && _movingElementChanged != null)
|
||||
{
|
||||
SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs
|
||||
{
|
||||
container.Invalidate();
|
||||
}
|
||||
Elements = selectedElements
|
||||
};
|
||||
_movingElementChanged(this, eventArgs);
|
||||
}
|
||||
|
||||
if (invalidate)
|
||||
{
|
||||
container.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
61
src/Greenshot.Editor/Drawing/SvgContainer.cs
Normal file
61
src/Greenshot.Editor/Drawing/SvgContainer.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 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 SvgContainer : VectorGraphicsContainer
|
||||
{
|
||||
private SvgDocument _svgDocument;
|
||||
|
||||
public SvgContainer(SvgDocument svgDocument, ISurface parent) : base(parent)
|
||||
{
|
||||
_svgDocument = svgDocument;
|
||||
Size = new Size((int)svgDocument.Width, (int)svgDocument.Height);
|
||||
}
|
||||
|
||||
protected override Image ComputeBitmap()
|
||||
{
|
||||
//var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent);
|
||||
|
||||
var image = _svgDocument.Draw(Width, Height);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ using System.Drawing.Text;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing.Fields;
|
||||
using Greenshot.Editor.Helpers;
|
||||
|
@ -83,7 +84,7 @@ namespace Greenshot.Editor.Drawing
|
|||
OnPropertyChanged("Text");
|
||||
}
|
||||
|
||||
public TextContainer(Surface parent) : base(parent)
|
||||
public TextContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
@ -154,17 +155,17 @@ namespace Greenshot.Editor.Drawing
|
|||
FieldChanged += TextContainer_FieldChanged;
|
||||
}
|
||||
|
||||
protected override void SwitchParent(Surface newParent)
|
||||
protected override void SwitchParent(ISurface newParent)
|
||||
{
|
||||
if (_parent != null)
|
||||
if (InternalParent != null)
|
||||
{
|
||||
_parent.SizeChanged -= Parent_SizeChanged;
|
||||
InternalParent.SizeChanged -= Parent_SizeChanged;
|
||||
}
|
||||
|
||||
base.SwitchParent(newParent);
|
||||
if (_parent != null)
|
||||
if (InternalParent != null)
|
||||
{
|
||||
_parent.SizeChanged += Parent_SizeChanged;
|
||||
InternalParent.SizeChanged += Parent_SizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,10 +222,10 @@ namespace Greenshot.Editor.Drawing
|
|||
{
|
||||
ShowTextBox();
|
||||
}
|
||||
else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible)
|
||||
else if (InternalParent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible)
|
||||
{
|
||||
// Fix (workaround) for BUG-1698
|
||||
_parent.KeysLocked = true;
|
||||
InternalParent.KeysLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,10 +296,10 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
private void ShowTextBox()
|
||||
{
|
||||
if (_parent != null)
|
||||
if (InternalParent != null)
|
||||
{
|
||||
_parent.KeysLocked = true;
|
||||
_parent.Controls.Add(_textBox);
|
||||
InternalParent.KeysLocked = true;
|
||||
InternalParent.Controls.Add(_textBox);
|
||||
}
|
||||
|
||||
EnsureTextBoxContrast();
|
||||
|
@ -332,15 +333,15 @@ namespace Greenshot.Editor.Drawing
|
|||
|
||||
private void HideTextBox()
|
||||
{
|
||||
_parent?.Focus();
|
||||
InternalParent?.Focus();
|
||||
_textBox?.Hide();
|
||||
if (_parent == null)
|
||||
if (InternalParent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent.KeysLocked = false;
|
||||
_parent.Controls.Remove(_textBox);
|
||||
InternalParent.KeysLocked = false;
|
||||
InternalParent.Controls.Remove(_textBox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
117
src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs
Normal file
117
src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.Runtime.Serialization;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the base container for vector graphics, these ae graphics which can resize without loss of quality.
|
||||
/// Examples for this are SVG, WMF or EMF, but also graphics based on fonts (e.g. Emoji)
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class VectorGraphicsContainer : DrawableContainer
|
||||
{
|
||||
protected int RotationAngle;
|
||||
|
||||
/// <summary>
|
||||
/// This is the cached version of the bitmap, pre-rendered to save performance
|
||||
/// Do not serialized, it can be rebuild with some other information.
|
||||
/// </summary>
|
||||
[NonSerialized] private Image _cachedImage;
|
||||
|
||||
public VectorGraphicsContainer(ISurface parent) : base(parent)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
protected override void OnDeserialized(StreamingContext streamingContext)
|
||||
{
|
||||
base.OnDeserialized(streamingContext);
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
CreateDefaultAdorners();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The bulk of the clean-up code is implemented in Dispose(bool)
|
||||
/// This Dispose is called from the Dispose and the Destructor.
|
||||
/// When disposing==true all non-managed resources should be freed too!
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ResetCachedBitmap();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
public override void Transform(Matrix matrix)
|
||||
{
|
||||
RotationAngle += CalculateAngle(matrix);
|
||||
RotationAngle %= 360;
|
||||
|
||||
ResetCachedBitmap();
|
||||
|
||||
base.Transform(matrix);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IDrawableContainer"/>
|
||||
public override void Draw(Graphics graphics, RenderMode rm)
|
||||
{
|
||||
if (_cachedImage != null && _cachedImage.Size != Bounds.Size)
|
||||
{
|
||||
ResetCachedBitmap();
|
||||
}
|
||||
|
||||
_cachedImage ??= ComputeBitmap();
|
||||
|
||||
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
|
||||
graphics.DrawImage(_cachedImage, Bounds);
|
||||
}
|
||||
|
||||
protected abstract Image ComputeBitmap();
|
||||
|
||||
private void ResetCachedBitmap()
|
||||
{
|
||||
_cachedImage?.Dispose();
|
||||
_cachedImage = null;
|
||||
}
|
||||
}
|
||||
}
|
50
src/Greenshot.Editor/EditorInitialize.cs
Normal file
50
src/Greenshot.Editor/EditorInitialize.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Editor.FileFormatHandlers;
|
||||
|
||||
namespace Greenshot.Editor
|
||||
{
|
||||
public static class EditorInitialize
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
SimpleServiceProvider.Current.AddService<IFileFormatHandler>(
|
||||
// All generic things, like gif, png, jpg etc.
|
||||
new DefaultFileFormatHandler(),
|
||||
// Greenshot format
|
||||
new GreenshotFileFormatHandler(),
|
||||
// For .svg support
|
||||
new SvgFileFormatHandler(),
|
||||
// For clipboard support
|
||||
new DibFileFormatHandler(),
|
||||
// .ico
|
||||
new IconFileFormatHandler(),
|
||||
// EMF & WMF
|
||||
new MetaFileFormatHandler(),
|
||||
// JPG XR
|
||||
new WpfFileFormatHandler()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.IO;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
public abstract class AbstractFileFormatHandler : IFileFormatHandler
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IDictionary<FileFormatHandlerActions, IReadOnlyCollection<string>> SupportedExtensions { get; } = new Dictionary<FileFormatHandlerActions, IReadOnlyCollection<string>>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null);
|
||||
|
||||
public abstract bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap);
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation taking the TryLoadFromStream image and placing it in an ImageContainer
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="parent">ISurface</param>
|
||||
/// <returns>IEnumerable{IDrawableContainer}</returns>
|
||||
public virtual IEnumerable<IDrawableContainer> LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null)
|
||||
{
|
||||
if (TryLoadFromStream(stream, extension, out var bitmap))
|
||||
{
|
||||
var imageContainer = new ImageContainer(parent)
|
||||
{
|
||||
Image = bitmap
|
||||
};
|
||||
yield return imageContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the default .NET bitmap file format handler
|
||||
/// </summary>
|
||||
public class DefaultFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(DefaultFileFormatHandler));
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new[] { ".png", ".bmp", ".gif", ".jpg", ".jpeg", ".tiff", ".tif" };
|
||||
public DefaultFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
ImageFormat imageFormat = extension switch
|
||||
{
|
||||
".png" => ImageFormat.Png,
|
||||
".bmp" => ImageFormat.Bmp,
|
||||
".gif" => ImageFormat.Gif,
|
||||
".jpg" => ImageFormat.Jpeg,
|
||||
".jpeg" => ImageFormat.Jpeg,
|
||||
".tiff" => ImageFormat.Tiff,
|
||||
".tif" => ImageFormat.Tiff,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (imageFormat == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
surfaceOutputSettings ??= new SurfaceOutputSettings();
|
||||
var imageEncoder = ImageCodecInfo.GetImageEncoders().FirstOrDefault(ie => ie.FilenameExtension.ToLowerInvariant().Contains(extension));
|
||||
if (imageEncoder == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
EncoderParameters parameters = new EncoderParameters(1)
|
||||
{
|
||||
Param =
|
||||
{
|
||||
[0] = new EncoderParameter(Encoder.Quality, surfaceOutputSettings.JPGQuality)
|
||||
}
|
||||
};
|
||||
// For those images which are with Alpha, but the format doesn't support this, change it to 24bpp
|
||||
if (imageFormat.Guid == ImageFormat.Jpeg.Guid && Image.IsAlphaPixelFormat(bitmap.PixelFormat))
|
||||
{
|
||||
var nonAlphaImage = ImageHelper.Clone(bitmap, PixelFormat.Format24bppRgb) as Bitmap;
|
||||
try
|
||||
{
|
||||
// Set that this file was written by Greenshot
|
||||
nonAlphaImage.AddTag();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warn("Couldn't set 'software used' tag on image.", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
nonAlphaImage.Save(destination, imageEncoder, parameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't save image: ", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
nonAlphaImage.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set that this file was written by Greenshot
|
||||
bitmap.AddTag();
|
||||
bitmap.Save(destination, imageEncoder, parameters);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var tmpImage = Image.FromStream(stream, true, true);
|
||||
bitmap = ImageHelper.Clone(tmpImage, PixelFormat.DontCare);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't load image: ", ex);
|
||||
}
|
||||
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,29 +20,112 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Though Greenshot implements the specs for the DIB image format,
|
||||
/// it seems to cause a lot of issues when using the clipboard.
|
||||
/// There is some research done about the DIB on the clipboard, this code is based upon the information
|
||||
/// <a href="https://stackoverflow.com/questions/44177115/copying-from-and-to-clipboard-loses-image-transparency">here</a>
|
||||
/// This handles creating a DIB (Device Independent Bitmap) on the clipboard
|
||||
/// </summary>
|
||||
internal static class DibHelper
|
||||
public class DibFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private const double DpiToPelsPerMeter = 39.3701;
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(DibFileFormatHandler));
|
||||
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new[] { ".dib", ".format17" };
|
||||
|
||||
public DibFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
var dibBytes = ConvertToDib(bitmap);
|
||||
destination.Write(dibBytes, 0, dibBytes.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
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);
|
||||
// TODO: Replace with a FileFormatHandler
|
||||
bitmap = ImageIO.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS.
|
||||
/// </summary>
|
||||
/// <param name="sourceBitmap">Bitmap to convert to DIB</param>
|
||||
/// <returns>byte{} with the image converted to DIB</returns>
|
||||
public static byte[] ConvertToDib(this Bitmap sourceBitmap)
|
||||
private static byte[] ConvertToDib(Bitmap sourceBitmap)
|
||||
{
|
||||
if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap));
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
public class GreenshotFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(GreenshotFileFormatHandler));
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new [] { ".greenshot" };
|
||||
public GreenshotFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream stream, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
if (surface == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bitmap.Save(stream, ImageFormat.Png);
|
||||
using MemoryStream tmpStream = new MemoryStream();
|
||||
long bytesWritten = surface.SaveElementsToStream(tmpStream);
|
||||
using BinaryWriter writer = new BinaryWriter(tmpStream);
|
||||
writer.Write(bytesWritten);
|
||||
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
|
||||
writer.Write(marker);
|
||||
tmpStream.WriteTo(stream);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't save surface as .greenshot: ", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
try
|
||||
{
|
||||
var surface = LoadSurface(stream);
|
||||
bitmap = (Bitmap)surface.GetImageForExport();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't load .greenshot: ", ex);
|
||||
}
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private ISurface LoadSurface(Stream surfaceFileStream)
|
||||
{
|
||||
var returnSurface = SimpleServiceProvider.Current.GetInstance<Func<ISurface>>().Invoke();
|
||||
Bitmap captureBitmap;
|
||||
|
||||
// Fixed problem that the bitmap stream is disposed... by Cloning the image
|
||||
// This also ensures the bitmap is correctly created
|
||||
using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
|
||||
{
|
||||
Log.DebugFormat("Loaded capture from .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
captureBitmap = ImageHelper.Clone(tmpImage) as Bitmap;
|
||||
}
|
||||
|
||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
||||
const int markerSize = 14;
|
||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
||||
using (var streamReader = new StreamReader(surfaceFileStream))
|
||||
{
|
||||
var greenshotMarker = streamReader.ReadToEnd();
|
||||
if (!greenshotMarker.StartsWith("Greenshot"))
|
||||
{
|
||||
throw new ArgumentException("Stream is not a Greenshot file!");
|
||||
}
|
||||
|
||||
Log.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
||||
const int fileSizeLocation = 8 + markerSize;
|
||||
surfaceFileStream.Seek(-fileSizeLocation, SeekOrigin.End);
|
||||
using BinaryReader reader = new BinaryReader(surfaceFileStream);
|
||||
long bytesWritten = reader.ReadInt64();
|
||||
surfaceFileStream.Seek(-(bytesWritten + fileSizeLocation), SeekOrigin.End);
|
||||
returnSurface.LoadElementsFromStream(surfaceFileStream);
|
||||
}
|
||||
|
||||
if (captureBitmap != null)
|
||||
{
|
||||
returnSurface.Image = captureBitmap;
|
||||
Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", captureBitmap.Width, captureBitmap.Height, captureBitmap.PixelFormat, captureBitmap.HorizontalResolution, captureBitmap.VerticalResolution);
|
||||
}
|
||||
|
||||
return returnSurface;
|
||||
}
|
||||
}
|
||||
}
|
218
src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs
Normal file
218
src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// THis is the .ico format handler
|
||||
/// </summary>
|
||||
public class IconFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(IconFileFormatHandler));
|
||||
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new[] { ".ico" };
|
||||
|
||||
public IconFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream stream, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
IList<Image> images = new List<Image>
|
||||
{
|
||||
bitmap
|
||||
};
|
||||
|
||||
var binaryWriter = new BinaryWriter(stream);
|
||||
//
|
||||
// ICONDIR structure
|
||||
//
|
||||
binaryWriter.Write((short)0); // reserved
|
||||
binaryWriter.Write((short)1); // image type (icon)
|
||||
binaryWriter.Write((short)images.Count); // number of images
|
||||
|
||||
IList<Size> imageSizes = new List<Size>();
|
||||
IList<MemoryStream> encodedImages = new List<MemoryStream>();
|
||||
foreach (var image in images)
|
||||
{
|
||||
// Pick the best fit
|
||||
var sizes = new[]
|
||||
{
|
||||
16, 32, 48
|
||||
};
|
||||
int size = 256;
|
||||
foreach (var possibleSize in sizes)
|
||||
{
|
||||
if (image.Width <= possibleSize && image.Height <= possibleSize)
|
||||
{
|
||||
size = possibleSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var imageStream = new MemoryStream();
|
||||
if (image.Width == size && image.Height == size)
|
||||
{
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
clonedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(new Size(size, size));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resize to the specified size, first make sure the image is 32bpp
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null);
|
||||
resizedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(resizedImage.Size);
|
||||
}
|
||||
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
encodedImages.Add(imageStream);
|
||||
}
|
||||
|
||||
//
|
||||
// ICONDIRENTRY structure
|
||||
//
|
||||
const int iconDirSize = 6;
|
||||
const int iconDirEntrySize = 16;
|
||||
|
||||
var offset = iconDirSize + (images.Count * iconDirEntrySize);
|
||||
for (int i = 0; i < images.Count; i++)
|
||||
{
|
||||
var imageSize = imageSizes[i];
|
||||
// Write the width / height, 0 means 256
|
||||
binaryWriter.Write(imageSize.Width == 256 ? (byte)0 : (byte)imageSize.Width);
|
||||
binaryWriter.Write(imageSize.Height == 256 ? (byte)0 : (byte)imageSize.Height);
|
||||
binaryWriter.Write((byte)0); // no pallete
|
||||
binaryWriter.Write((byte)0); // reserved
|
||||
binaryWriter.Write((short)0); // no color planes
|
||||
binaryWriter.Write((short)32); // 32 bpp
|
||||
binaryWriter.Write((int)encodedImages[i].Length); // image data length
|
||||
binaryWriter.Write(offset);
|
||||
offset += (int)encodedImages[i].Length;
|
||||
}
|
||||
|
||||
binaryWriter.Flush();
|
||||
//
|
||||
// Write image data
|
||||
//
|
||||
foreach (var encodedImage in encodedImages)
|
||||
{
|
||||
encodedImage.WriteTo(stream);
|
||||
encodedImage.Dispose();
|
||||
}
|
||||
|
||||
// TODO: Implement this
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
_ = stream.Seek(0, SeekOrigin.Current);
|
||||
|
||||
// Icon logic, try to get the Vista icon, else the biggest possible
|
||||
try
|
||||
{
|
||||
using Image tmpImage = ExtractVistaIcon(stream);
|
||||
if (tmpImage != null)
|
||||
{
|
||||
bitmap = ImageHelper.Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception vistaIconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", vistaIconException);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// No vista icon, try normal icon
|
||||
stream.Position = stream.Seek(0, SeekOrigin.Begin);
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
using Icon tmpIcon = new Icon(stream, new Size(1024, 1024));
|
||||
using Image tmpImage = tmpIcon.ToBitmap();
|
||||
bitmap = ImageHelper.Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
return true;
|
||||
}
|
||||
catch (Exception iconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", iconException);
|
||||
}
|
||||
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx
|
||||
/// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx
|
||||
/// </summary>
|
||||
/// <param name="iconStream">Stream with the icon information</param>
|
||||
/// <returns>Bitmap with the Vista Icon (256x256)</returns>
|
||||
private static Bitmap ExtractVistaIcon(Stream iconStream)
|
||||
{
|
||||
const int sizeIconDir = 6;
|
||||
const int sizeIconDirEntry = 16;
|
||||
Bitmap bmpPngExtracted = null;
|
||||
try
|
||||
{
|
||||
byte[] srcBuf = new byte[iconStream.Length];
|
||||
// TODO: Check if there is a need to process the result
|
||||
_ = iconStream.Read(srcBuf, 0, (int)iconStream.Length);
|
||||
int iCount = BitConverter.ToInt16(srcBuf, 4);
|
||||
for (int iIndex = 0; iIndex < iCount; iIndex++)
|
||||
{
|
||||
int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
|
||||
int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
|
||||
if (iWidth != 0 || iHeight != 0) continue;
|
||||
|
||||
int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
|
||||
int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
|
||||
using MemoryStream destStream = new MemoryStream();
|
||||
destStream.Write(srcBuf, iImageOffset, iImageSize);
|
||||
destStream.Seek(0, SeekOrigin.Begin);
|
||||
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return bmpPngExtracted;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This handles the Windows metafile files
|
||||
/// </summary>
|
||||
public class MetaFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new[] { ".wmf", ".emf" };
|
||||
|
||||
public MetaFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override 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 override IEnumerable<IDrawableContainer> LoadDrawablesFromStream(Stream stream, string extension, ISurface surface = null)
|
||||
{
|
||||
if (Image.FromStream(stream, true, true) is Metafile metaFile)
|
||||
{
|
||||
yield return new MetafileContainer(metaFile, surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Editor.Drawing;
|
||||
using log4net;
|
||||
using Svg;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This handled the loading of SVG images to the editor
|
||||
/// </summary>
|
||||
public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler));
|
||||
private readonly IReadOnlyCollection<string> _ourExtensions = new[] { ".svg" };
|
||||
|
||||
public SvgFileFormatHandler()
|
||||
{
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions;
|
||||
}
|
||||
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
var svgDocument = SvgDocument.Open<SvgDocument>(stream);
|
||||
|
||||
try
|
||||
{
|
||||
bitmap = svgDocument.Draw();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Can't load SVG", ex);
|
||||
}
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
// TODO: Implement this
|
||||
return false;
|
||||
}
|
||||
|
||||
public override IEnumerable<IDrawableContainer> LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null)
|
||||
{
|
||||
SvgDocument svgDocument = null;
|
||||
try
|
||||
{
|
||||
svgDocument = SvgDocument.Open<SvgDocument>(stream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Can't load SVG", ex);
|
||||
}
|
||||
if (svgDocument != null)
|
||||
{
|
||||
yield return new SvgContainer(svgDocument, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
144
src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs
Normal file
144
src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Greenshot.Editor.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the System.Windows.Media.Imaging (WPF) file format handler, which uses WIC
|
||||
/// </summary>
|
||||
public class WpfFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(WpfFileFormatHandler));
|
||||
private const string HeifDecoder = "{E9A4A80A-44FE-4DE4-8971-7150B10A5199}";
|
||||
private const string WicDecoderCategory = "{7ED96837-96F0-4812-B211-F13C24117ED3}";
|
||||
|
||||
private IReadOnlyCollection<string> LoadFromStreamExtensions { get; } = new []{ ".jxr", ".dds", ".hdp", ".wdp", ".wmp"};
|
||||
private IReadOnlyCollection<string> SaveToStreamExtensions { get; } = new[] { ".jxr" };
|
||||
|
||||
public WpfFileFormatHandler()
|
||||
{
|
||||
LoadFromStreamExtensions = LoadFromStreamExtensions.ToList().Concat(RetrieveSupportedExtensions()).OrderBy(e => e).Distinct().ToArray();
|
||||
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = LoadFromStreamExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = LoadFromStreamExtensions;
|
||||
SupportedExtensions[FileFormatHandlerActions.SaveToStream] = SaveToStreamExtensions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detect all the formats WIC supports
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{string}</returns>
|
||||
private IEnumerable<string> RetrieveSupportedExtensions()
|
||||
{
|
||||
string baseKeyPath;
|
||||
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
|
||||
{
|
||||
baseKeyPath = "Wow6432Node\\CLSID";
|
||||
}
|
||||
else
|
||||
{
|
||||
baseKeyPath = "CLSID";
|
||||
}
|
||||
|
||||
using RegistryKey baseKey = Registry.ClassesRoot.OpenSubKey(baseKeyPath, false);
|
||||
if (baseKey == null) yield break;
|
||||
|
||||
var wicDecoderCategoryPath = Path.Combine(baseKeyPath, WicDecoderCategory, "instance");
|
||||
using RegistryKey categoryKey = Registry.ClassesRoot.OpenSubKey(wicDecoderCategoryPath, false);
|
||||
if (categoryKey == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var codecGuid in categoryKey.GetSubKeyNames())
|
||||
{
|
||||
// Read the properties of the single registered decoder
|
||||
using var codecKey = baseKey.OpenSubKey(codecGuid);
|
||||
if (codecKey == null) continue;
|
||||
|
||||
var fileExtensions = Convert.ToString(codecKey.GetValue("FileExtensions", "")).ToLowerInvariant();
|
||||
foreach (var fileExtension in fileExtensions.Split(','))
|
||||
{
|
||||
yield return fileExtension;
|
||||
}
|
||||
}
|
||||
var heifDecoderPath = Path.Combine(baseKeyPath, HeifDecoder);
|
||||
|
||||
using RegistryKey heifKey = Registry.ClassesRoot.OpenSubKey(heifDecoderPath, false);
|
||||
if (heifKey == null) yield break;
|
||||
|
||||
yield return ".heic";
|
||||
yield return ".heif";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
surfaceOutputSettings ??= new SurfaceOutputSettings();
|
||||
try
|
||||
{
|
||||
var bitmapSource = bitmap.ToBitmapSource();
|
||||
var bitmapFrame = BitmapFrame.Create(bitmapSource);
|
||||
var jpegXrEncoder = new WmpBitmapEncoder();
|
||||
jpegXrEncoder.Frames.Add(bitmapFrame);
|
||||
// TODO: Support supplying a quality
|
||||
jpegXrEncoder.ImageQualityLevel = surfaceOutputSettings.JPGQuality / 100f;
|
||||
jpegXrEncoder.Save(destination);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't save image as JPEG XR: ", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bitmapDecoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
|
||||
var bitmapSource = bitmapDecoder.Frames[0];
|
||||
bitmap = bitmapSource.ToBitmap();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't load image: ", ex);
|
||||
}
|
||||
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,13 +56,13 @@ namespace Greenshot.Editor.Forms
|
|||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageEditorForm));
|
||||
private static readonly EditorConfiguration EditorConfiguration = IniConfig.GetIniSection<EditorConfiguration>();
|
||||
|
||||
private static readonly List<string> IgnoreDestinations = new List<string>
|
||||
private static readonly List<string> IgnoreDestinations = new()
|
||||
{
|
||||
nameof(WellKnownDestinations.Picker),
|
||||
EditorDestination.DESIGNATION
|
||||
};
|
||||
|
||||
private static readonly List<IImageEditor> EditorList = new List<IImageEditor>();
|
||||
private static readonly List<IImageEditor> EditorList = new();
|
||||
|
||||
private Surface _surface;
|
||||
private GreenshotToolStripButton[] _toolbarButtons;
|
||||
|
@ -78,7 +78,7 @@ namespace Greenshot.Editor.Forms
|
|||
// whether part of the editor controls are disabled depending on selected item(s)
|
||||
private bool _controlsDisabledDueToConfirmable;
|
||||
|
||||
// Used for tracking the mouse scrollwheel changes
|
||||
// Used for tracking the mouse scroll wheel changes
|
||||
private DateTime _zoomStartTime = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
|
@ -181,6 +181,20 @@ namespace Greenshot.Editor.Forms
|
|||
|
||||
UpdateUi();
|
||||
|
||||
// Use best fit, for those capture modes where we can get huge images
|
||||
bool useBestFit = _surface.CaptureDetails.CaptureMode switch
|
||||
{
|
||||
CaptureMode.File => true,
|
||||
CaptureMode.Clipboard => true,
|
||||
CaptureMode.IE => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (useBestFit)
|
||||
{
|
||||
ZoomBestFitMenuItemClick(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
// Workaround: As the cursor is (mostly) selected on the surface a funny artifact is visible, this fixes it.
|
||||
HideToolstripItems();
|
||||
}
|
||||
|
@ -1290,7 +1304,7 @@ namespace Greenshot.Editor.Forms
|
|||
propertiesToolStrip.SuspendLayout();
|
||||
if (_surface.HasSelectedElements || _surface.DrawingMode != DrawingModes.None)
|
||||
{
|
||||
FieldAggregator props = _surface.FieldAggregator;
|
||||
var props = (FieldAggregator)_surface.FieldAggregator;
|
||||
btnFillColor.Visible = props.HasFieldValue(FieldType.FILL_COLOR);
|
||||
btnLineColor.Visible = props.HasFieldValue(FieldType.LINE_COLOR);
|
||||
lineThicknessLabel.Visible = lineThicknessUpDown.Visible = props.HasFieldValue(FieldType.LINE_THICKNESS);
|
||||
|
@ -1350,7 +1364,7 @@ namespace Greenshot.Editor.Forms
|
|||
btnStepLabel.Image = icon;
|
||||
addCounterToolStripMenuItem.Image = icon;
|
||||
|
||||
FieldAggregator props = _surface.FieldAggregator;
|
||||
FieldAggregator props = (FieldAggregator)_surface.FieldAggregator;
|
||||
// if a confirmable element is selected, we must disable most of the controls
|
||||
// since we demand confirmation or cancel for confirmable element
|
||||
if (props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Languages\language*.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Memento
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -31,9 +30,9 @@ namespace Greenshot.Editor.Memento
|
|||
public class AddElementMemento : IMemento
|
||||
{
|
||||
private IDrawableContainer _drawableContainer;
|
||||
private Surface _surface;
|
||||
private ISurface _surface;
|
||||
|
||||
public AddElementMemento(Surface surface, IDrawableContainer drawableContainer)
|
||||
public AddElementMemento(ISurface surface, IDrawableContainer drawableContainer)
|
||||
{
|
||||
_surface = surface;
|
||||
_drawableContainer = drawableContainer;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Memento
|
||||
{
|
||||
|
@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento
|
|||
public class AddElementsMemento : IMemento
|
||||
{
|
||||
private IDrawableContainerList _containerList;
|
||||
private Surface _surface;
|
||||
private ISurface _surface;
|
||||
|
||||
public AddElementsMemento(Surface surface, IDrawableContainerList containerList)
|
||||
public AddElementsMemento(ISurface surface, IDrawableContainerList containerList)
|
||||
{
|
||||
_surface = surface;
|
||||
_containerList = containerList;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Memento
|
||||
{
|
||||
|
@ -31,9 +31,9 @@ namespace Greenshot.Editor.Memento
|
|||
public class DeleteElementMemento : IMemento
|
||||
{
|
||||
private IDrawableContainer _drawableContainer;
|
||||
private readonly Surface _surface;
|
||||
private readonly ISurface _surface;
|
||||
|
||||
public DeleteElementMemento(Surface surface, IDrawableContainer drawableContainer)
|
||||
public DeleteElementMemento(ISurface surface, IDrawableContainer drawableContainer)
|
||||
{
|
||||
_surface = surface;
|
||||
_drawableContainer = drawableContainer;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Memento
|
||||
{
|
||||
|
@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento
|
|||
public class DeleteElementsMemento : IMemento
|
||||
{
|
||||
private IDrawableContainerList _containerList;
|
||||
private Surface _surface;
|
||||
private ISurface _surface;
|
||||
|
||||
public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList)
|
||||
public DeleteElementsMemento(ISurface surface, IDrawableContainerList containerList)
|
||||
{
|
||||
_surface = surface;
|
||||
_containerList = containerList;
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Editor.Drawing;
|
||||
|
||||
namespace Greenshot.Editor.Memento
|
||||
{
|
||||
|
@ -32,10 +32,10 @@ namespace Greenshot.Editor.Memento
|
|||
public class SurfaceBackgroundChangeMemento : IMemento
|
||||
{
|
||||
private Image _image;
|
||||
private Surface _surface;
|
||||
private ISurface _surface;
|
||||
private Matrix _matrix;
|
||||
|
||||
public SurfaceBackgroundChangeMemento(Surface surface, Matrix matrix)
|
||||
public SurfaceBackgroundChangeMemento(ISurface surface, Matrix matrix)
|
||||
{
|
||||
_surface = surface;
|
||||
_image = surface.Image;
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace Greenshot.Plugin.Box.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(208, 12);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(BoxConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Box";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(215, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 5;
|
||||
|
@ -115,7 +115,7 @@ namespace Greenshot.Plugin.Box.Forms {
|
|||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "box.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(208, 45);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(BoxConfiguration.AfterUploadLinkToClipBoard);
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Box";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 10;
|
||||
|
|
|
@ -54,8 +54,8 @@ namespace Greenshot.Plugin.Confluence
|
|||
Uri confluenceIconUri = new Uri("/Greenshot.Plugin.Confluence;component/Images/Confluence.ico", UriKind.Relative);
|
||||
using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream)
|
||||
{
|
||||
// TODO: Check what to do with the IImage
|
||||
ConfluenceIcon = ImageHelper.FromStream(iconStream);
|
||||
// TODO: Replace with FileFormatHandler
|
||||
ConfluenceIcon = ImageIO.FromStream(iconStream);
|
||||
}
|
||||
|
||||
IsInitialized = true;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Plugin.Dropbox.Forms;
|
||||
|
@ -29,10 +28,10 @@ using Greenshot.Plugin.Dropbox.Forms;
|
|||
namespace Greenshot.Plugin.Dropbox
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of ImgurConfiguration.
|
||||
/// The configuration for Dropbox
|
||||
/// </summary>
|
||||
[IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")]
|
||||
public class DropboxPluginConfiguration : IniSection
|
||||
public class DropboxConfiguration : IniSection
|
||||
{
|
||||
[IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
|
||||
public OutputFormat UploadFormat { get; set; }
|
|
@ -29,7 +29,7 @@ namespace Greenshot.Plugin.Dropbox
|
|||
{
|
||||
internal class DropboxDestination : AbstractDestination
|
||||
{
|
||||
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>();
|
||||
private static readonly DropboxConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxConfiguration>();
|
||||
|
||||
private readonly DropboxPlugin _plugin;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox
|
|||
public class DropboxPlugin : IGreenshotPlugin
|
||||
{
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin));
|
||||
private static DropboxPluginConfiguration _config;
|
||||
private static DropboxConfiguration _config;
|
||||
private ComponentResourceManager _resources;
|
||||
private ToolStripMenuItem _itemPlugInConfig;
|
||||
|
||||
|
@ -71,7 +71,7 @@ namespace Greenshot.Plugin.Dropbox
|
|||
public bool Initialize()
|
||||
{
|
||||
// Register configuration (don't need the configuration itself)
|
||||
_config = IniConfig.GetIniSection<DropboxPluginConfiguration>();
|
||||
_config = IniConfig.GetIniSection<DropboxConfiguration>();
|
||||
_resources = new ComponentResourceManager(typeof(DropboxPlugin));
|
||||
SimpleServiceProvider.Current.AddService<IDestination>(new DropboxDestination(this));
|
||||
_itemPlugInConfig = new ToolStripMenuItem
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox
|
|||
public class DropboxUtils
|
||||
{
|
||||
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils));
|
||||
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>();
|
||||
private static readonly DropboxConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxConfiguration>();
|
||||
|
||||
private DropboxUtils()
|
||||
{
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Dropbox.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(116, 9);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(DropboxConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Dropbox";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(309, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
|
@ -112,7 +112,7 @@ namespace Greenshot.Plugin.Dropbox.Forms {
|
|||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "dropbox.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(116, 37);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(DropboxConfiguration.AfterUploadLinkToClipBoard);
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Dropbox";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Greenshot.Plugin.ExternalCommand
|
|||
}
|
||||
|
||||
bool runInBackground = config.RunInbackground[_presetCommand];
|
||||
string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings);
|
||||
string fullPath = captureDetails.Filename ?? ImageIO.SaveNamedTmpFile(surface, captureDetails, outputSettings);
|
||||
|
||||
string output;
|
||||
string error;
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(174, 6);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(FlickrConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Flickr";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(251, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
|
@ -111,7 +111,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.checkBoxPublic.LanguageKey = "flickr.public";
|
||||
this.checkBoxPublic.Location = new System.Drawing.Point(174, 88);
|
||||
this.checkBoxPublic.Name = "checkBoxPublic";
|
||||
this.checkBoxPublic.PropertyName = "flickrIsPublic";
|
||||
this.checkBoxPublic.PropertyName = nameof(FlickrConfiguration.IsPublic);
|
||||
this.checkBoxPublic.SectionName = "Flickr";
|
||||
this.checkBoxPublic.Size = new System.Drawing.Size(55, 17);
|
||||
this.checkBoxPublic.TabIndex = 4;
|
||||
|
@ -122,7 +122,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.checkBoxFamily.LanguageKey = "flickr.family";
|
||||
this.checkBoxFamily.Location = new System.Drawing.Point(265, 88);
|
||||
this.checkBoxFamily.Name = "checkBoxFamily";
|
||||
this.checkBoxFamily.PropertyName = "flickrIsFamily";
|
||||
this.checkBoxFamily.PropertyName = nameof(FlickrConfiguration.IsFamily);
|
||||
this.checkBoxFamily.SectionName = "Flickr";
|
||||
this.checkBoxFamily.Size = new System.Drawing.Size(55, 17);
|
||||
this.checkBoxFamily.TabIndex = 5;
|
||||
|
@ -133,7 +133,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.checkBoxFriend.LanguageKey = "flickr.friend";
|
||||
this.checkBoxFriend.Location = new System.Drawing.Point(350, 88);
|
||||
this.checkBoxFriend.Name = "checkBoxFriend";
|
||||
this.checkBoxFriend.PropertyName = "flickrIsFriend";
|
||||
this.checkBoxFriend.PropertyName = nameof(FlickrConfiguration.IsFriend);
|
||||
this.checkBoxFriend.SectionName = "Flickr";
|
||||
this.checkBoxFriend.Size = new System.Drawing.Size(55, 17);
|
||||
this.checkBoxFriend.TabIndex = 6;
|
||||
|
@ -155,7 +155,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.combobox_safetyLevel.FormattingEnabled = true;
|
||||
this.combobox_safetyLevel.Location = new System.Drawing.Point(174, 33);
|
||||
this.combobox_safetyLevel.Name = "combobox_safetyLevel";
|
||||
this.combobox_safetyLevel.PropertyName = "SafetyLevel";
|
||||
this.combobox_safetyLevel.PropertyName = nameof(FlickrConfiguration.SafetyLevel);
|
||||
this.combobox_safetyLevel.SectionName = "Flickr";
|
||||
this.combobox_safetyLevel.Size = new System.Drawing.Size(251, 21);
|
||||
this.combobox_safetyLevel.TabIndex = 2;
|
||||
|
@ -173,7 +173,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "flickr.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(173, 116);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(FlickrConfiguration.AfterUploadLinkToClipBoard);
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Flickr";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 7;
|
||||
|
@ -184,7 +184,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
|
|||
this.checkBox_hiddenfromsearch.LanguageKey = "flickr.label_HiddenFromSearch";
|
||||
this.checkBox_hiddenfromsearch.Location = new System.Drawing.Point(174, 60);
|
||||
this.checkBox_hiddenfromsearch.Name = "checkBox_hiddenfromsearch";
|
||||
this.checkBox_hiddenfromsearch.PropertyName = "HiddenFromSearch";
|
||||
this.checkBox_hiddenfromsearch.PropertyName = nameof(FlickrConfiguration.HiddenFromSearch);
|
||||
this.checkBox_hiddenfromsearch.SectionName = "Flickr";
|
||||
this.checkBox_hiddenfromsearch.Size = new System.Drawing.Size(118, 17);
|
||||
this.checkBox_hiddenfromsearch.TabIndex = 3;
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(GooglePhotosConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "GooglePhotos";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
|
@ -114,7 +114,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms {
|
|||
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50);
|
||||
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard";
|
||||
this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(GooglePhotosConfiguration.AfterUploadLinkToClipBoard);
|
||||
this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos";
|
||||
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
|
||||
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Imgur.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(168, 7);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(ImgurConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Imgur";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(210, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
|
@ -115,7 +115,7 @@ namespace Greenshot.Plugin.Imgur.Forms {
|
|||
this.checkbox_anonymous_access.LanguageKey = "imgur.anonymous_access";
|
||||
this.checkbox_anonymous_access.Location = new System.Drawing.Point(15, 38);
|
||||
this.checkbox_anonymous_access.Name = "checkbox_anonymous_access";
|
||||
this.checkbox_anonymous_access.PropertyName = "AnonymousAccess";
|
||||
this.checkbox_anonymous_access.PropertyName = nameof(ImgurConfiguration.AnonymousAccess);
|
||||
this.checkbox_anonymous_access.SectionName = "Imgur";
|
||||
this.checkbox_anonymous_access.Size = new System.Drawing.Size(139, 17);
|
||||
this.checkbox_anonymous_access.TabIndex = 2;
|
||||
|
@ -126,7 +126,7 @@ namespace Greenshot.Plugin.Imgur.Forms {
|
|||
this.checkbox_usepagelink.LanguageKey = "imgur.use_page_link";
|
||||
this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 57);
|
||||
this.checkbox_usepagelink.Name = "checkbox_usepagelink";
|
||||
this.checkbox_usepagelink.PropertyName = "UsePageLink";
|
||||
this.checkbox_usepagelink.PropertyName = nameof(ImgurConfiguration.UsePageLink);
|
||||
this.checkbox_usepagelink.SectionName = "Imgur";
|
||||
this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17);
|
||||
this.checkbox_usepagelink.TabIndex = 3;
|
||||
|
|
|
@ -179,7 +179,7 @@ namespace Greenshot.Plugin.Imgur
|
|||
{
|
||||
using (var requestStream = webRequest.GetRequestStream())
|
||||
{
|
||||
ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings);
|
||||
ImageIO.SaveToStream(surfaceToUpload, requestStream, outputSettings);
|
||||
}
|
||||
|
||||
using WebResponse response = webRequest.GetResponse();
|
||||
|
@ -265,7 +265,8 @@ namespace Greenshot.Plugin.Imgur
|
|||
Stream responseStream = response.GetResponseStream();
|
||||
if (responseStream != null)
|
||||
{
|
||||
imgurInfo.Image = ImageHelper.FromStream(responseStream);
|
||||
// TODO: Replace with some other code, like the file format handler
|
||||
imgurInfo.Image = ImageIO.FromStream(responseStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace Greenshot.Plugin.Jira.Forms {
|
|||
this.textBoxUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.textBoxUrl.Location = new System.Drawing.Point(164, 21);
|
||||
this.textBoxUrl.Name = "textBoxUrl";
|
||||
this.textBoxUrl.PropertyName = "Url";
|
||||
this.textBoxUrl.PropertyName = nameof(JiraConfiguration.Url);
|
||||
this.textBoxUrl.SectionName = "Jira";
|
||||
this.textBoxUrl.Size = new System.Drawing.Size(214, 20);
|
||||
this.textBoxUrl.TabIndex = 6;
|
||||
|
@ -105,7 +105,7 @@ namespace Greenshot.Plugin.Jira.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(164, 47);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(JiraConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Jira";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(214, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 8;
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace Greenshot.Plugin.Office.Destinations
|
|||
string imageFile = captureDetails.Filename;
|
||||
if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
|
||||
{
|
||||
imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
imageFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
createdFile = true;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ namespace Greenshot.Plugin.Office.Destinations
|
|||
// Cleanup imageFile if we created it here, so less tmp-files are generated and left
|
||||
if (createdFile)
|
||||
{
|
||||
ImageOutput.DeleteNamedTmpFile(imageFile);
|
||||
ImageIO.DeleteNamedTmpFile(imageFile);
|
||||
}
|
||||
|
||||
return exportInformation;
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace Greenshot.Plugin.Office.Destinations
|
|||
string tmpFile = captureDetails.Filename;
|
||||
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
|
||||
{
|
||||
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace Greenshot.Plugin.Office.Destinations
|
|||
Size imageSize = Size.Empty;
|
||||
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
|
||||
{
|
||||
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
imageSize = surface.Image.Size;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace Greenshot.Plugin.Office.Destinations
|
|||
string tmpFile = captureDetails.Filename;
|
||||
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$"))
|
||||
{
|
||||
tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat());
|
||||
}
|
||||
|
||||
if (_documentCaption != null)
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
|
|||
|
||||
using var pngStream = new MemoryStream();
|
||||
var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||
ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
|
||||
ImageIO.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
|
||||
var base64String = Convert.ToBase64String(pngStream.GetBuffer());
|
||||
var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height);
|
||||
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace Greenshot.Plugin.Photobucket.Forms {
|
|||
this.combobox_uploadimageformat.FormattingEnabled = true;
|
||||
this.combobox_uploadimageformat.Location = new System.Drawing.Point(102, 11);
|
||||
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat";
|
||||
this.combobox_uploadimageformat.PropertyName = "UploadFormat";
|
||||
this.combobox_uploadimageformat.PropertyName = nameof(PhotobucketConfiguration.UploadFormat);
|
||||
this.combobox_uploadimageformat.SectionName = "Photobucket";
|
||||
this.combobox_uploadimageformat.Size = new System.Drawing.Size(276, 21);
|
||||
this.combobox_uploadimageformat.TabIndex = 1;
|
||||
|
@ -102,7 +102,7 @@ namespace Greenshot.Plugin.Photobucket.Forms {
|
|||
this.checkbox_usepagelink.LanguageKey = "photobucket.use_page_link";
|
||||
this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 43);
|
||||
this.checkbox_usepagelink.Name = "checkbox_usepagelink";
|
||||
this.checkbox_usepagelink.PropertyName = "UsePageLink";
|
||||
this.checkbox_usepagelink.PropertyName = nameof(PhotobucketConfiguration.UsePageLink);
|
||||
this.checkbox_usepagelink.SectionName = "Photobucket";
|
||||
this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17);
|
||||
this.checkbox_usepagelink.TabIndex = 2;
|
||||
|
|
|
@ -151,7 +151,7 @@ namespace Greenshot.Plugin.Win10.Destinations
|
|||
outputSettings.PreventGreenshotFormat();
|
||||
|
||||
// Create capture for export
|
||||
ImageOutput.SaveToStream(surface, imageStream, outputSettings);
|
||||
ImageIO.SaveToStream(surface, imageStream, outputSettings);
|
||||
imageStream.Position = 0;
|
||||
Log.Debug("Created RandomAccessStreamReference for the image");
|
||||
var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream);
|
||||
|
@ -161,7 +161,7 @@ namespace Greenshot.Plugin.Win10.Destinations
|
|||
using (var tmpImageForThumbnail = surface.GetImageForExport())
|
||||
using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160))
|
||||
{
|
||||
ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
|
||||
ImageIO.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
|
||||
thumbnailStream.Position = 0;
|
||||
thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream);
|
||||
Log.Debug("Created RandomAccessStreamReference for the thumbnail");
|
||||
|
@ -172,7 +172,7 @@ namespace Greenshot.Plugin.Win10.Destinations
|
|||
using (var logo = GreenshotResources.GetGreenshotIcon().ToBitmap())
|
||||
using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30))
|
||||
{
|
||||
ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
|
||||
ImageIO.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
|
||||
logoStream.Position = 0;
|
||||
logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream);
|
||||
Log.Info("Created RandomAccessStreamReference for the logo");
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Win10
|
|||
IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight);
|
||||
outputSettings.Effects.Add(effect);
|
||||
}
|
||||
ImageOutput.SaveToStream(surface, imageStream, outputSettings);
|
||||
ImageIO.SaveToStream(surface, imageStream, outputSettings);
|
||||
imageStream.Position = 0;
|
||||
var randomAccessStream = imageStream.AsRandomAccessStream();
|
||||
|
||||
|
@ -117,7 +117,7 @@ namespace Greenshot.Plugin.Win10
|
|||
OcrInformation result;
|
||||
using (var imageStream = new MemoryStream())
|
||||
{
|
||||
ImageOutput.SaveToStream(image, null, imageStream, new SurfaceOutputSettings());
|
||||
ImageIO.SaveToStream(image, null, imageStream, new SurfaceOutputSettings());
|
||||
imageStream.Position = 0;
|
||||
var randomAccessStream = imageStream.AsRandomAccessStream();
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<configuration>
|
||||
<!--<system.windows.forms jitDebugging="true" />-->
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace Greenshot.Destinations
|
|||
overwrite = true;
|
||||
Log.InfoFormat("Using previous filename");
|
||||
fullPath = captureDetails.Filename;
|
||||
outputSettings.Format = ImageOutput.FormatForFilename(fullPath);
|
||||
outputSettings.Format = ImageIO.FormatForFilename(fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ namespace Greenshot.Destinations
|
|||
// This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642
|
||||
try
|
||||
{
|
||||
ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
ImageIO.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
outputMade = true;
|
||||
}
|
||||
catch (ArgumentException ex1)
|
||||
|
@ -95,7 +95,7 @@ namespace Greenshot.Destinations
|
|||
// Our generated filename exists, display 'save-as'
|
||||
Log.InfoFormat("Not overwriting: {0}", ex1.Message);
|
||||
// when we don't allow to overwrite present a new SaveWithDialog
|
||||
fullPath = ImageOutput.SaveWithDialog(surface, captureDetails);
|
||||
fullPath = ImageIO.SaveWithDialog(surface, captureDetails);
|
||||
outputMade = fullPath != null;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
|
@ -104,7 +104,7 @@ namespace Greenshot.Destinations
|
|||
// Show the problem
|
||||
MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error));
|
||||
// when save failed we present a SaveWithDialog
|
||||
fullPath = ImageOutput.SaveWithDialog(surface, captureDetails);
|
||||
fullPath = ImageIO.SaveWithDialog(surface, captureDetails);
|
||||
outputMade = fullPath != null;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Greenshot.Destinations
|
|||
{
|
||||
ExportInformation exportInformation = new ExportInformation(Designation, Description);
|
||||
// Bug #2918756 don't overwrite path if SaveWithDialog returns null!
|
||||
var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails);
|
||||
var savedTo = ImageIO.SaveWithDialog(surface, captureDetails);
|
||||
if (savedTo != null)
|
||||
{
|
||||
exportInformation.ExportMade = true;
|
||||
|
|
|
@ -36,6 +36,7 @@ using Greenshot.Base;
|
|||
using Greenshot.Base.Controls;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.Help;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
|
@ -43,6 +44,7 @@ using Greenshot.Base.Interfaces.Plugin;
|
|||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.Destinations;
|
||||
using Greenshot.Editor;
|
||||
using Greenshot.Editor.Destinations;
|
||||
using Greenshot.Editor.Drawing;
|
||||
using Greenshot.Editor.Forms;
|
||||
|
@ -162,7 +164,7 @@ namespace Greenshot.Forms
|
|||
|
||||
if (argument.ToLower().Equals("/exit"))
|
||||
{
|
||||
// unregister application on uninstall (allow uninstall)
|
||||
// un-register application on uninstall (allow uninstall)
|
||||
try
|
||||
{
|
||||
LOG.Info("Sending all instances the exit command.");
|
||||
|
@ -387,6 +389,8 @@ namespace Greenshot.Forms
|
|||
|
||||
_instance = this;
|
||||
|
||||
EditorInitialize.Initialize();
|
||||
|
||||
// Factory for surface objects
|
||||
ISurface SurfaceFactory() => new Surface();
|
||||
|
||||
|
@ -923,10 +927,10 @@ namespace Greenshot.Forms
|
|||
Hide();
|
||||
ShowInTaskbar = false;
|
||||
|
||||
|
||||
using var loProcess = Process.GetCurrentProcess();
|
||||
loProcess.MaxWorkingSet = (IntPtr)750000;
|
||||
loProcess.MinWorkingSet = (IntPtr)300000;
|
||||
// TODO: Do we really need this?
|
||||
//using var loProcess = Process.GetCurrentProcess();
|
||||
//loProcess.MaxWorkingSet = (IntPtr)750000;
|
||||
//loProcess.MinWorkingSet = (IntPtr)300000;
|
||||
}
|
||||
|
||||
private void CaptureRegion()
|
||||
|
@ -936,9 +940,12 @@ namespace Greenshot.Forms
|
|||
|
||||
private void CaptureFile(IDestination destination = null)
|
||||
{
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var extensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).Select(e => $"*{e}").ToList();
|
||||
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Filter = @"Image files (*.greenshot, *.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.greenshot; *.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf"
|
||||
Filter = @$"Image files ({string.Join(", ", extensions)})|{string.Join("; ", extensions)}"
|
||||
};
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
{
|
||||
|
@ -1904,7 +1911,7 @@ namespace Greenshot.Forms
|
|||
LOG.Error("Error closing application!", e);
|
||||
}
|
||||
|
||||
ImageOutput.RemoveTmpFiles();
|
||||
ImageIO.RemoveTmpFiles();
|
||||
|
||||
// Store any open configuration changes
|
||||
try
|
||||
|
|
17
src/Greenshot/Forms/PrintOptionsDialog.Designer.cs
generated
17
src/Greenshot/Forms/PrintOptionsDialog.Designer.cs
generated
|
@ -89,7 +89,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink";
|
||||
this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23);
|
||||
this.checkboxAllowShrink.Name = "checkboxAllowShrink";
|
||||
this.checkboxAllowShrink.PropertyName = "OutputPrintAllowShrink";
|
||||
this.checkboxAllowShrink.PropertyName = nameof(coreConfiguration.OutputPrintAllowShrink);
|
||||
this.checkboxAllowShrink.Size = new System.Drawing.Size(168, 17);
|
||||
this.checkboxAllowShrink.TabIndex = 2;
|
||||
this.checkboxAllowShrink.Text = "Shrink printout to fit paper size";
|
||||
|
@ -103,7 +103,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge";
|
||||
this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46);
|
||||
this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge";
|
||||
this.checkboxAllowEnlarge.PropertyName = "OutputPrintAllowEnlarge";
|
||||
this.checkboxAllowEnlarge.PropertyName = nameof(coreConfiguration.OutputPrintAllowEnlarge);
|
||||
this.checkboxAllowEnlarge.Size = new System.Drawing.Size(174, 17);
|
||||
this.checkboxAllowEnlarge.TabIndex = 3;
|
||||
this.checkboxAllowEnlarge.Text = "Enlarge printout to fit paper size";
|
||||
|
@ -117,7 +117,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter";
|
||||
this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92);
|
||||
this.checkboxAllowCenter.Name = "checkboxAllowCenter";
|
||||
this.checkboxAllowCenter.PropertyName = "OutputPrintCenter";
|
||||
this.checkboxAllowCenter.PropertyName = nameof(coreConfiguration.OutputPrintCenter);
|
||||
this.checkboxAllowCenter.Size = new System.Drawing.Size(137, 17);
|
||||
this.checkboxAllowCenter.TabIndex = 5;
|
||||
this.checkboxAllowCenter.Text = "Center printout on page";
|
||||
|
@ -131,7 +131,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate";
|
||||
this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69);
|
||||
this.checkboxAllowRotate.Name = "checkboxAllowRotate";
|
||||
this.checkboxAllowRotate.PropertyName = "OutputPrintAllowRotate";
|
||||
this.checkboxAllowRotate.PropertyName = nameof(coreConfiguration.OutputPrintAllowRotate);
|
||||
this.checkboxAllowRotate.Size = new System.Drawing.Size(187, 17);
|
||||
this.checkboxAllowRotate.TabIndex = 4;
|
||||
this.checkboxAllowRotate.Text = "Rotate printout to page orientation";
|
||||
|
@ -158,7 +158,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxDateTime.LanguageKey = "printoptions_timestamp";
|
||||
this.checkboxDateTime.Location = new System.Drawing.Point(13, 115);
|
||||
this.checkboxDateTime.Name = "checkboxDateTime";
|
||||
this.checkboxDateTime.PropertyName = "OutputPrintFooter";
|
||||
this.checkboxDateTime.PropertyName = nameof(coreConfiguration.OutputPrintFooter);
|
||||
this.checkboxDateTime.Size = new System.Drawing.Size(187, 17);
|
||||
this.checkboxDateTime.TabIndex = 6;
|
||||
this.checkboxDateTime.Text = "Print date / time at bottom of page";
|
||||
|
@ -184,7 +184,7 @@ namespace Greenshot.Forms
|
|||
this.checkboxPrintInverted.LanguageKey = "printoptions_inverted";
|
||||
this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88);
|
||||
this.checkboxPrintInverted.Name = "checkboxPrintInverted";
|
||||
this.checkboxPrintInverted.PropertyName = "OutputPrintInverted";
|
||||
this.checkboxPrintInverted.PropertyName = nameof(coreConfiguration.OutputPrintInverted);
|
||||
this.checkboxPrintInverted.Size = new System.Drawing.Size(141, 17);
|
||||
this.checkboxPrintInverted.TabIndex = 14;
|
||||
this.checkboxPrintInverted.Text = "Print with inverted colors";
|
||||
|
@ -198,7 +198,7 @@ namespace Greenshot.Forms
|
|||
this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale";
|
||||
this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42);
|
||||
this.radioBtnGrayScale.Name = "radioBtnGrayScale";
|
||||
this.radioBtnGrayScale.PropertyName = "OutputPrintGrayscale";
|
||||
this.radioBtnGrayScale.PropertyName = nameof(coreConfiguration.OutputPrintGrayscale);
|
||||
this.radioBtnGrayScale.Size = new System.Drawing.Size(137, 17);
|
||||
this.radioBtnGrayScale.TabIndex = 12;
|
||||
this.radioBtnGrayScale.Text = "Force grayscale printing";
|
||||
|
@ -212,7 +212,7 @@ namespace Greenshot.Forms
|
|||
this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome";
|
||||
this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65);
|
||||
this.radioBtnMonochrome.Name = "radioBtnMonochrome";
|
||||
this.radioBtnMonochrome.PropertyName = "OutputPrintMonochrome";
|
||||
this.radioBtnMonochrome.PropertyName = nameof(coreConfiguration.OutputPrintMonochrome);
|
||||
this.radioBtnMonochrome.Size = new System.Drawing.Size(148, 17);
|
||||
this.radioBtnMonochrome.TabIndex = 13;
|
||||
this.radioBtnMonochrome.Text = "Force black/white printing";
|
||||
|
@ -255,7 +255,6 @@ namespace Greenshot.Forms
|
|||
this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor";
|
||||
this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19);
|
||||
this.radioBtnColorPrint.Name = "radioBtnColorPrint";
|
||||
this.radioBtnColorPrint.PropertyName = "OutputPrintColor";
|
||||
this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17);
|
||||
this.radioBtnColorPrint.TabIndex = 11;
|
||||
this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft;
|
||||
|
|
77
src/Greenshot/Forms/SettingsForm.Designer.cs
generated
77
src/Greenshot/Forms/SettingsForm.Designer.cs
generated
|
@ -20,6 +20,8 @@
|
|||
*/
|
||||
|
||||
using Greenshot.Base.Controls;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Editor.Configuration;
|
||||
using Greenshot.Editor.Controls;
|
||||
|
||||
namespace Greenshot.Forms {
|
||||
|
@ -248,7 +250,7 @@ namespace Greenshot.Forms {
|
|||
this.textbox_screenshotname.Location = new System.Drawing.Point(205, 42);
|
||||
this.textbox_screenshotname.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.textbox_screenshotname.Name = "textbox_screenshotname";
|
||||
this.textbox_screenshotname.PropertyName = "OutputFileFilenamePattern";
|
||||
this.textbox_screenshotname.PropertyName = nameof(coreConfiguration.OutputFileFilenamePattern);
|
||||
this.textbox_screenshotname.Size = new System.Drawing.Size(205, 20);
|
||||
this.textbox_screenshotname.TabIndex = 3;
|
||||
this.textbox_screenshotname.TextChanged += new System.EventHandler(this.FilenamePatternChanged);
|
||||
|
@ -281,7 +283,7 @@ namespace Greenshot.Forms {
|
|||
this.combobox_primaryimageformat.Location = new System.Drawing.Point(205, 66);
|
||||
this.combobox_primaryimageformat.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.combobox_primaryimageformat.Name = "combobox_primaryimageformat";
|
||||
this.combobox_primaryimageformat.PropertyName = "OutputFileFormat";
|
||||
this.combobox_primaryimageformat.PropertyName = nameof(coreConfiguration.OutputFileFormat);
|
||||
this.combobox_primaryimageformat.Size = new System.Drawing.Size(235, 21);
|
||||
this.combobox_primaryimageformat.TabIndex = 5;
|
||||
//
|
||||
|
@ -333,7 +335,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_copypathtoclipboard.Location = new System.Drawing.Point(8, 93);
|
||||
this.checkbox_copypathtoclipboard.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_copypathtoclipboard.Name = "checkbox_copypathtoclipboard";
|
||||
this.checkbox_copypathtoclipboard.PropertyName = "OutputFileCopyPathToClipboard";
|
||||
this.checkbox_copypathtoclipboard.PropertyName = nameof(coreConfiguration.OutputFileCopyPathToClipboard);
|
||||
this.checkbox_copypathtoclipboard.Size = new System.Drawing.Size(358, 20);
|
||||
this.checkbox_copypathtoclipboard.TabIndex = 6;
|
||||
this.checkbox_copypathtoclipboard.Text = "Copy file path to clipboard every time an image is saved";
|
||||
|
@ -345,7 +347,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_zoomer.Location = new System.Drawing.Point(4, 82);
|
||||
this.checkbox_zoomer.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_zoomer.Name = "checkbox_zoomer";
|
||||
this.checkbox_zoomer.PropertyName = "ZoomerEnabled";
|
||||
this.checkbox_zoomer.PropertyName = nameof(coreConfiguration.ZoomerEnabled);
|
||||
this.checkbox_zoomer.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_zoomer.TabIndex = 4;
|
||||
this.checkbox_zoomer.Text = "Show magnifier";
|
||||
|
@ -440,7 +442,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_reducecolors.Location = new System.Drawing.Point(8, 95);
|
||||
this.checkbox_reducecolors.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_reducecolors.Name = "checkbox_reducecolors";
|
||||
this.checkbox_reducecolors.PropertyName = "OutputFileReduceColors";
|
||||
this.checkbox_reducecolors.PropertyName = nameof(coreConfiguration.OutputFileReduceColors);
|
||||
this.checkbox_reducecolors.Size = new System.Drawing.Size(358, 20);
|
||||
this.checkbox_reducecolors.TabIndex = 10;
|
||||
this.checkbox_reducecolors.Text = "Reduce the amount of colors to a maximum of 256";
|
||||
|
@ -452,7 +454,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_alwaysshowqualitydialog.Location = new System.Drawing.Point(8, 69);
|
||||
this.checkbox_alwaysshowqualitydialog.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_alwaysshowqualitydialog.Name = "checkbox_alwaysshowqualitydialog";
|
||||
this.checkbox_alwaysshowqualitydialog.PropertyName = "OutputFilePromptQuality";
|
||||
this.checkbox_alwaysshowqualitydialog.PropertyName = nameof(coreConfiguration.OutputFilePromptQuality);
|
||||
this.checkbox_alwaysshowqualitydialog.Size = new System.Drawing.Size(358, 20);
|
||||
this.checkbox_alwaysshowqualitydialog.TabIndex = 9;
|
||||
this.checkbox_alwaysshowqualitydialog.Text = "Show quality dialog every time an image is saved";
|
||||
|
@ -620,7 +622,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_usedefaultproxy.Location = new System.Drawing.Point(7, 19);
|
||||
this.checkbox_usedefaultproxy.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_usedefaultproxy.Name = "checkbox_usedefaultproxy";
|
||||
this.checkbox_usedefaultproxy.PropertyName = "UseProxy";
|
||||
this.checkbox_usedefaultproxy.PropertyName = nameof(coreConfiguration.UseProxy);
|
||||
this.checkbox_usedefaultproxy.Size = new System.Drawing.Size(359, 20);
|
||||
this.checkbox_usedefaultproxy.TabIndex = 7;
|
||||
this.checkbox_usedefaultproxy.Text = "Use default system proxy";
|
||||
|
@ -665,7 +667,7 @@ namespace Greenshot.Forms {
|
|||
this.lastregion_hotkeyControl.Location = new System.Drawing.Point(280, 81);
|
||||
this.lastregion_hotkeyControl.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.lastregion_hotkeyControl.Name = "lastregion_hotkeyControl";
|
||||
this.lastregion_hotkeyControl.PropertyName = "LastregionHotkey";
|
||||
this.lastregion_hotkeyControl.PropertyName = nameof(coreConfiguration.LastregionHotkey);
|
||||
this.lastregion_hotkeyControl.Size = new System.Drawing.Size(158, 20);
|
||||
this.lastregion_hotkeyControl.TabIndex = 5;
|
||||
//
|
||||
|
@ -686,7 +688,7 @@ namespace Greenshot.Forms {
|
|||
this.ie_hotkeyControl.Location = new System.Drawing.Point(280, 104);
|
||||
this.ie_hotkeyControl.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.ie_hotkeyControl.Name = "ie_hotkeyControl";
|
||||
this.ie_hotkeyControl.PropertyName = "IEHotkey";
|
||||
this.ie_hotkeyControl.PropertyName = nameof(coreConfiguration.IEHotkey);
|
||||
this.ie_hotkeyControl.Size = new System.Drawing.Size(158, 20);
|
||||
this.ie_hotkeyControl.TabIndex = 6;
|
||||
//
|
||||
|
@ -727,7 +729,7 @@ namespace Greenshot.Forms {
|
|||
this.region_hotkeyControl.Location = new System.Drawing.Point(280, 59);
|
||||
this.region_hotkeyControl.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.region_hotkeyControl.Name = "region_hotkeyControl";
|
||||
this.region_hotkeyControl.PropertyName = "RegionHotkey";
|
||||
this.region_hotkeyControl.PropertyName = nameof(coreConfiguration.RegionHotkey);
|
||||
this.region_hotkeyControl.Size = new System.Drawing.Size(158, 20);
|
||||
this.region_hotkeyControl.TabIndex = 4;
|
||||
//
|
||||
|
@ -738,7 +740,7 @@ namespace Greenshot.Forms {
|
|||
this.window_hotkeyControl.Location = new System.Drawing.Point(280, 36);
|
||||
this.window_hotkeyControl.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.window_hotkeyControl.Name = "window_hotkeyControl";
|
||||
this.window_hotkeyControl.PropertyName = "WindowHotkey";
|
||||
this.window_hotkeyControl.PropertyName = nameof(coreConfiguration.WindowHotkey);
|
||||
this.window_hotkeyControl.Size = new System.Drawing.Size(158, 20);
|
||||
this.window_hotkeyControl.TabIndex = 3;
|
||||
//
|
||||
|
@ -749,7 +751,7 @@ namespace Greenshot.Forms {
|
|||
this.fullscreen_hotkeyControl.Location = new System.Drawing.Point(280, 14);
|
||||
this.fullscreen_hotkeyControl.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.fullscreen_hotkeyControl.Name = "fullscreen_hotkeyControl";
|
||||
this.fullscreen_hotkeyControl.PropertyName = "FullscreenHotkey";
|
||||
this.fullscreen_hotkeyControl.PropertyName = nameof(coreConfiguration.FullscreenHotkey);
|
||||
this.fullscreen_hotkeyControl.Size = new System.Drawing.Size(158, 20);
|
||||
this.fullscreen_hotkeyControl.TabIndex = 2;
|
||||
//
|
||||
|
@ -787,7 +789,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_editor_match_capture_size.Location = new System.Drawing.Point(4, 17);
|
||||
this.checkbox_editor_match_capture_size.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_editor_match_capture_size.Name = "checkbox_editor_match_capture_size";
|
||||
this.checkbox_editor_match_capture_size.PropertyName = "MatchSizeToCapture";
|
||||
this.checkbox_editor_match_capture_size.PropertyName = nameof(EditorConfiguration.MatchSizeToCapture);
|
||||
this.checkbox_editor_match_capture_size.SectionName = "Editor";
|
||||
this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_editor_match_capture_size.TabIndex = 11;
|
||||
|
@ -813,7 +815,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_ie_capture.Location = new System.Drawing.Point(4, 16);
|
||||
this.checkbox_ie_capture.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_ie_capture.Name = "checkbox_ie_capture";
|
||||
this.checkbox_ie_capture.PropertyName = "IECapture";
|
||||
this.checkbox_ie_capture.PropertyName = nameof(coreConfiguration.IECapture);
|
||||
this.checkbox_ie_capture.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_ie_capture.TabIndex = 10;
|
||||
this.checkbox_ie_capture.Text = "Internet Explorer capture";
|
||||
|
@ -864,7 +866,7 @@ namespace Greenshot.Forms {
|
|||
this.radiobuttonInteractiveCapture.Location = new System.Drawing.Point(4, 17);
|
||||
this.radiobuttonInteractiveCapture.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.radiobuttonInteractiveCapture.Name = "radiobuttonInteractiveCapture";
|
||||
this.radiobuttonInteractiveCapture.PropertyName = "CaptureWindowsInteractive";
|
||||
this.radiobuttonInteractiveCapture.PropertyName = nameof(coreConfiguration.CaptureWindowsInteractive);
|
||||
this.radiobuttonInteractiveCapture.Size = new System.Drawing.Size(362, 20);
|
||||
this.radiobuttonInteractiveCapture.TabIndex = 6;
|
||||
this.radiobuttonInteractiveCapture.TabStop = true;
|
||||
|
@ -910,7 +912,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_notifications.Location = new System.Drawing.Point(4, 60);
|
||||
this.checkbox_notifications.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_notifications.Name = "checkbox_notifications";
|
||||
this.checkbox_notifications.PropertyName = "ShowTrayNotification";
|
||||
this.checkbox_notifications.PropertyName = nameof(coreConfiguration.ShowTrayNotification);
|
||||
this.checkbox_notifications.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_notifications.TabIndex = 3;
|
||||
this.checkbox_notifications.Text = "Show notifications";
|
||||
|
@ -922,7 +924,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_playsound.Location = new System.Drawing.Point(4, 38);
|
||||
this.checkbox_playsound.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_playsound.Name = "checkbox_playsound";
|
||||
this.checkbox_playsound.PropertyName = "PlayCameraSound";
|
||||
this.checkbox_playsound.PropertyName = nameof(coreConfiguration.PlayCameraSound);
|
||||
this.checkbox_playsound.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_playsound.TabIndex = 2;
|
||||
this.checkbox_playsound.Text = "Play camera sound";
|
||||
|
@ -934,7 +936,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_capture_mousepointer.Location = new System.Drawing.Point(4, 16);
|
||||
this.checkbox_capture_mousepointer.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_capture_mousepointer.Name = "checkbox_capture_mousepointer";
|
||||
this.checkbox_capture_mousepointer.PropertyName = "CaptureMousepointer";
|
||||
this.checkbox_capture_mousepointer.PropertyName = nameof(coreConfiguration.CaptureMousepointer);
|
||||
this.checkbox_capture_mousepointer.Size = new System.Drawing.Size(362, 20);
|
||||
this.checkbox_capture_mousepointer.TabIndex = 1;
|
||||
this.checkbox_capture_mousepointer.Text = "Capture mousepointer";
|
||||
|
@ -1035,7 +1037,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxPrintInverted.Location = new System.Drawing.Point(10, 94);
|
||||
this.checkboxPrintInverted.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxPrintInverted.Name = "checkboxPrintInverted";
|
||||
this.checkboxPrintInverted.PropertyName = "OutputPrintInverted";
|
||||
this.checkboxPrintInverted.PropertyName = nameof(coreConfiguration.OutputPrintInverted);
|
||||
this.checkboxPrintInverted.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxPrintInverted.TabIndex = 14;
|
||||
this.checkboxPrintInverted.Text = "Print with inverted colors";
|
||||
|
@ -1050,7 +1052,8 @@ namespace Greenshot.Forms {
|
|||
this.radioBtnColorPrint.Location = new System.Drawing.Point(10, 16);
|
||||
this.radioBtnColorPrint.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.radioBtnColorPrint.Name = "radioBtnColorPrint";
|
||||
this.radioBtnColorPrint.PropertyName = "OutputPrintColor";
|
||||
//TODO missing property in coreConfiguration
|
||||
//this.radioBtnColorPrint.PropertyName = nameof(coreConfiguration.OutputPrintColor);
|
||||
this.radioBtnColorPrint.Size = new System.Drawing.Size(355, 20);
|
||||
this.radioBtnColorPrint.TabIndex = 11;
|
||||
this.radioBtnColorPrint.Text = "Full color print";
|
||||
|
@ -1065,7 +1068,7 @@ namespace Greenshot.Forms {
|
|||
this.radioBtnGrayScale.Location = new System.Drawing.Point(10, 42);
|
||||
this.radioBtnGrayScale.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.radioBtnGrayScale.Name = "radioBtnGrayScale";
|
||||
this.radioBtnGrayScale.PropertyName = "OutputPrintGrayscale";
|
||||
this.radioBtnGrayScale.PropertyName = nameof(coreConfiguration.OutputPrintGrayscale);
|
||||
this.radioBtnGrayScale.Size = new System.Drawing.Size(355, 20);
|
||||
this.radioBtnGrayScale.TabIndex = 12;
|
||||
this.radioBtnGrayScale.Text = "Force grayscale printing";
|
||||
|
@ -1080,7 +1083,7 @@ namespace Greenshot.Forms {
|
|||
this.radioBtnMonochrome.Location = new System.Drawing.Point(10, 68);
|
||||
this.radioBtnMonochrome.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.radioBtnMonochrome.Name = "radioBtnMonochrome";
|
||||
this.radioBtnMonochrome.PropertyName = "OutputPrintMonochrome";
|
||||
this.radioBtnMonochrome.PropertyName = nameof(coreConfiguration.OutputPrintMonochrome);
|
||||
this.radioBtnMonochrome.Size = new System.Drawing.Size(355, 20);
|
||||
this.radioBtnMonochrome.TabIndex = 13;
|
||||
this.radioBtnMonochrome.Text = "Force black/white printing";
|
||||
|
@ -1112,7 +1115,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxDateTime.Location = new System.Drawing.Point(10, 116);
|
||||
this.checkboxDateTime.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxDateTime.Name = "checkboxDateTime";
|
||||
this.checkboxDateTime.PropertyName = "OutputPrintFooter";
|
||||
this.checkboxDateTime.PropertyName = nameof(coreConfiguration.OutputPrintFooter);
|
||||
this.checkboxDateTime.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxDateTime.TabIndex = 6;
|
||||
this.checkboxDateTime.Text = "Print date / time at bottom of page";
|
||||
|
@ -1127,7 +1130,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxAllowShrink.Location = new System.Drawing.Point(10, 20);
|
||||
this.checkboxAllowShrink.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxAllowShrink.Name = "checkboxAllowShrink";
|
||||
this.checkboxAllowShrink.PropertyName = "OutputPrintAllowShrink";
|
||||
this.checkboxAllowShrink.PropertyName = nameof(coreConfiguration.OutputPrintAllowShrink);
|
||||
this.checkboxAllowShrink.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxAllowShrink.TabIndex = 2;
|
||||
this.checkboxAllowShrink.Text = "Shrink printout to fit paper size";
|
||||
|
@ -1142,7 +1145,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxAllowEnlarge.Location = new System.Drawing.Point(10, 44);
|
||||
this.checkboxAllowEnlarge.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge";
|
||||
this.checkboxAllowEnlarge.PropertyName = "OutputPrintAllowEnlarge";
|
||||
this.checkboxAllowEnlarge.PropertyName = nameof(coreConfiguration.OutputPrintAllowEnlarge);
|
||||
this.checkboxAllowEnlarge.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxAllowEnlarge.TabIndex = 3;
|
||||
this.checkboxAllowEnlarge.Text = "Enlarge printout to fit paper size";
|
||||
|
@ -1157,7 +1160,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxAllowRotate.Location = new System.Drawing.Point(10, 68);
|
||||
this.checkboxAllowRotate.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxAllowRotate.Name = "checkboxAllowRotate";
|
||||
this.checkboxAllowRotate.PropertyName = "OutputPrintAllowRotate";
|
||||
this.checkboxAllowRotate.PropertyName = nameof(coreConfiguration.OutputPrintAllowRotate);
|
||||
this.checkboxAllowRotate.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxAllowRotate.TabIndex = 4;
|
||||
this.checkboxAllowRotate.Text = "Rotate printout to page orientation";
|
||||
|
@ -1172,7 +1175,7 @@ namespace Greenshot.Forms {
|
|||
this.checkboxAllowCenter.Location = new System.Drawing.Point(10, 92);
|
||||
this.checkboxAllowCenter.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkboxAllowCenter.Name = "checkboxAllowCenter";
|
||||
this.checkboxAllowCenter.PropertyName = "OutputPrintCenter";
|
||||
this.checkboxAllowCenter.PropertyName = nameof(coreConfiguration.OutputPrintCenter);
|
||||
this.checkboxAllowCenter.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkboxAllowCenter.TabIndex = 5;
|
||||
this.checkboxAllowCenter.Text = "Center printout on page";
|
||||
|
@ -1185,7 +1188,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_alwaysshowprintoptionsdialog.Location = new System.Drawing.Point(14, 282);
|
||||
this.checkbox_alwaysshowprintoptionsdialog.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_alwaysshowprintoptionsdialog.Name = "checkbox_alwaysshowprintoptionsdialog";
|
||||
this.checkbox_alwaysshowprintoptionsdialog.PropertyName = "OutputPrintPromptOptions";
|
||||
this.checkbox_alwaysshowprintoptionsdialog.PropertyName = nameof(coreConfiguration.OutputPrintPromptOptions);
|
||||
this.checkbox_alwaysshowprintoptionsdialog.Size = new System.Drawing.Size(355, 20);
|
||||
this.checkbox_alwaysshowprintoptionsdialog.TabIndex = 15;
|
||||
this.checkbox_alwaysshowprintoptionsdialog.Text = "Show print options dialog every time an image is printed";
|
||||
|
@ -1293,7 +1296,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_reuseeditor.Location = new System.Drawing.Point(8, 240);
|
||||
this.checkbox_reuseeditor.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_reuseeditor.Name = "checkbox_reuseeditor";
|
||||
this.checkbox_reuseeditor.PropertyName = "ReuseEditor";
|
||||
this.checkbox_reuseeditor.PropertyName = nameof(EditorConfiguration.ReuseEditor);
|
||||
this.checkbox_reuseeditor.SectionName = "Editor";
|
||||
this.checkbox_reuseeditor.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_reuseeditor.TabIndex = 9;
|
||||
|
@ -1306,7 +1309,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_minimizememoryfootprint.Location = new System.Drawing.Point(8, 216);
|
||||
this.checkbox_minimizememoryfootprint.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_minimizememoryfootprint.Name = "checkbox_minimizememoryfootprint";
|
||||
this.checkbox_minimizememoryfootprint.PropertyName = "MinimizeWorkingSetSize";
|
||||
this.checkbox_minimizememoryfootprint.PropertyName = nameof(coreConfiguration.MinimizeWorkingSetSize);
|
||||
this.checkbox_minimizememoryfootprint.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_minimizememoryfootprint.TabIndex = 8;
|
||||
this.checkbox_minimizememoryfootprint.Text = "Minimize memory footprint, but with a performance penalty (not advised).";
|
||||
|
@ -1318,7 +1321,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_checkunstableupdates.Location = new System.Drawing.Point(8, 192);
|
||||
this.checkbox_checkunstableupdates.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_checkunstableupdates.Name = "checkbox_checkunstableupdates";
|
||||
this.checkbox_checkunstableupdates.PropertyName = "CheckForUnstable";
|
||||
this.checkbox_checkunstableupdates.PropertyName = nameof(coreConfiguration.CheckForUnstable);
|
||||
this.checkbox_checkunstableupdates.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_checkunstableupdates.TabIndex = 7;
|
||||
this.checkbox_checkunstableupdates.Text = "Check for unstable updates";
|
||||
|
@ -1330,7 +1333,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_suppresssavedialogatclose.Location = new System.Drawing.Point(8, 168);
|
||||
this.checkbox_suppresssavedialogatclose.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_suppresssavedialogatclose.Name = "checkbox_suppresssavedialogatclose";
|
||||
this.checkbox_suppresssavedialogatclose.PropertyName = "SuppressSaveDialogAtClose";
|
||||
this.checkbox_suppresssavedialogatclose.PropertyName = nameof(EditorConfiguration.SuppressSaveDialogAtClose);
|
||||
this.checkbox_suppresssavedialogatclose.SectionName = "Editor";
|
||||
this.checkbox_suppresssavedialogatclose.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_suppresssavedialogatclose.TabIndex = 6;
|
||||
|
@ -1352,7 +1355,7 @@ namespace Greenshot.Forms {
|
|||
this.textbox_counter.Location = new System.Drawing.Point(304, 288);
|
||||
this.textbox_counter.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.textbox_counter.Name = "textbox_counter";
|
||||
this.textbox_counter.PropertyName = "OutputFileIncrementingNumber";
|
||||
this.textbox_counter.PropertyName = nameof(coreConfiguration.OutputFileIncrementingNumber);
|
||||
this.textbox_counter.Size = new System.Drawing.Size(134, 20);
|
||||
this.textbox_counter.TabIndex = 11;
|
||||
//
|
||||
|
@ -1371,7 +1374,7 @@ namespace Greenshot.Forms {
|
|||
this.textbox_footerpattern.Location = new System.Drawing.Point(155, 264);
|
||||
this.textbox_footerpattern.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.textbox_footerpattern.Name = "textbox_footerpattern";
|
||||
this.textbox_footerpattern.PropertyName = "OutputPrintFooterPattern";
|
||||
this.textbox_footerpattern.PropertyName = nameof(coreConfiguration.OutputPrintFooterPattern);
|
||||
this.textbox_footerpattern.Size = new System.Drawing.Size(283, 20);
|
||||
this.textbox_footerpattern.TabIndex = 10;
|
||||
//
|
||||
|
@ -1381,7 +1384,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_thumbnailpreview.Location = new System.Drawing.Point(8, 144);
|
||||
this.checkbox_thumbnailpreview.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_thumbnailpreview.Name = "checkbox_thumbnailpreview";
|
||||
this.checkbox_thumbnailpreview.PropertyName = "ThumnailPreview";
|
||||
this.checkbox_thumbnailpreview.PropertyName = nameof(coreConfiguration.ThumnailPreview);
|
||||
this.checkbox_thumbnailpreview.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_thumbnailpreview.TabIndex = 5;
|
||||
this.checkbox_thumbnailpreview.Text = "Show window thumbnails in context menu (for Vista and windows 7)";
|
||||
|
@ -1393,7 +1396,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_optimizeforrdp.Location = new System.Drawing.Point(8, 120);
|
||||
this.checkbox_optimizeforrdp.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_optimizeforrdp.Name = "checkbox_optimizeforrdp";
|
||||
this.checkbox_optimizeforrdp.PropertyName = "OptimizeForRDP";
|
||||
this.checkbox_optimizeforrdp.PropertyName = nameof(coreConfiguration.OptimizeForRDP);
|
||||
this.checkbox_optimizeforrdp.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_optimizeforrdp.TabIndex = 4;
|
||||
this.checkbox_optimizeforrdp.Text = "Make some optimizations for usage with remote desktop";
|
||||
|
@ -1405,7 +1408,7 @@ namespace Greenshot.Forms {
|
|||
this.checkbox_autoreducecolors.Location = new System.Drawing.Point(8, 102);
|
||||
this.checkbox_autoreducecolors.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
|
||||
this.checkbox_autoreducecolors.Name = "checkbox_autoreducecolors";
|
||||
this.checkbox_autoreducecolors.PropertyName = "OutputFileAutoReduceColors";
|
||||
this.checkbox_autoreducecolors.PropertyName = nameof(coreConfiguration.OutputFileAutoReduceColors);
|
||||
this.checkbox_autoreducecolors.Size = new System.Drawing.Size(410, 20);
|
||||
this.checkbox_autoreducecolors.TabIndex = 3;
|
||||
this.checkbox_autoreducecolors.Text = "Create an 8-bit image if the colors are less than 256 while having a > 8 bits ima" +
|
||||
|
|
|
@ -37,7 +37,6 @@ using Greenshot.Base.Interfaces;
|
|||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Configuration;
|
||||
using Greenshot.Destinations;
|
||||
using Greenshot.Helpers;
|
||||
using log4net;
|
||||
|
||||
|
@ -320,7 +319,7 @@ namespace Greenshot.Forms
|
|||
combobox_language.SelectedValue = Language.CurrentLanguage;
|
||||
}
|
||||
|
||||
// Delaying the SelectedIndexChanged events untill all is initiated
|
||||
// Delaying the SelectedIndexChanged events until all is initiated
|
||||
combobox_language.SelectedIndexChanged += Combobox_languageSelectedIndexChanged;
|
||||
UpdateDestinationDescriptions();
|
||||
UpdateClipboardFormatDescriptions();
|
||||
|
@ -832,22 +831,19 @@ namespace Greenshot.Forms
|
|||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
if (!(x is ListViewItem))
|
||||
if (x is not ListViewItem listViewItemX)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(y is ListViewItem))
|
||||
if (y is not ListViewItem listViewItemY)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ListViewItem l1 = (ListViewItem) x;
|
||||
ListViewItem l2 = (ListViewItem) y;
|
||||
IDestination firstDestination = listViewItemX.Tag as IDestination;
|
||||
|
||||
IDestination firstDestination = l1.Tag as IDestination;
|
||||
|
||||
if (!(l2.Tag is IDestination secondDestination))
|
||||
if (listViewItemY.Tag is not IDestination secondDestination)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -430,12 +431,13 @@ namespace Greenshot.Helpers
|
|||
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
// TODO: Fix that the Greenshot format needs a separate code path
|
||||
try
|
||||
{
|
||||
if (filename.ToLower().EndsWith("." + OutputFormat.greenshot))
|
||||
{
|
||||
ISurface surface = new Surface();
|
||||
surface = ImageOutput.LoadGreenshotSurface(filename, surface);
|
||||
surface = ImageIO.LoadGreenshotSurface(filename, surface);
|
||||
surface.CaptureDetails = _capture.CaptureDetails;
|
||||
DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails);
|
||||
break;
|
||||
|
@ -447,9 +449,10 @@ namespace Greenshot.Helpers
|
|||
MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename));
|
||||
}
|
||||
|
||||
// TODO: Remove Image loading for here
|
||||
try
|
||||
{
|
||||
fileImage = ImageHelper.LoadImage(filename);
|
||||
fileImage = ImageIO.LoadImage(filename);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace Greenshot.Helpers
|
|||
/// <param name="captureDetails">ICaptureDetails</param>
|
||||
public static void SendImage(ISurface surface, ICaptureDetails captureDetails)
|
||||
{
|
||||
string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings());
|
||||
string tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings());
|
||||
|
||||
if (tmpFile == null) return;
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace Greenshot.Helpers
|
|||
|
||||
ApplyEffects(printOutputSettings);
|
||||
|
||||
bool disposeImage = ImageOutput.CreateImageFromSurface(_surface, printOutputSettings, out var image);
|
||||
bool disposeImage = ImageIO.CreateImageFromSurface(_surface, printOutputSettings, out var image);
|
||||
try
|
||||
{
|
||||
ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue