Feature Improve file format support (#385)

This feature will make it easier to support different file formats later on, and also adds a "VectorGraphicsContainer" base class to better support non pixel graphics in the editor. Examples are SVG, WMF/EMF and Emoji which scale automatically to the correct size and are not resized from pixels. Multiple new formats have been added for reading, Jpeg XR for writing.
This commit is contained in:
Robin Krom 2022-02-20 13:21:32 +01:00 committed by GitHub
commit 60956771c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 2793 additions and 1340 deletions

View file

@ -120,6 +120,7 @@ namespace Greenshot.Base.Controls
private void PrepareFilterOptions() private void PrepareFilterOptions()
{ {
// TODO: Change to the FileFormatHandlerRegistry to look for all the supported extensions
OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat));
_filterOptions = new FilterOption[supportedImageFormats.Length]; _filterOptions = new FilterOption[supportedImageFormats.Length];
for (int i = 0; i < _filterOptions.Length; i++) 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 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; if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn;
// otherwise we just add the selected filter item's extension // otherwise we just add the selected filter item's extension
else return fn + "." + Extension; return fn + "." + Extension;
} }
set set
{ {

View file

@ -31,8 +31,10 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.Enums;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using log4net; using log4net;
@ -63,7 +65,8 @@ namespace Greenshot.Base.Core
//private static readonly string FORMAT_HTML = "HTML Format"; //private static readonly string FORMAT_HTML = "HTML Format";
// Template for the HTML Text on the clipboard // 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 // or: https://msdn.microsoft.com/en-us/library/Aa767917.aspx
private const string HtmlClipboardString = @"Version:0.9 private const string HtmlClipboardString = @"Version:0.9
StartHTML:<<<<<<<1 StartHTML:<<<<<<<1
@ -298,14 +301,15 @@ EndSelection:<<<<<<<4
{ {
return true; return true;
} }
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
foreach (var fileData in IterateClipboardContent(dataObject)) var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
{ {
try 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; return true;
} }
} }
@ -315,7 +319,7 @@ EndSelection:<<<<<<<4
} }
finally finally
{ {
fileData?.Dispose(); stream?.Dispose();
} }
} }
@ -327,7 +331,8 @@ EndSelection:<<<<<<<4
var imageStream = clipboardContent as MemoryStream; var imageStream = clipboardContent as MemoryStream;
if (IsValidStream(imageStream)) 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 // If we get here, there is an image
return true; return true;
@ -373,8 +378,8 @@ EndSelection:<<<<<<<4
/// Iterate the clipboard content /// Iterate the clipboard content
/// </summary> /// </summary>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>IEnumerable{MemoryStream}</returns> /// <returns>IEnumerable{(MemoryStream,string)}</returns>
private static IEnumerable<MemoryStream> IterateClipboardContent(IDataObject dataObject) private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject)
{ {
var fileDescriptors = AvailableFileDescriptors(dataObject); var fileDescriptors = AvailableFileDescriptors(dataObject);
if (fileDescriptors == null) yield break; if (fileDescriptors == null) yield break;
@ -413,8 +418,8 @@ EndSelection:<<<<<<<4
/// </summary> /// </summary>
/// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param> /// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>IEnumerable{MemoryStream}</returns> /// <returns>IEnumerable{(MemoryStream stream, string filename)}</returns>
private static IEnumerable<MemoryStream> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject) private static IEnumerable<(MemoryStream stream, string filename)> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
{ {
if (fileDescriptors == null) if (fileDescriptors == null)
{ {
@ -445,7 +450,7 @@ EndSelection:<<<<<<<4
if (fileData?.Length > 0) if (fileData?.Length > 0)
{ {
fileData.Position = 0; fileData.Position = 0;
yield return fileData; yield return (fileData, fileDescriptor.FileName);
} }
fileIndex++; fileIndex++;
@ -490,7 +495,7 @@ EndSelection:<<<<<<<4
{ {
IDataObject clipboardData = GetDataObject(); IDataObject clipboardData = GetDataObject();
// Return the first image // Return the first image
foreach (Image clipboardImage in GetImages(clipboardData)) foreach (var clipboardImage in GetImages(clipboardData))
{ {
return clipboardImage; return clipboardImage;
} }
@ -503,24 +508,38 @@ EndSelection:<<<<<<<4
/// Returned images must be disposed by the calling code! /// Returned images must be disposed by the calling code!
/// </summary> /// </summary>
/// <param name="dataObject"></param> /// <param name="dataObject"></param>
/// <returns>IEnumerable of Image</returns> /// <returns>IEnumerable of Bitmap</returns>
public static IEnumerable<Image> GetImages(IDataObject dataObject) public static IEnumerable<Bitmap> GetImages(IDataObject dataObject)
{ {
// Get single image, this takes the "best" match // Get single image, this takes the "best" match
Image singleImage = GetImage(dataObject); Bitmap singleImage = GetImage(dataObject);
if (singleImage != null) if (singleImage != null)
{ {
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
yield return singleImage; yield return singleImage;
yield break;
} }
else
var 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; continue;
}
Bitmap bitmap = null;
try try
{ {
image = ImageHelper.FromStream(fileData); if (!fileFormatHandlers.TryLoadFromStream(stream, extension, out bitmap))
{
continue;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -529,31 +548,114 @@ EndSelection:<<<<<<<4
} }
finally finally
{ {
fileData?.Dispose(); stream?.Dispose();
} }
// If we get here, there is an image // If we get here, there is an image
yield return image; yield return bitmap;
} }
// check if files are supplied // check if files are supplied
foreach (string imageFile in GetImageFilenames(dataObject)) foreach (string imageFile in GetImageFilenames(dataObject))
{ {
Image returnImage = null; var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
try if (!supportedExtensions.Contains(extension))
{ {
returnImage = ImageHelper.LoadImage(imageFile); continue;
}
catch (Exception streamImageEx)
{
Log.Error("Problem retrieving Image from clipboard.", streamImageEx);
} }
if (returnImage != null) Bitmap bitmap = null;
using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
try
{ {
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); if (!fileFormatHandlers.TryLoadFromStream(fileStream, extension, out bitmap))
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,11 +664,11 @@ EndSelection:<<<<<<<4
/// </summary> /// </summary>
/// <param name="dataObject"></param> /// <param name="dataObject"></param>
/// <returns>Image or null</returns> /// <returns>Image or null</returns>
private static Image GetImage(IDataObject dataObject) private static Bitmap GetImage(IDataObject dataObject)
{
Image returnImage = null;
if (dataObject != null)
{ {
if (dataObject == null) return null;
Bitmap returnImage = null;
IList<string> formats = GetFormats(dataObject); IList<string> formats = GetFormats(dataObject);
string[] retrieveFormats; string[] retrieveFormats;
@ -608,21 +710,77 @@ EndSelection:<<<<<<<4
return returnImage; return returnImage;
} }
} }
return null;
}
/// <summary>
/// Get an IDrawableContainer from the IDataObject, don't check for FileDrop
/// </summary>
/// <param name="dataObject"></param>
/// <returns>Image or null</returns>
private static IDrawableContainer GetDrawable(IDataObject dataObject)
{
if (dataObject == null) return null;
IDrawableContainer returnImage = null;
IList<string> formats = GetFormats(dataObject);
string[] retrieveFormats;
// Found a weird bug, where PNG's from Outlook 2010 are clipped
// So I build some special logic to get the best format:
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
{
// Outlook ??
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
retrieveFormats = new[]
{
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
};
}
else
{
retrieveFormats = new[]
{
FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
};
}
foreach (string currentFormat in retrieveFormats)
{
if (formats != null && formats.Contains(currentFormat))
{
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
returnImage = GetDrawableForFormat(currentFormat, dataObject);
}
else
{
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
}
if (returnImage != null)
{
return returnImage;
}
} }
return null; return null;
} }
/// <summary> /// <summary>
/// Helper method to try to get an image in the specified format from the dataObject /// Helper method to try to get an Bitmap in the specified format from the dataObject
/// the DIB reader should solve some issues /// the DIB reader should solve some issues
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591 /// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
/// </summary> /// </summary>
/// <param name="format">string with the format</param> /// <param name="format">string with the format</param>
/// <param name="dataObject">IDataObject</param> /// <param name="dataObject">IDataObject</param>
/// <returns>Image or null</returns> /// <returns>Bitmap or null</returns>
private static Image GetImageForFormat(string format, IDataObject dataObject) private static Bitmap GetImageForFormat(string format, IDataObject dataObject)
{ {
Bitmap bitmap = null;
if (format == FORMAT_HTML) if (format == FORMAT_HTML)
{ {
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
@ -638,10 +796,10 @@ EndSelection:<<<<<<<4
var srcAttribute = imgNode.Attributes["src"]; var srcAttribute = imgNode.Attributes["src"];
var imageUrl = srcAttribute.Value; var imageUrl = srcAttribute.Value;
Log.Debug(imageUrl); Log.Debug(imageUrl);
var image = NetworkHelper.DownloadImage(imageUrl); bitmap = NetworkHelper.DownloadImage(imageUrl);
if (image != null) if (bitmap != null)
{ {
return image; return bitmap;
} }
} }
} }
@ -652,113 +810,82 @@ EndSelection:<<<<<<<4
var imageStream = clipboardObject as MemoryStream; var imageStream = clipboardObject as MemoryStream;
if (!IsValidStream(imageStream)) if (!IsValidStream(imageStream))
{ {
// TODO: add "HTML Format" support here... return clipboardObject as Bitmap;
return clipboardObject as Image; }
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
// From here, imageStream is a valid stream
if (!fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap))
{
return bitmap;
}
return null;
} }
if (CoreConfig.EnableSpecialDIBClipboardReader) /// <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)
{ {
if (format == FORMAT_17 || format == DataFormats.Dib) IDrawableContainer drawableContainer = null;
{
Log.Info("Found DIB stream, trying to process it.");
try
{
if (imageStream != null)
{
byte[] dibBuffer = new byte[imageStream.Length];
_ = imageStream.Read(dibBuffer, 0, dibBuffer.Length);
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADERV5>(dibBuffer);
if (!infoHeader.IsDibV5)
{
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
uint infoHeaderSize = infoHeader.biSize;
int fileSize = (int) (fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
var fileHeader = new BITMAPFILEHEADER if (format == FORMAT_HTML)
{ {
bfType = BITMAPFILEHEADER.BM, var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
bfSize = fileSize, if (textObject != null)
bfReserved1 = 0, {
bfReserved2 = 0, var doc = new HtmlDocument();
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4) doc.LoadHtml(textObject);
}; var imgNodes = doc.DocumentNode.SelectNodes("//img");
if (imgNodes != null)
{
foreach (var imgNode in imgNodes)
{
var srcAttribute = imgNode.Attributes["src"];
var imageUrl = srcAttribute.Value;
Log.Debug(imageUrl);
drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl);
if (drawableContainer != null)
{
return drawableContainer;
}
}
}
}
}
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); object clipboardObject = GetFromDataObject(dataObject, format);
var imageStream = clipboardObject as MemoryStream;
using var bitmapStream = new MemoryStream(); if (!IsValidStream(imageStream))
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); {
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); // TODO: add text based, like "HTML Format" support here...
bitmapStream.Seek(0, SeekOrigin.Begin); // TODO: solve the issue that we do not have a factory for the ImageContainer
var image = ImageHelper.FromStream(bitmapStream); /*var image = clipboardObject as Image;
if (image != null) if (image != null)
{ {
return image; return new ImageContainer(this)
}
}
else
{ {
Log.Info("Using special DIBV5 / Format17 format reader"); Image = image,
// CF_DIBV5 Left = x,
IntPtr gcHandle = IntPtr.Zero; Top = y
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) return clipboardObject as Image;
{ */
Log.Error("Problem retrieving Format17 from clipboard.", ex);
}
finally
{
if (gcHandle == IntPtr.Zero)
{
GCHandle.FromIntPtr(gcHandle).Free();
}
}
}
}
}
catch (Exception dibEx)
{
Log.Error("Problem retrieving DIB from clipboard.", dibEx);
}
}
}
else
{
Log.Info("Skipping special DIB format reader as it's disabled in the configuration.");
}
try
{
if (imageStream != null)
{
imageStream.Seek(0, SeekOrigin.Begin);
var tmpImage = ImageHelper.FromStream(imageStream);
if (tmpImage != null)
{
Log.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
return tmpImage;
}
}
}
catch (Exception streamImageEx)
{
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
}
return null; return null;
} }
// From here, imageStream is a valid stream
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
return fileFormatHandlers.LoadDrawablesFromStream(imageStream, format).FirstOrDefault();
}
/// <summary> /// <summary>
/// Get Text from the DataObject /// Get Text from the DataObject
/// </summary> /// </summary>
@ -840,7 +967,7 @@ EndSelection:<<<<<<<4
{ {
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); 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 // 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 try
{ {
// Create PNG stream // Create PNG stream
@ -849,7 +976,7 @@ EndSelection:<<<<<<<4
pngStream = new MemoryStream(); pngStream = new MemoryStream();
// PNG works for e.g. Powerpoint // PNG works for e.g. Powerpoint
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); 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); pngStream.Seek(0, SeekOrigin.Begin);
// Set the PNG stream // Set the PNG stream
dataObject.SetData(FORMAT_PNG, false, pngStream); dataObject.SetData(FORMAT_PNG, false, pngStream);
@ -866,13 +993,20 @@ EndSelection:<<<<<<<4
{ {
// Create the stream for the clipboard // Create the stream for the clipboard
dibStream = new MemoryStream(); dibStream = new MemoryStream();
var dibBytes = ((Bitmap)imageToSave).ConvertToDib(); var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
dibStream.Write(dibBytes,0, dibBytes.Length);
if (!fileFormatHandlers.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib))
{
dibStream.Dispose();
dibStream = null;
}
else
{
// Set the DIB to the clipboard DataObject // Set the DIB to the clipboard DataObject
dataObject.SetData(DataFormats.Dib, false, dibStream); dataObject.SetData(DataFormats.Dib, false, dibStream);
} }
} }
}
catch (Exception dibEx) catch (Exception dibEx)
{ {
Log.Error("Error creating DIB for the Clipboard.", dibEx); Log.Error("Error creating DIB for the Clipboard.", dibEx);
@ -924,7 +1058,7 @@ EndSelection:<<<<<<<4
// Set the HTML // Set the HTML
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.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); string html = GetHtmlString(surface, tmpFile);
dataObject.SetText(html, TextDataFormat.Html); dataObject.SetText(html, TextDataFormat.Html);
} }
@ -942,11 +1076,11 @@ EndSelection:<<<<<<<4
// Check if we can use the previously used image // Check if we can use the previously used image
if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed)
{ {
ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); ImageIO.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
} }
else else
{ {
ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); ImageIO.SaveToStream(surface, tmpPngStream, pngOutputSettings);
} }
html = GetHtmlDataUrlString(surface, tmpPngStream); html = GetHtmlDataUrlString(surface, tmpPngStream);
@ -1125,15 +1259,15 @@ EndSelection:<<<<<<<4
public static IEnumerable<string> GetImageFilenames(IDataObject dataObject) public static IEnumerable<string> GetImageFilenames(IDataObject dataObject)
{ {
string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop); string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop);
if (dropFileNames != null && dropFileNames.Length > 0) if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty<string>();
{ var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
return dropFileNames return dropFileNames
.Where(filename => !string.IsNullOrEmpty(filename)) .Where(filename => !string.IsNullOrEmpty(filename))
.Where(Path.HasExtension) .Where(Path.HasExtension)
.Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); .Where(filename => supportedExtensions.Contains(Path.GetExtension(filename)));
}
return Enumerable.Empty<string>();
} }
/// <summary> /// <summary>

View file

@ -0,0 +1,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,
}
}

View file

@ -31,6 +31,7 @@ namespace Greenshot.Base.Core.Enums
jpg, jpg,
png, png,
tiff, tiff,
jxr,
greenshot, greenshot,
ico ico
} }

View file

@ -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);
}
}
}

View file

@ -61,7 +61,7 @@ namespace Greenshot.Base.Core
float HorizontalResolution { get; } float HorizontalResolution { get; }
/// <summary> /// <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> /// </summary>
Image Image { get; } Image Image { get; }
} }

View file

@ -24,28 +24,24 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging; 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.Effects;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using log4net; 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 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> /// <summary>
/// Description of ImageHelper. /// Description of ImageHelper.
/// </summary> /// </summary>
@ -55,83 +51,6 @@ namespace Greenshot.Base.Core
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
private const int ExifOrientationId = 0x0112; 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> /// <summary>
/// Make sure the image is orientated correctly /// Make sure the image is orientated correctly
@ -371,127 +290,6 @@ namespace Greenshot.Base.Core
return cropRectangle; 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> /// <summary>
/// Apply the effect to the bitmap /// Apply the effect to the bitmap
/// </summary> /// </summary>
@ -563,8 +361,7 @@ namespace Greenshot.Base.Core
/// <returns>Changed bitmap</returns> /// <returns>Changed bitmap</returns>
public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) 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, Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
sourceImage.VerticalResolution);
using (var path = new GraphicsPath()) using (var path = new GraphicsPath())
{ {
Random random = new Random(); Random random = new Random();
@ -1396,7 +1193,7 @@ namespace Greenshot.Base.Core
} }
// If no pixelformat is supplied // If no pixelformat is supplied
if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) if (targetFormat is PixelFormat.DontCare or PixelFormat.Undefined)
{ {
if (SupportsPixelFormat(sourceImage.PixelFormat)) if (SupportsPixelFormat(sourceImage.PixelFormat))
{ {
@ -1517,10 +1314,10 @@ namespace Greenshot.Base.Core
/// <param name="height"></param> /// <param name="height"></param>
/// <param name="format"></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="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="horizontalResolution">float</param>
/// <param name="verticalResolution"></param> /// <param name="verticalResolution">float</param>
/// <returns>Bitmap</returns> /// <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 // Create a new "clean" image
Bitmap newImage = new Bitmap(width, height, format); Bitmap newImage = new Bitmap(width, height, format);
@ -1711,98 +1508,106 @@ namespace Greenshot.Base.Core
} }
/// <summary> /// <summary>
/// Load a Greenshot surface from a stream /// Rotate the image
/// </summary> /// </summary>
/// <param name="surfaceFileStream">Stream</param> /// <param name="image">Input image</param>
/// <param name="returnSurface"></param> /// <param name="rotationAngle">Angle in degrees</param>
/// <returns>ISurface</returns> /// <returns>Rotated image</returns>
public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) public static Image Rotate(this Image image, float rotationAngle)
{ {
Image fileImage; var bitmap = CreateEmptyLike(image, Color.Transparent);
// 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 using var graphics = Graphics.FromImage(bitmap);
surfaceFileStream.Position = 0; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
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);
}
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2);
const int markerSize = 14; graphics.RotateTransform(rotationAngle);
surfaceFileStream.Seek(-markerSize, SeekOrigin.End); graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2);
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); graphics.DrawImage(image, new Point(0, 0));
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) return bitmap;
{
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;
} }
/// <summary> /// <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> /// </summary>
/// <param name="stream">Stream</param> /// <param name="pixelFormat">System.Drawing.Imaging.PixelFormat</param>
/// <param name="extension"></param> /// <returns>System.Windows.Media.PixelFormat</returns>
/// <returns>Image</returns> /// <exception cref="NotSupportedException"></exception>
public static Image FromStream(Stream stream, string extension = null) public static System.Windows.Media.PixelFormat Map(this PixelFormat pixelFormat) =>
pixelFormat switch
{ {
if (stream == null) 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)
{ {
return null; if (pixelFormat == PixelFormats.Bgra32)
{
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}.");
{
extension = extension.Replace(".", string.Empty);
} }
// Make sure we can try multiple times /// <summary>
if (!stream.CanSeek) /// Convert a Bitmap to a BitmapSource
/// </summary>
/// <param name="bitmap">Bitmap</param>
/// <returns>BitmapSource</returns>
public static BitmapSource ToBitmapSource(this Bitmap bitmap)
{ {
var memoryStream = new MemoryStream(); var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
stream.CopyTo(memoryStream);
stream = memoryStream; BitmapSource bitmapSource;
try
{
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);
} }
Image returnImage = null; return bitmapSource;
if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter))
{
returnImage = converter(stream, extension);
} }
// Fallback /// <summary>
if (returnImage == null) /// Convert a BitmapSource to a Bitmap
/// </summary>
/// <param name="bitmapSource">BitmapSource</param>
/// <returns>Bitmap</returns>
public static Bitmap ToBitmap(this BitmapSource bitmapSource)
{ {
// We create a copy of the bitmap, so everything else can be disposed var pixelFormat = bitmapSource.Format.Map();
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;
} }
} }
} }

View file

@ -20,12 +20,11 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -33,20 +32,21 @@ using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Controls; using Greenshot.Base.Controls;
using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.Enums;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers;
using log4net; using log4net;
using Encoder = System.Drawing.Imaging.Encoder;
namespace Greenshot.Base.Core namespace Greenshot.Base.Core
{ {
/// <summary> /// <summary>
/// Description of ImageOutput. /// Description of ImageOutput.
/// </summary> /// </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 CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131;
private static readonly Cache<string, string> TmpFileCache = new Cache<string, string>(10 * 60 * 60, RemoveExpiredTmpFile); private static readonly Cache<string, string> TmpFileCache = new Cache<string, string>(10 * 60 * 60, RemoveExpiredTmpFile);
@ -54,7 +54,7 @@ namespace Greenshot.Base.Core
/// <summary> /// <summary>
/// Creates a PropertyItem (Metadata) to store with the image. /// 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 /// 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> /// </summary>
/// <param name="id">ID</param> /// <param name="id">ID</param>
/// <param name="text">Text</param> /// <param name="text">Text</param>
@ -124,102 +124,21 @@ namespace Greenshot.Base.Core
try try
{ {
var imageFormat = outputSettings.Format switch // Check if we want to use a memory stream, to prevent issues with non seekable streams
{
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
// The save is made to the targetStream, this is directed to either the MemoryStream or the original // The save is made to the targetStream, this is directed to either the MemoryStream or the original
Stream targetStream = stream; Stream targetStream = stream;
if (!stream.CanSeek) if (!stream.CanSeek)
{ {
useMemoryStream = true; 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(); memoryStream = new MemoryStream();
targetStream = 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; return;
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();
}
} }
// If we used a memory stream, we need to stream the memory stream to the original stream. // 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); 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 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> /// <summary>
/// Create an image from a surface with the settings from the output settings applied /// Create an image from a surface with the settings from the output settings applied
/// </summary> /// </summary>
@ -429,12 +250,11 @@ namespace Greenshot.Base.Core
/// Add the greenshot property! /// Add the greenshot property!
/// </summary> /// </summary>
/// <param name="imageToSave"></param> /// <param name="imageToSave"></param>
private static void AddTag(Image imageToSave) public static void AddTag(this Image imageToSave)
{ {
// Create meta-data // Create meta-data
PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot");
if (softwareUsedPropertyItem != null) if (softwareUsedPropertyItem == null) return;
{
try try
{ {
imageToSave.SetPropertyItem(softwareUsedPropertyItem); imageToSave.SetPropertyItem(softwareUsedPropertyItem);
@ -444,7 +264,6 @@ namespace Greenshot.Base.Core
Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
} }
} }
}
/// <summary> /// <summary>
/// Load a Greenshot surface /// Load a Greenshot surface
@ -463,7 +282,7 @@ namespace Greenshot.Base.Core
// Fixed lock problem Bug #3431881 // Fixed lock problem Bug #3431881
using (Stream surfaceFileStream = File.OpenRead(fullPath)) using (Stream surfaceFileStream = File.OpenRead(fullPath))
{ {
returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); returnSurface = LoadGreenshotSurface(surfaceFileStream, returnSurface);
} }
if (returnSurface != null) if (returnSurface != null)
@ -547,8 +366,7 @@ namespace Greenshot.Base.Core
using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails))
{ {
DialogResult dialogResult = saveImageFileDialog.ShowDialog(); DialogResult dialogResult = saveImageFileDialog.ShowDialog();
if (dialogResult.Equals(DialogResult.OK)) if (!dialogResult.Equals(DialogResult.OK)) return returnValue;
{
try try
{ {
string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension;
@ -569,7 +387,6 @@ namespace Greenshot.Base.Core
MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error"));
} }
} }
}
return returnValue; return returnValue;
} }
@ -709,91 +526,218 @@ namespace Greenshot.Base.Core
} }
/// <summary> /// <summary>
/// Write the images to the stream as icon /// Load an image from file
/// Every image is resized to 256x256 (but the content maintains the aspect ratio)
/// </summary> /// </summary>
/// <param name="stream">Stream to write to</param> /// <param name="filename"></param>
/// <param name="images">List of images</param> /// <returns></returns>
public static void WriteIcon(Stream stream, IList<Image> images) public static Image LoadImage(string filename)
{ {
var binaryWriter = new BinaryWriter(stream); if (string.IsNullOrEmpty(filename))
// {
// ICONDIR structure return null;
// }
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>(); if (!File.Exists(filename))
IList<MemoryStream> encodedImages = new List<MemoryStream>();
foreach (var image in images)
{ {
// Pick the best fit return null;
var sizes = new[] }
Image fileImage;
Log.InfoFormat("Loading image from file {0}", filename);
// Fixed lock problem Bug #3431881
using (Stream imageFileStream = File.OpenRead(filename))
{ {
16, 32, 48 fileImage = FromStream(imageFileStream, Path.GetExtension(filename));
}; }
int size = 256;
foreach (var possibleSize in sizes) if (fileImage != null)
{ {
if (image.Width <= possibleSize && image.Height <= possibleSize) 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)
{ {
size = possibleSize; 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; break;
} }
} }
}
var imageStream = new MemoryStream(); catch
if (image.Width == size && image.Height == size)
{ {
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); return null;
clonedImage.Save(imageStream, ImageFormat.Png);
imageSizes.Add(new Size(size, size));
} }
else
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)
{ {
// Resize to the specified size, first make sure the image is 32bpp Shell32.ExtractIconEx(location, index, out var large, out var small, 1);
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); Icon returnIcon = null;
using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); bool isLarge = false;
resizedImage.Save(imageStream, ImageFormat.Png); bool isSmall = false;
imageSizes.Add(resizedImage.Size); try
}
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]; if (takeLarge && !IntPtr.Zero.Equals(large))
// Write the width / height, 0 means 256 {
binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); returnIcon = Icon.FromHandle(large);
binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); isLarge = true;
binaryWriter.Write((byte) 0); // no pallete }
binaryWriter.Write((byte) 0); // reserved else if (!IntPtr.Zero.Equals(small))
binaryWriter.Write((short) 0); // no color planes {
binaryWriter.Write((short) 32); // 32 bpp returnIcon = Icon.FromHandle(small);
binaryWriter.Write((int) encodedImages[i].Length); // image data length isSmall = true;
binaryWriter.Write(offset); }
offset += (int) encodedImages[i].Length; else if (!IntPtr.Zero.Equals(large))
{
returnIcon = Icon.FromHandle(large);
isLarge = true;
}
}
finally
{
if (isLarge && !IntPtr.Zero.Equals(small))
{
User32.DestroyIcon(small);
} }
binaryWriter.Flush(); if (isSmall && !IntPtr.Zero.Equals(large))
//
// Write image data
//
foreach (var encodedImage in encodedImages)
{ {
encodedImage.WriteTo(stream); User32.DestroyIcon(large);
encodedImage.Dispose(); }
} }
return returnIcon;
}
/// <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)
{
return null;
}
if (!string.IsNullOrEmpty(extension))
{
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;
} }
} }
} }

View file

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

View file

@ -24,11 +24,14 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using log4net; using log4net;
@ -87,24 +90,14 @@ namespace Greenshot.Base.Core
} }
/// <summary> /// <summary>
/// Download the uri to Bitmap /// Download the uri to build an IDrawableContainer
/// </summary> /// </summary>
/// <param name="url">Of an image</param> /// <param name="url">Of an image</param>
/// <returns>Bitmap</returns> /// <returns>IDrawableContainer</returns>
public static Image DownloadImage(string url) public static IDrawableContainer DownloadImageAsDrawableContainer(string url)
{ {
var extensions = new StringBuilder(); var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
foreach (var extension in ImageHelper.StreamConverters.Keys) var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
{
if (string.IsNullOrEmpty(extension))
{
continue;
}
extensions.AppendFormat(@"\.{0}|", extension);
}
extensions.Length--;
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})"); var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
var match = imageUrlRegex.Match(url); var match = imageUrlRegex.Match(url);
@ -113,7 +106,12 @@ namespace Greenshot.Base.Core
using var memoryStream = GetAsMemoryStream(url); using var memoryStream = GetAsMemoryStream(url);
try try
{ {
return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); var extension = match.Success ? match.Groups["extension"]?.Value : null;
var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream, extension).FirstOrDefault();
if (drawableContainer != null)
{
return drawableContainer;
}
} }
catch (Exception) catch (Exception)
{ {
@ -136,7 +134,71 @@ namespace Greenshot.Base.Core
} }
using var memoryStream2 = GetAsMemoryStream(match.Value); 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) catch (Exception e)
@ -670,7 +732,7 @@ namespace Greenshot.Base.Core
public string ToBase64String(Base64FormattingOptions formattingOptions) public string ToBase64String(Base64FormattingOptions formattingOptions)
{ {
using MemoryStream stream = new MemoryStream(); 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); return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions);
} }
@ -682,7 +744,7 @@ namespace Greenshot.Base.Core
public byte[] ToByteArray() public byte[] ToByteArray()
{ {
using MemoryStream stream = new MemoryStream(); using MemoryStream stream = new MemoryStream();
ImageOutput.SaveToStream(_surface, stream, _outputSettings); ImageIO.SaveToStream(_surface, stream, _outputSettings);
return stream.ToArray(); 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"; 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)); formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); ImageIO.SaveToStream(_surface, formDataStream, _outputSettings);
} }
/// <summary> /// <summary>
@ -708,7 +770,7 @@ namespace Greenshot.Base.Core
public void WriteToStream(Stream dataStream) public void WriteToStream(Stream dataStream)
{ {
// Write the file data directly to the Stream, rather than serializing it to a string. // 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> /// <summary>

View file

@ -158,7 +158,7 @@ namespace Greenshot.Base.Core
try try
{ {
using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) using (Icon appIcon = ImageIO.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons))
{ {
if (appIcon != null) if (appIcon != null)
{ {

View file

@ -10,22 +10,19 @@ namespace Greenshot.Base.Core
/// </summary> /// </summary>
public class SimpleServiceProvider : IServiceLocator 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 static IServiceLocator Current { get; } = new SimpleServiceProvider();
public IEnumerable<TService> GetAllInstances<TService>() public IReadOnlyList<TService> GetAllInstances<TService>()
{ {
var typeOfService = typeof(TService); var typeOfService = typeof(TService);
if (!_services.TryGetValue(typeOfService, out var results)) if (!_services.TryGetValue(typeOfService, out var results))
{ {
yield break; return Array.Empty<TService>();
} }
foreach (TService result in results) return results.Cast<TService>().ToArray();
{
yield return result;
}
} }
public TService GetInstance<TService>() public TService GetInstance<TService>()

View file

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

View file

@ -782,7 +782,9 @@ namespace Greenshot.Base.Core
/// </summary> /// </summary>
public WindowStyleFlags WindowStyle 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)); set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value));
} }

View file

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

View file

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

View 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);
}
}

View file

@ -32,7 +32,7 @@ namespace Greenshot.Base.Interfaces
/// </summary> /// </summary>
/// <typeparam name="TService">Service to find</typeparam> /// <typeparam name="TService">Service to find</typeparam>
/// <returns>IEnumerable{TService}</returns> /// <returns>IEnumerable{TService}</returns>
IEnumerable<TService> GetAllInstances<TService>(); IReadOnlyList<TService> GetAllInstances<TService>();
/// <summary> /// <summary>
/// Get the only instance of the specified service /// Get the only instance of the specified service

View file

@ -21,6 +21,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Core; using Greenshot.Base.Core;
@ -201,5 +202,14 @@ namespace Greenshot.Base.Interfaces
Rectangle ToImageCoordinates(Rectangle rc); Rectangle ToImageCoordinates(Rectangle rc);
void MakeUndoable(IMemento memento, bool allowMerge); 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);
} }
} }

View file

@ -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;
using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.Enums;
using Greenshot.Base.Effects; using Greenshot.Base.Effects;

View file

@ -32,7 +32,7 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums
public enum WindowStyleFlags : int public enum WindowStyleFlags : int
{ {
//WS_OVERLAPPED = 0x00000000, //WS_OVERLAPPED = 0x00000000,
WS_POPUP = -2147483648, WS_POPUP = -2147483648, // 0x80000000
WS_CHILD = 0x40000000, WS_CHILD = 0x40000000,
WS_MINIMIZE = 0x20000000, WS_MINIMIZE = 0x20000000,
WS_VISIBLE = 0x10000000, WS_VISIBLE = 0x10000000,

View file

@ -127,7 +127,7 @@ namespace Greenshot.Base.UnmanagedHelpers
public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] [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")] [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")]
public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
@ -276,17 +276,15 @@ namespace Greenshot.Base.UnmanagedHelpers
/// <param name="hWnd"></param> /// <param name="hWnd"></param>
/// <param name="nIndex"></param> /// <param name="nIndex"></param>
/// <returns></returns> /// <returns></returns>
public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) public static IntPtr GetWindowLongWrapper(IntPtr hWnd, int nIndex)
{ {
if (IntPtr.Size == 8) if (IntPtr.Size == 8)
{ {
return GetWindowLongPtr(hWnd, nIndex).ToInt64(); return GetWindowLongPtr(hWnd, nIndex);
} }
else
{
return GetWindowLong(hWnd, nIndex); return GetWindowLong(hWnd, nIndex);
} }
}
/// <summary> /// <summary>
/// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one.

View file

@ -22,6 +22,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
@ -43,7 +44,7 @@ namespace Greenshot.Editor.Drawing
private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6);
public ArrowContainer(Surface parent) : base(parent) public ArrowContainer(ISurface parent) : base(parent)
{ {
} }

View file

@ -21,6 +21,7 @@
using System.Drawing; using System.Drawing;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -32,7 +33,7 @@ namespace Greenshot.Editor.Drawing
/// </summary> /// </summary>
public class CropContainer : DrawableContainer public class CropContainer : DrawableContainer
{ {
public CropContainer(Surface parent) : base(parent) public CropContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -25,6 +25,7 @@ using System.Drawing.Drawing2D;
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using log4net; using log4net;
@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing
protected Cursor cursor; protected Cursor cursor;
public CursorContainer(Surface parent) : base(parent) public CursorContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }
@ -56,7 +57,7 @@ namespace Greenshot.Editor.Drawing
CreateDefaultAdorners(); CreateDefaultAdorners();
} }
public CursorContainer(Surface parent, string filename) : this(parent) public CursorContainer(ISurface parent, string filename) : this(parent)
{ {
Load(filename); Load(filename);
} }

View file

@ -126,12 +126,17 @@ namespace Greenshot.Editor.Drawing
} }
} }
[NonSerialized] internal Surface _parent; [NonSerialized] internal ISurface _parent;
public ISurface Parent public ISurface Parent
{ {
get => _parent; get => _parent;
set => SwitchParent((Surface) value); set => SwitchParent(value);
}
protected Surface InternalParent
{
get => (Surface)_parent;
} }
[NonSerialized] private TargetAdorner _targetAdorner; [NonSerialized] private TargetAdorner _targetAdorner;
@ -277,7 +282,7 @@ namespace Greenshot.Editor.Drawing
Height = Round(newBounds.Height); Height = Round(newBounds.Height);
} }
public DrawableContainer(Surface parent) public DrawableContainer(ISurface parent)
{ {
InitializeFields(); InitializeFields();
_parent = parent; _parent = parent;
@ -505,7 +510,7 @@ namespace Greenshot.Editor.Drawing
{ {
Invalidate(); Invalidate();
// reset "workrbench" rectangle to current bounds // reset "workbench" rectangle to current bounds
_boundsAfterResize.X = _boundsBeforeResize.Left; _boundsAfterResize.X = _boundsBeforeResize.Left;
_boundsAfterResize.Y = _boundsBeforeResize.Top; _boundsAfterResize.Y = _boundsBeforeResize.Top;
_boundsAfterResize.Width = x - _boundsAfterResize.Left; _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) if (newParent == Parent)
{ {

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing
[Serializable()] [Serializable()]
public class EllipseContainer : DrawableContainer public class EllipseContainer : DrawableContainer
{ {
public EllipseContainer(Surface parent) : base(parent) public EllipseContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -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. /// If the property values of the selected elements differ, the value of the last bound element wins.
/// </summary> /// </summary>
[Serializable] [Serializable]
public sealed class FieldAggregator : AbstractFieldHolder public sealed class FieldAggregator : AbstractFieldHolder, IFieldAggregator
{ {
private readonly IDrawableContainerList _boundContainers; private readonly IDrawableContainerList _boundContainers;
private bool _internalUpdateRunning; private bool _internalUpdateRunning;
@ -117,12 +117,11 @@ namespace Greenshot.Editor.Drawing.Fields
public void UnbindElement(IDrawableContainer dc) public void UnbindElement(IDrawableContainer dc)
{ {
if (_boundContainers.Contains(dc)) if (!_boundContainers.Contains(dc)) return;
{
_boundContainers.Remove(dc); _boundContainers.Remove(dc);
UpdateFromBoundElements(); UpdateFromBoundElements();
} }
}
public void Clear() public void Clear()
{ {

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -51,7 +52,7 @@ namespace Greenshot.Editor.Drawing
MAGNIFICATION MAGNIFICATION
}; };
public FilterContainer(Surface parent) : base(parent) public FilterContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -24,6 +24,7 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -50,7 +51,7 @@ namespace Greenshot.Editor.Drawing
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public FreehandContainer(Surface parent) : base(parent) public FreehandContainer(ISurface parent) : base(parent)
{ {
Width = parent.Image.Width; Width = parent.Image.Width;
Height = parent.Image.Height; Height = parent.Image.Height;

View file

@ -21,6 +21,7 @@
using System; using System;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Drawing.Filters; using Greenshot.Editor.Drawing.Filters;
@ -33,7 +34,7 @@ namespace Greenshot.Editor.Drawing
[Serializable] [Serializable]
public class HighlightContainer : FilterContainer public class HighlightContainer : FilterContainer
{ {
public HighlightContainer(Surface parent) : base(parent) public HighlightContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -24,6 +24,7 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.IO; using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using log4net; using log4net;
@ -39,7 +40,7 @@ namespace Greenshot.Editor.Drawing
protected Icon icon; protected Icon icon;
public IconContainer(Surface parent) : base(parent) public IconContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }
@ -55,11 +56,16 @@ namespace Greenshot.Editor.Drawing
CreateDefaultAdorners(); CreateDefaultAdorners();
} }
public IconContainer(Surface parent, string filename) : base(parent) public IconContainer(ISurface parent, string filename) : base(parent)
{ {
Load(filename); Load(filename);
} }
public IconContainer(ISurface parent, Stream stream) : base(parent)
{
Load(stream);
}
public Icon Icon public Icon Icon
{ {
set set
@ -99,6 +105,18 @@ namespace Greenshot.Editor.Drawing
Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
} }
public void Load(Stream iconStream)
{
if (iconStream == null)
{
return;
}
using Icon fileIcon = new Icon(iconStream);
Icon = fileIcon;
Log.Debug("Loaded stream: with resolution: " + Height + "," + Width);
}
public override void Draw(Graphics graphics, RenderMode rm) public override void Draw(Graphics graphics, RenderMode rm)
{ {
if (icon == null) if (icon == null)

View file

@ -26,6 +26,7 @@ using System.IO;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Core; using Greenshot.Base.Core;
using Greenshot.Base.Effects; using Greenshot.Base.Effects;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using log4net; using log4net;
@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing
{ {
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer));
private Image image; private Image _image;
/// <summary> /// <summary>
/// This is the shadow version of the bitmap, rendered once to save performance /// This is the shadow version of the bitmap, rendered once to save performance
@ -54,12 +55,12 @@ namespace Greenshot.Editor.Drawing
/// </summary> /// </summary>
[NonSerialized] private Point _shadowOffset = new Point(-1, -1); [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); Load(filename);
} }
public ImageContainer(Surface parent) : base(parent) public ImageContainer(ISurface parent) : base(parent)
{ {
FieldChanged += BitmapContainer_OnFieldChanged; FieldChanged += BitmapContainer_OnFieldChanged;
Init(); Init();
@ -107,8 +108,8 @@ namespace Greenshot.Editor.Drawing
} }
else else
{ {
Width = image.Width; Width = _image.Width;
Height = image.Height; Height = _image.Height;
if (_shadowBitmap != null) if (_shadowBitmap != null)
{ {
Left += _shadowOffset.X; Left += _shadowOffset.X;
@ -124,13 +125,13 @@ namespace Greenshot.Editor.Drawing
// Remove all current bitmaps // Remove all current bitmaps
DisposeImage(); DisposeImage();
DisposeShadow(); DisposeShadow();
image = ImageHelper.Clone(value); _image = ImageHelper.Clone(value);
bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool shadow = GetFieldValueAsBool(FieldType.SHADOW);
CheckShadow(shadow); CheckShadow(shadow);
if (!shadow) if (!shadow)
{ {
Width = image.Width; Width = _image.Width;
Height = image.Height; Height = _image.Height;
} }
else else
{ {
@ -140,7 +141,7 @@ namespace Greenshot.Editor.Drawing
Top -= _shadowOffset.Y; Top -= _shadowOffset.Y;
} }
} }
get { return image; } get { return _image; }
} }
/// <summary> /// <summary>
@ -162,8 +163,8 @@ namespace Greenshot.Editor.Drawing
private void DisposeImage() private void DisposeImage()
{ {
image?.Dispose(); _image?.Dispose();
image = null; _image = null;
} }
private void DisposeShadow() private void DisposeShadow()
@ -186,9 +187,9 @@ namespace Greenshot.Editor.Drawing
Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
DisposeShadow(); DisposeShadow();
using var tmpMatrix = new Matrix(); 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, // Always make sure ImageHelper.LoadBitmap results are disposed some time,
// as we close the bitmap internally, we need to do it afterwards // 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; Image = tmpImage;
} }
@ -228,7 +230,7 @@ namespace Greenshot.Editor.Drawing
} }
using var matrix = new Matrix(); using var matrix = new Matrix();
_shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); _shadowBitmap = ImageHelper.ApplyEffect(_image, new DropShadowEffect(), matrix);
} }
/// <summary> /// <summary>
@ -238,7 +240,7 @@ namespace Greenshot.Editor.Drawing
/// <param name="rm"></param> /// <param name="rm"></param>
public override void Draw(Graphics graphics, RenderMode rm) public override void Draw(Graphics graphics, RenderMode rm)
{ {
if (image == null) if (_image == null)
{ {
return; return;
} }
@ -256,12 +258,12 @@ namespace Greenshot.Editor.Drawing
} }
else else
{ {
graphics.DrawImage(image, Bounds); graphics.DrawImage(_image, Bounds);
} }
} }
public override bool HasDefaultSize => true; 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);
} }
} }

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Adorners; using Greenshot.Editor.Drawing.Adorners;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
@ -36,7 +37,7 @@ namespace Greenshot.Editor.Drawing
[Serializable()] [Serializable()]
public class LineContainer : DrawableContainer public class LineContainer : DrawableContainer
{ {
public LineContainer(Surface parent) : base(parent) public LineContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View 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);
}
}

View file

@ -21,6 +21,7 @@
using System; using System;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Drawing.Filters; using Greenshot.Editor.Drawing.Filters;
@ -28,12 +29,12 @@ using Greenshot.Editor.Drawing.Filters;
namespace Greenshot.Editor.Drawing namespace Greenshot.Editor.Drawing
{ {
/// <summary> /// <summary>
/// Description of ObfuscateContainer. /// This is a FilterContainer for the obfuscator filters like blur and pixelate.
/// </summary> /// </summary>
[Serializable] [Serializable]
public class ObfuscateContainer : FilterContainer public class ObfuscateContainer : FilterContainer
{ {
public ObfuscateContainer(Surface parent) : base(parent) public ObfuscateContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -23,6 +23,7 @@ using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing
[Serializable] [Serializable]
public class RectangleContainer : DrawableContainer public class RectangleContainer : DrawableContainer
{ {
public RectangleContainer(Surface parent) : base(parent) public RectangleContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }

View file

@ -24,6 +24,7 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Text; using System.Drawing.Text;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -64,8 +65,7 @@ namespace Greenshot.Editor.Drawing
InitAdorner(Color.Green, _storedTargetGripperLocation); InitAdorner(Color.Green, _storedTargetGripperLocation);
} }
public SpeechbubbleContainer(Surface parent) public SpeechbubbleContainer(ISurface parent) : base(parent)
: base(parent)
{ {
} }

View file

@ -24,6 +24,7 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Text; using System.Drawing.Text;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -41,9 +42,9 @@ namespace Greenshot.Editor.Drawing
private readonly bool _drawAsRectangle = false; private readonly bool _drawAsRectangle = false;
public StepLabelContainer(Surface parent) : base(parent) public StepLabelContainer(ISurface parent) : base(parent)
{ {
parent.AddStepLabel(this); InternalParent?.AddStepLabel(this);
InitContent(); InitContent();
Init(); Init();
} }
@ -72,11 +73,10 @@ namespace Greenshot.Editor.Drawing
[OnSerializing] [OnSerializing]
private void SetValuesOnSerializing(StreamingContext context) private void SetValuesOnSerializing(StreamingContext context)
{ {
if (Parent != null) if (InternalParent == null) return;
{
Number = ((Surface) Parent).CountStepLabels(this); Number = InternalParent.CountStepLabels(this);
_counterStart = ((Surface) Parent).CounterStart; _counterStart = InternalParent.CounterStart;
}
} }
/// <summary> /// <summary>
@ -97,23 +97,23 @@ namespace Greenshot.Editor.Drawing
/// Add the StepLabel to the parent /// Add the StepLabel to the parent
/// </summary> /// </summary>
/// <param name="newParent"></param> /// <param name="newParent"></param>
protected override void SwitchParent(Surface newParent) protected override void SwitchParent(ISurface newParent)
{ {
if (newParent == Parent) if (newParent == Parent)
{ {
return; return;
} }
((Surface) Parent)?.RemoveStepLabel(this); if (newParent is not Surface newParentSurface)
base.SwitchParent(newParent);
if (newParent == null)
{ {
return; return;
} }
InternalParent?.RemoveStepLabel(this);
base.SwitchParent(newParent);
// Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack)
newParent.CounterStart = _counterStart; newParentSurface.CounterStart = _counterStart;
newParent.AddStepLabel(this); newParentSurface.AddStepLabel(this);
} }
public override Size DefaultSize => new Size(30, 30); public override Size DefaultSize => new Size(30, 30);

View file

@ -49,7 +49,6 @@ namespace Greenshot.Editor.Drawing
public sealed class Surface : Control, ISurface, INotifyPropertyChanged public sealed class Surface : Control, ISurface, INotifyPropertyChanged
{ {
private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface));
public static int Count;
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
// Property to identify the Surface ID // Property to identify the Surface ID
@ -294,7 +293,7 @@ namespace Greenshot.Editor.Drawing
/// <summary> /// <summary>
/// all elements on the surface, needed with serialization /// all elements on the surface, needed with serialization
/// </summary> /// </summary>
private FieldAggregator _fieldAggregator; private IFieldAggregator _fieldAggregator;
/// <summary> /// <summary>
/// the cursor container, needed with serialization as we need a direct acces to it. /// 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. /// 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. /// e.g. used to decided if and which line thickness is shown when multiple elements are selected.
/// </summary> /// </summary>
public FieldAggregator FieldAggregator public IFieldAggregator FieldAggregator
{ {
get => _fieldAggregator; get => _fieldAggregator;
set => _fieldAggregator = value; set => _fieldAggregator = value;
@ -467,7 +466,6 @@ namespace Greenshot.Editor.Drawing
public Surface() public Surface()
{ {
_fieldAggregator = new FieldAggregator(this); _fieldAggregator = new FieldAggregator(this);
Count++;
_elements = new DrawableContainerList(_uniqueId); _elements = new DrawableContainerList(_uniqueId);
selectedElements = new DrawableContainerList(_uniqueId); selectedElements = new DrawableContainerList(_uniqueId);
LOG.Debug("Creating surface!"); LOG.Debug("Creating surface!");
@ -550,7 +548,6 @@ namespace Greenshot.Editor.Drawing
{ {
if (disposing) if (disposing)
{ {
Count--;
LOG.Debug("Disposing surface!"); LOG.Debug("Disposing surface!");
if (_buffer != null) if (_buffer != null)
{ {
@ -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> /// <summary>
/// Handle the drag/drop /// Handle the drag/drop
/// </summary> /// </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 // Test if it's an url and try to download the image so we have it in the original form
if (possibleUrl != null && possibleUrl.StartsWith("http")) if (possibleUrl != null && possibleUrl.StartsWith("http"))
{ {
using Image image = NetworkHelper.DownloadImage(possibleUrl); var drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(possibleUrl);
if (image != null) if (drawableContainer != null)
{ {
AddImageContainer(image, mouse.X, mouse.Y); drawableContainer.Left = Location.X;
drawableContainer.Top = Location.Y;
FitContainer(drawableContainer);
AddElement(drawableContainer);
return; 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); mouse.Offset(10, 10);
image.Dispose();
} }
} }
@ -987,14 +1010,12 @@ namespace Greenshot.Editor.Drawing
{ {
//create a blank bitmap the same size as original //create a blank bitmap the same size as original
Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty);
if (newBitmap != null) if (newBitmap == null) return;
{
// Make undoable // Make undoable
MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false);
SetImage(newBitmap, false); SetImage(newBitmap, false);
Invalidate(); Invalidate();
} }
}
/// <summary> /// <summary>
/// Apply a bitmap effect to the surface /// Apply a bitmap effect to the surface
@ -2057,19 +2078,18 @@ namespace Greenshot.Editor.Drawing
{ {
Point pasteLocation = GetPasteLocation(0.1f, 0.1f); Point pasteLocation = GetPasteLocation(0.1f, 0.1f);
foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) foreach (var drawableContainer in ClipboardHelper.GetDrawables(clipboard))
{
if (clipboardImage != null)
{ {
if (drawableContainer == null) continue;
DeselectAllElements(); DeselectAllElements();
IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); drawableContainer.Left = pasteLocation.X;
SelectElement(container); drawableContainer.Top = pasteLocation.Y;
clipboardImage.Dispose(); AddElement(drawableContainer);
SelectElement(drawableContainer);
pasteLocation.X += 10; pasteLocation.X += 10;
pasteLocation.Y += 10; pasteLocation.Y += 10;
} }
} }
}
else if (ClipboardHelper.ContainsText(clipboard)) else if (ClipboardHelper.ContainsText(clipboard))
{ {
Point pasteLocation = GetPasteLocation(0.4f, 0.4f); Point pasteLocation = GetPasteLocation(0.4f, 0.4f);
@ -2208,8 +2228,8 @@ namespace Greenshot.Editor.Drawing
/// <param name="generateEvents">false to skip event generation</param> /// <param name="generateEvents">false to skip event generation</param>
public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true)
{ {
if (!selectedElements.Contains(container)) if (selectedElements.Contains(container)) return;
{
selectedElements.Add(container); selectedElements.Add(container);
container.Selected = true; container.Selected = true;
FieldAggregator.BindElement(container); FieldAggregator.BindElement(container);
@ -2227,7 +2247,6 @@ namespace Greenshot.Editor.Drawing
container.Invalidate(); container.Invalidate();
} }
} }
}
/// <summary> /// <summary>
/// Select all elements, this is called when Ctrl+A is pressed /// Select all elements, this is called when Ctrl+A is pressed

View 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);
}
}

View file

@ -28,6 +28,7 @@ using System.Drawing.Text;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Core; using Greenshot.Base.Core;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Fields;
using Greenshot.Editor.Helpers; using Greenshot.Editor.Helpers;
@ -83,7 +84,7 @@ namespace Greenshot.Editor.Drawing
OnPropertyChanged("Text"); OnPropertyChanged("Text");
} }
public TextContainer(Surface parent) : base(parent) public TextContainer(ISurface parent) : base(parent)
{ {
Init(); Init();
} }
@ -154,17 +155,17 @@ namespace Greenshot.Editor.Drawing
FieldChanged += TextContainer_FieldChanged; 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); 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(); 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 // Fix (workaround) for BUG-1698
_parent.KeysLocked = true; InternalParent.KeysLocked = true;
} }
} }
@ -295,10 +296,10 @@ namespace Greenshot.Editor.Drawing
private void ShowTextBox() private void ShowTextBox()
{ {
if (_parent != null) if (InternalParent != null)
{ {
_parent.KeysLocked = true; InternalParent.KeysLocked = true;
_parent.Controls.Add(_textBox); InternalParent.Controls.Add(_textBox);
} }
EnsureTextBoxContrast(); EnsureTextBoxContrast();
@ -332,15 +333,15 @@ namespace Greenshot.Editor.Drawing
private void HideTextBox() private void HideTextBox()
{ {
_parent?.Focus(); InternalParent?.Focus();
_textBox?.Hide(); _textBox?.Hide();
if (_parent == null) if (InternalParent == null)
{ {
return; return;
} }
_parent.KeysLocked = false; InternalParent.KeysLocked = false;
_parent.Controls.Remove(_textBox); InternalParent.Controls.Remove(_textBox);
} }
/// <summary> /// <summary>

View 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;
}
}
}

View 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()
);
}
}
}

View file

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

View file

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

View file

@ -20,29 +20,112 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Greenshot.Base.Core;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using log4net;
namespace Greenshot.Base.Core namespace Greenshot.Editor.FileFormatHandlers
{ {
/// <summary> /// <summary>
/// Though Greenshot implements the specs for the DIB image format, /// This handles creating a DIB (Device Independent Bitmap) on the clipboard
/// 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>
/// </summary> /// </summary>
internal static class DibHelper public class DibFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler
{ {
private const double DpiToPelsPerMeter = 39.3701; 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> /// <summary>
/// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS. /// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS.
/// </summary> /// </summary>
/// <param name="sourceBitmap">Bitmap to convert to DIB</param> /// <param name="sourceBitmap">Bitmap to convert to DIB</param>
/// <returns>byte{} with the image converted to DIB</returns> /// <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)); if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap));

View file

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

View 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;
}
}
}

View 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.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);
}
}
}
}

View file

@ -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);
}
}
}
}

View 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;
}
}
}

View file

@ -56,13 +56,13 @@ namespace Greenshot.Editor.Forms
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageEditorForm)); private static readonly ILog Log = LogManager.GetLogger(typeof(ImageEditorForm));
private static readonly EditorConfiguration EditorConfiguration = IniConfig.GetIniSection<EditorConfiguration>(); 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), nameof(WellKnownDestinations.Picker),
EditorDestination.DESIGNATION EditorDestination.DESIGNATION
}; };
private static readonly List<IImageEditor> EditorList = new List<IImageEditor>(); private static readonly List<IImageEditor> EditorList = new();
private Surface _surface; private Surface _surface;
private GreenshotToolStripButton[] _toolbarButtons; private GreenshotToolStripButton[] _toolbarButtons;
@ -181,6 +181,20 @@ namespace Greenshot.Editor.Forms
UpdateUi(); 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. // Workaround: As the cursor is (mostly) selected on the surface a funny artifact is visible, this fixes it.
HideToolstripItems(); HideToolstripItems();
} }
@ -1290,7 +1304,7 @@ namespace Greenshot.Editor.Forms
propertiesToolStrip.SuspendLayout(); propertiesToolStrip.SuspendLayout();
if (_surface.HasSelectedElements || _surface.DrawingMode != DrawingModes.None) if (_surface.HasSelectedElements || _surface.DrawingMode != DrawingModes.None)
{ {
FieldAggregator props = _surface.FieldAggregator; var props = (FieldAggregator)_surface.FieldAggregator;
btnFillColor.Visible = props.HasFieldValue(FieldType.FILL_COLOR); btnFillColor.Visible = props.HasFieldValue(FieldType.FILL_COLOR);
btnLineColor.Visible = props.HasFieldValue(FieldType.LINE_COLOR); btnLineColor.Visible = props.HasFieldValue(FieldType.LINE_COLOR);
lineThicknessLabel.Visible = lineThicknessUpDown.Visible = props.HasFieldValue(FieldType.LINE_THICKNESS); lineThicknessLabel.Visible = lineThicknessUpDown.Visible = props.HasFieldValue(FieldType.LINE_THICKNESS);
@ -1350,7 +1364,7 @@ namespace Greenshot.Editor.Forms
btnStepLabel.Image = icon; btnStepLabel.Image = icon;
addCounterToolStripMenuItem.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 // if a confirmable element is selected, we must disable most of the controls
// since we demand confirmation or cancel for confirmable element // since we demand confirmation or cancel for confirmable element
if (props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE) if (props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE)

View file

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

View file

@ -20,9 +20,8 @@
*/ */
using System; using System;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.Memento namespace Greenshot.Editor.Memento
{ {
/// <summary> /// <summary>
@ -31,9 +30,9 @@ namespace Greenshot.Editor.Memento
public class AddElementMemento : IMemento public class AddElementMemento : IMemento
{ {
private IDrawableContainer _drawableContainer; private IDrawableContainer _drawableContainer;
private Surface _surface; private ISurface _surface;
public AddElementMemento(Surface surface, IDrawableContainer drawableContainer) public AddElementMemento(ISurface surface, IDrawableContainer drawableContainer)
{ {
_surface = surface; _surface = surface;
_drawableContainer = drawableContainer; _drawableContainer = drawableContainer;

View file

@ -19,8 +19,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.Memento namespace Greenshot.Editor.Memento
{ {
@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento
public class AddElementsMemento : IMemento public class AddElementsMemento : IMemento
{ {
private IDrawableContainerList _containerList; private IDrawableContainerList _containerList;
private Surface _surface; private ISurface _surface;
public AddElementsMemento(Surface surface, IDrawableContainerList containerList) public AddElementsMemento(ISurface surface, IDrawableContainerList containerList)
{ {
_surface = surface; _surface = surface;
_containerList = containerList; _containerList = containerList;

View file

@ -20,8 +20,8 @@
*/ */
using System; using System;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.Memento namespace Greenshot.Editor.Memento
{ {
@ -31,9 +31,9 @@ namespace Greenshot.Editor.Memento
public class DeleteElementMemento : IMemento public class DeleteElementMemento : IMemento
{ {
private IDrawableContainer _drawableContainer; 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; _surface = surface;
_drawableContainer = drawableContainer; _drawableContainer = drawableContainer;

View file

@ -19,8 +19,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.Memento namespace Greenshot.Editor.Memento
{ {
@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento
public class DeleteElementsMemento : IMemento public class DeleteElementsMemento : IMemento
{ {
private IDrawableContainerList _containerList; private IDrawableContainerList _containerList;
private Surface _surface; private ISurface _surface;
public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList) public DeleteElementsMemento(ISurface surface, IDrawableContainerList containerList)
{ {
_surface = surface; _surface = surface;
_containerList = containerList; _containerList = containerList;

View file

@ -21,8 +21,8 @@
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing;
using Greenshot.Editor.Drawing;
namespace Greenshot.Editor.Memento namespace Greenshot.Editor.Memento
{ {
@ -32,10 +32,10 @@ namespace Greenshot.Editor.Memento
public class SurfaceBackgroundChangeMemento : IMemento public class SurfaceBackgroundChangeMemento : IMemento
{ {
private Image _image; private Image _image;
private Surface _surface; private ISurface _surface;
private Matrix _matrix; private Matrix _matrix;
public SurfaceBackgroundChangeMemento(Surface surface, Matrix matrix) public SurfaceBackgroundChangeMemento(ISurface surface, Matrix matrix)
{ {
_surface = surface; _surface = surface;
_image = surface.Image; _image = surface.Image;

View file

@ -87,7 +87,7 @@ namespace Greenshot.Plugin.Box.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(208, 12); this.combobox_uploadimageformat.Location = new System.Drawing.Point(208, 12);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Box";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(215, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(215, 21);
this.combobox_uploadimageformat.TabIndex = 5; this.combobox_uploadimageformat.TabIndex = 5;
@ -115,7 +115,7 @@ namespace Greenshot.Plugin.Box.Forms {
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "box.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "box.label_AfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(208, 45); this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(208, 45);
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(BoxConfiguration.AfterUploadLinkToClipBoard);
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Box"; this.checkboxAfterUploadLinkToClipBoard.SectionName = "Box";
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 10; this.checkboxAfterUploadLinkToClipBoard.TabIndex = 10;

View file

@ -54,8 +54,8 @@ namespace Greenshot.Plugin.Confluence
Uri confluenceIconUri = new Uri("/Greenshot.Plugin.Confluence;component/Images/Confluence.ico", UriKind.Relative); Uri confluenceIconUri = new Uri("/Greenshot.Plugin.Confluence;component/Images/Confluence.ico", UriKind.Relative);
using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream)
{ {
// TODO: Check what to do with the IImage // TODO: Replace with FileFormatHandler
ConfluenceIcon = ImageHelper.FromStream(iconStream); ConfluenceIcon = ImageIO.FromStream(iconStream);
} }
IsInitialized = true; IsInitialized = true;

View file

@ -21,7 +21,6 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
using Greenshot.Base.Core;
using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.Enums;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Plugin.Dropbox.Forms; using Greenshot.Plugin.Dropbox.Forms;
@ -29,10 +28,10 @@ using Greenshot.Plugin.Dropbox.Forms;
namespace Greenshot.Plugin.Dropbox namespace Greenshot.Plugin.Dropbox
{ {
/// <summary> /// <summary>
/// Description of ImgurConfiguration. /// The configuration for Dropbox
/// </summary> /// </summary>
[IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] [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")] [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")]
public OutputFormat UploadFormat { get; set; } public OutputFormat UploadFormat { get; set; }

View file

@ -29,7 +29,7 @@ namespace Greenshot.Plugin.Dropbox
{ {
internal class DropboxDestination : AbstractDestination internal class DropboxDestination : AbstractDestination
{ {
private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxPluginConfiguration>(); private static readonly DropboxConfiguration DropboxConfig = IniConfig.GetIniSection<DropboxConfiguration>();
private readonly DropboxPlugin _plugin; private readonly DropboxPlugin _plugin;

View file

@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox
public class DropboxPlugin : IGreenshotPlugin public class DropboxPlugin : IGreenshotPlugin
{ {
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin));
private static DropboxPluginConfiguration _config; private static DropboxConfiguration _config;
private ComponentResourceManager _resources; private ComponentResourceManager _resources;
private ToolStripMenuItem _itemPlugInConfig; private ToolStripMenuItem _itemPlugInConfig;
@ -71,7 +71,7 @@ namespace Greenshot.Plugin.Dropbox
public bool Initialize() public bool Initialize()
{ {
// Register configuration (don't need the configuration itself) // Register configuration (don't need the configuration itself)
_config = IniConfig.GetIniSection<DropboxPluginConfiguration>(); _config = IniConfig.GetIniSection<DropboxConfiguration>();
_resources = new ComponentResourceManager(typeof(DropboxPlugin)); _resources = new ComponentResourceManager(typeof(DropboxPlugin));
SimpleServiceProvider.Current.AddService<IDestination>(new DropboxDestination(this)); SimpleServiceProvider.Current.AddService<IDestination>(new DropboxDestination(this));
_itemPlugInConfig = new ToolStripMenuItem _itemPlugInConfig = new ToolStripMenuItem

View file

@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox
public class DropboxUtils public class DropboxUtils
{ {
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(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() private DropboxUtils()
{ {

View file

@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Dropbox.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(116, 9); this.combobox_uploadimageformat.Location = new System.Drawing.Point(116, 9);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Dropbox";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(309, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(309, 21);
this.combobox_uploadimageformat.TabIndex = 1; this.combobox_uploadimageformat.TabIndex = 1;
@ -112,7 +112,7 @@ namespace Greenshot.Plugin.Dropbox.Forms {
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "dropbox.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "dropbox.label_AfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(116, 37); this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(116, 37);
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(DropboxConfiguration.AfterUploadLinkToClipBoard);
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Dropbox"; this.checkboxAfterUploadLinkToClipBoard.SectionName = "Dropbox";
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;

View file

@ -77,7 +77,7 @@ namespace Greenshot.Plugin.ExternalCommand
} }
bool runInBackground = config.RunInbackground[_presetCommand]; 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 output;
string error; string error;

View file

@ -93,7 +93,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(174, 6); this.combobox_uploadimageformat.Location = new System.Drawing.Point(174, 6);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Flickr";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(251, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(251, 21);
this.combobox_uploadimageformat.TabIndex = 1; this.combobox_uploadimageformat.TabIndex = 1;
@ -111,7 +111,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.checkBoxPublic.LanguageKey = "flickr.public"; this.checkBoxPublic.LanguageKey = "flickr.public";
this.checkBoxPublic.Location = new System.Drawing.Point(174, 88); this.checkBoxPublic.Location = new System.Drawing.Point(174, 88);
this.checkBoxPublic.Name = "checkBoxPublic"; this.checkBoxPublic.Name = "checkBoxPublic";
this.checkBoxPublic.PropertyName = "flickrIsPublic"; this.checkBoxPublic.PropertyName = nameof(FlickrConfiguration.IsPublic);
this.checkBoxPublic.SectionName = "Flickr"; this.checkBoxPublic.SectionName = "Flickr";
this.checkBoxPublic.Size = new System.Drawing.Size(55, 17); this.checkBoxPublic.Size = new System.Drawing.Size(55, 17);
this.checkBoxPublic.TabIndex = 4; this.checkBoxPublic.TabIndex = 4;
@ -122,7 +122,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.checkBoxFamily.LanguageKey = "flickr.family"; this.checkBoxFamily.LanguageKey = "flickr.family";
this.checkBoxFamily.Location = new System.Drawing.Point(265, 88); this.checkBoxFamily.Location = new System.Drawing.Point(265, 88);
this.checkBoxFamily.Name = "checkBoxFamily"; this.checkBoxFamily.Name = "checkBoxFamily";
this.checkBoxFamily.PropertyName = "flickrIsFamily"; this.checkBoxFamily.PropertyName = nameof(FlickrConfiguration.IsFamily);
this.checkBoxFamily.SectionName = "Flickr"; this.checkBoxFamily.SectionName = "Flickr";
this.checkBoxFamily.Size = new System.Drawing.Size(55, 17); this.checkBoxFamily.Size = new System.Drawing.Size(55, 17);
this.checkBoxFamily.TabIndex = 5; this.checkBoxFamily.TabIndex = 5;
@ -133,7 +133,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.checkBoxFriend.LanguageKey = "flickr.friend"; this.checkBoxFriend.LanguageKey = "flickr.friend";
this.checkBoxFriend.Location = new System.Drawing.Point(350, 88); this.checkBoxFriend.Location = new System.Drawing.Point(350, 88);
this.checkBoxFriend.Name = "checkBoxFriend"; this.checkBoxFriend.Name = "checkBoxFriend";
this.checkBoxFriend.PropertyName = "flickrIsFriend"; this.checkBoxFriend.PropertyName = nameof(FlickrConfiguration.IsFriend);
this.checkBoxFriend.SectionName = "Flickr"; this.checkBoxFriend.SectionName = "Flickr";
this.checkBoxFriend.Size = new System.Drawing.Size(55, 17); this.checkBoxFriend.Size = new System.Drawing.Size(55, 17);
this.checkBoxFriend.TabIndex = 6; this.checkBoxFriend.TabIndex = 6;
@ -155,7 +155,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.combobox_safetyLevel.FormattingEnabled = true; this.combobox_safetyLevel.FormattingEnabled = true;
this.combobox_safetyLevel.Location = new System.Drawing.Point(174, 33); this.combobox_safetyLevel.Location = new System.Drawing.Point(174, 33);
this.combobox_safetyLevel.Name = "combobox_safetyLevel"; 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.SectionName = "Flickr";
this.combobox_safetyLevel.Size = new System.Drawing.Size(251, 21); this.combobox_safetyLevel.Size = new System.Drawing.Size(251, 21);
this.combobox_safetyLevel.TabIndex = 2; this.combobox_safetyLevel.TabIndex = 2;
@ -173,7 +173,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "flickr.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "flickr.label_AfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(173, 116); this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(173, 116);
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(FlickrConfiguration.AfterUploadLinkToClipBoard);
this.checkboxAfterUploadLinkToClipBoard.SectionName = "Flickr"; this.checkboxAfterUploadLinkToClipBoard.SectionName = "Flickr";
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 7; this.checkboxAfterUploadLinkToClipBoard.TabIndex = 7;
@ -184,7 +184,7 @@ namespace Greenshot.Plugin.Flickr.Forms {
this.checkBox_hiddenfromsearch.LanguageKey = "flickr.label_HiddenFromSearch"; this.checkBox_hiddenfromsearch.LanguageKey = "flickr.label_HiddenFromSearch";
this.checkBox_hiddenfromsearch.Location = new System.Drawing.Point(174, 60); this.checkBox_hiddenfromsearch.Location = new System.Drawing.Point(174, 60);
this.checkBox_hiddenfromsearch.Name = "checkBox_hiddenfromsearch"; 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.SectionName = "Flickr";
this.checkBox_hiddenfromsearch.Size = new System.Drawing.Size(118, 17); this.checkBox_hiddenfromsearch.Size = new System.Drawing.Size(118, 17);
this.checkBox_hiddenfromsearch.TabIndex = 3; this.checkBox_hiddenfromsearch.TabIndex = 3;

View file

@ -86,7 +86,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12); this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "GooglePhotos";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21);
this.combobox_uploadimageformat.TabIndex = 1; this.combobox_uploadimageformat.TabIndex = 1;
@ -114,7 +114,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms {
this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50); this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50);
this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard";
this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(GooglePhotosConfiguration.AfterUploadLinkToClipBoard);
this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos"; this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos";
this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17);
this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2;

View file

@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Imgur.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(168, 7); this.combobox_uploadimageformat.Location = new System.Drawing.Point(168, 7);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Imgur";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(210, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(210, 21);
this.combobox_uploadimageformat.TabIndex = 1; 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.LanguageKey = "imgur.anonymous_access";
this.checkbox_anonymous_access.Location = new System.Drawing.Point(15, 38); this.checkbox_anonymous_access.Location = new System.Drawing.Point(15, 38);
this.checkbox_anonymous_access.Name = "checkbox_anonymous_access"; 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.SectionName = "Imgur";
this.checkbox_anonymous_access.Size = new System.Drawing.Size(139, 17); this.checkbox_anonymous_access.Size = new System.Drawing.Size(139, 17);
this.checkbox_anonymous_access.TabIndex = 2; 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.LanguageKey = "imgur.use_page_link";
this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 57); this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 57);
this.checkbox_usepagelink.Name = "checkbox_usepagelink"; 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.SectionName = "Imgur";
this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17); this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17);
this.checkbox_usepagelink.TabIndex = 3; this.checkbox_usepagelink.TabIndex = 3;

View file

@ -179,7 +179,7 @@ namespace Greenshot.Plugin.Imgur
{ {
using (var requestStream = webRequest.GetRequestStream()) using (var requestStream = webRequest.GetRequestStream())
{ {
ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); ImageIO.SaveToStream(surfaceToUpload, requestStream, outputSettings);
} }
using WebResponse response = webRequest.GetResponse(); using WebResponse response = webRequest.GetResponse();
@ -265,7 +265,8 @@ namespace Greenshot.Plugin.Imgur
Stream responseStream = response.GetResponseStream(); Stream responseStream = response.GetResponseStream();
if (responseStream != null) if (responseStream != null)
{ {
imgurInfo.Image = ImageHelper.FromStream(responseStream); // TODO: Replace with some other code, like the file format handler
imgurInfo.Image = ImageIO.FromStream(responseStream);
} }
} }

View file

@ -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.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.Location = new System.Drawing.Point(164, 21);
this.textBoxUrl.Name = "textBoxUrl"; this.textBoxUrl.Name = "textBoxUrl";
this.textBoxUrl.PropertyName = "Url"; this.textBoxUrl.PropertyName = nameof(JiraConfiguration.Url);
this.textBoxUrl.SectionName = "Jira"; this.textBoxUrl.SectionName = "Jira";
this.textBoxUrl.Size = new System.Drawing.Size(214, 20); this.textBoxUrl.Size = new System.Drawing.Size(214, 20);
this.textBoxUrl.TabIndex = 6; this.textBoxUrl.TabIndex = 6;
@ -105,7 +105,7 @@ namespace Greenshot.Plugin.Jira.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(164, 47); this.combobox_uploadimageformat.Location = new System.Drawing.Point(164, 47);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Jira";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(214, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(214, 21);
this.combobox_uploadimageformat.TabIndex = 8; this.combobox_uploadimageformat.TabIndex = 8;

View file

@ -89,7 +89,7 @@ namespace Greenshot.Plugin.Office.Destinations
string imageFile = captureDetails.Filename; string imageFile = captureDetails.Filename;
if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) 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; 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 // Cleanup imageFile if we created it here, so less tmp-files are generated and left
if (createdFile) if (createdFile)
{ {
ImageOutput.DeleteNamedTmpFile(imageFile); ImageIO.DeleteNamedTmpFile(imageFile);
} }
return exportInformation; return exportInformation;

View file

@ -160,7 +160,7 @@ namespace Greenshot.Plugin.Office.Destinations
string tmpFile = captureDetails.Filename; string tmpFile = captureDetails.Filename;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) 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 else
{ {

View file

@ -114,7 +114,7 @@ namespace Greenshot.Plugin.Office.Destinations
Size imageSize = Size.Empty; Size imageSize = Size.Empty;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) 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; imageSize = surface.Image.Size;
} }

View file

@ -88,7 +88,7 @@ namespace Greenshot.Plugin.Office.Destinations
string tmpFile = captureDetails.Filename; string tmpFile = captureDetails.Filename;
if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) 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) if (_documentCaption != null)

View file

@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Office.OfficeExport
using var pngStream = new MemoryStream(); using var pngStream = new MemoryStream();
var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); 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 base64String = Convert.ToBase64String(pngStream.GetBuffer());
var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height); var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height);
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name); var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);

View file

@ -84,7 +84,7 @@ namespace Greenshot.Plugin.Photobucket.Forms {
this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.FormattingEnabled = true;
this.combobox_uploadimageformat.Location = new System.Drawing.Point(102, 11); this.combobox_uploadimageformat.Location = new System.Drawing.Point(102, 11);
this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; 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.SectionName = "Photobucket";
this.combobox_uploadimageformat.Size = new System.Drawing.Size(276, 21); this.combobox_uploadimageformat.Size = new System.Drawing.Size(276, 21);
this.combobox_uploadimageformat.TabIndex = 1; 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.LanguageKey = "photobucket.use_page_link";
this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 43); this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 43);
this.checkbox_usepagelink.Name = "checkbox_usepagelink"; 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.SectionName = "Photobucket";
this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17); this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17);
this.checkbox_usepagelink.TabIndex = 2; this.checkbox_usepagelink.TabIndex = 2;

View file

@ -151,7 +151,7 @@ namespace Greenshot.Plugin.Win10.Destinations
outputSettings.PreventGreenshotFormat(); outputSettings.PreventGreenshotFormat();
// Create capture for export // Create capture for export
ImageOutput.SaveToStream(surface, imageStream, outputSettings); ImageIO.SaveToStream(surface, imageStream, outputSettings);
imageStream.Position = 0; imageStream.Position = 0;
Log.Debug("Created RandomAccessStreamReference for the image"); Log.Debug("Created RandomAccessStreamReference for the image");
var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream); var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream);
@ -161,7 +161,7 @@ namespace Greenshot.Plugin.Win10.Destinations
using (var tmpImageForThumbnail = surface.GetImageForExport()) using (var tmpImageForThumbnail = surface.GetImageForExport())
using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160)) using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160))
{ {
ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings); ImageIO.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
thumbnailStream.Position = 0; thumbnailStream.Position = 0;
thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream); thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream);
Log.Debug("Created RandomAccessStreamReference for the thumbnail"); Log.Debug("Created RandomAccessStreamReference for the thumbnail");
@ -172,7 +172,7 @@ namespace Greenshot.Plugin.Win10.Destinations
using (var logo = GreenshotResources.GetGreenshotIcon().ToBitmap()) using (var logo = GreenshotResources.GetGreenshotIcon().ToBitmap())
using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30)) using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30))
{ {
ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings); ImageIO.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
logoStream.Position = 0; logoStream.Position = 0;
logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream); logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream);
Log.Info("Created RandomAccessStreamReference for the logo"); Log.Info("Created RandomAccessStreamReference for the logo");

View file

@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Win10
IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight); IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight);
outputSettings.Effects.Add(effect); outputSettings.Effects.Add(effect);
} }
ImageOutput.SaveToStream(surface, imageStream, outputSettings); ImageIO.SaveToStream(surface, imageStream, outputSettings);
imageStream.Position = 0; imageStream.Position = 0;
var randomAccessStream = imageStream.AsRandomAccessStream(); var randomAccessStream = imageStream.AsRandomAccessStream();
@ -117,7 +117,7 @@ namespace Greenshot.Plugin.Win10
OcrInformation result; OcrInformation result;
using (var imageStream = new MemoryStream()) using (var imageStream = new MemoryStream())
{ {
ImageOutput.SaveToStream(image, null, imageStream, new SurfaceOutputSettings()); ImageIO.SaveToStream(image, null, imageStream, new SurfaceOutputSettings());
imageStream.Position = 0; imageStream.Position = 0;
var randomAccessStream = imageStream.AsRandomAccessStream(); var randomAccessStream = imageStream.AsRandomAccessStream();

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<!--<system.windows.forms jitDebugging="true" />-->
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup> </startup>

View file

@ -68,7 +68,7 @@ namespace Greenshot.Destinations
overwrite = true; overwrite = true;
Log.InfoFormat("Using previous filename"); Log.InfoFormat("Using previous filename");
fullPath = captureDetails.Filename; fullPath = captureDetails.Filename;
outputSettings.Format = ImageOutput.FormatForFilename(fullPath); outputSettings.Format = ImageIO.FormatForFilename(fullPath);
} }
else else
{ {
@ -87,7 +87,7 @@ namespace Greenshot.Destinations
// This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642
try try
{ {
ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); ImageIO.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
outputMade = true; outputMade = true;
} }
catch (ArgumentException ex1) catch (ArgumentException ex1)
@ -95,7 +95,7 @@ namespace Greenshot.Destinations
// Our generated filename exists, display 'save-as' // Our generated filename exists, display 'save-as'
Log.InfoFormat("Not overwriting: {0}", ex1.Message); Log.InfoFormat("Not overwriting: {0}", ex1.Message);
// when we don't allow to overwrite present a new SaveWithDialog // when we don't allow to overwrite present a new SaveWithDialog
fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); fullPath = ImageIO.SaveWithDialog(surface, captureDetails);
outputMade = fullPath != null; outputMade = fullPath != null;
} }
catch (Exception ex2) catch (Exception ex2)
@ -104,7 +104,7 @@ namespace Greenshot.Destinations
// Show the problem // Show the problem
MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error));
// when save failed we present a SaveWithDialog // when save failed we present a SaveWithDialog
fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); fullPath = ImageIO.SaveWithDialog(surface, captureDetails);
outputMade = fullPath != null; outputMade = fullPath != null;
} }

View file

@ -57,7 +57,7 @@ namespace Greenshot.Destinations
{ {
ExportInformation exportInformation = new ExportInformation(Designation, Description); ExportInformation exportInformation = new ExportInformation(Designation, Description);
// Bug #2918756 don't overwrite path if SaveWithDialog returns null! // 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) if (savedTo != null)
{ {
exportInformation.ExportMade = true; exportInformation.ExportMade = true;

View file

@ -36,6 +36,7 @@ using Greenshot.Base;
using Greenshot.Base.Controls; using Greenshot.Base.Controls;
using Greenshot.Base.Core; using Greenshot.Base.Core;
using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.Enums;
using Greenshot.Base.Core.FileFormatHandlers;
using Greenshot.Base.Help; using Greenshot.Base.Help;
using Greenshot.Base.IniFile; using Greenshot.Base.IniFile;
using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces;
@ -43,6 +44,7 @@ using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using Greenshot.Configuration; using Greenshot.Configuration;
using Greenshot.Destinations; using Greenshot.Destinations;
using Greenshot.Editor;
using Greenshot.Editor.Destinations; using Greenshot.Editor.Destinations;
using Greenshot.Editor.Drawing; using Greenshot.Editor.Drawing;
using Greenshot.Editor.Forms; using Greenshot.Editor.Forms;
@ -162,7 +164,7 @@ namespace Greenshot.Forms
if (argument.ToLower().Equals("/exit")) if (argument.ToLower().Equals("/exit"))
{ {
// unregister application on uninstall (allow uninstall) // un-register application on uninstall (allow uninstall)
try try
{ {
LOG.Info("Sending all instances the exit command."); LOG.Info("Sending all instances the exit command.");
@ -387,6 +389,8 @@ namespace Greenshot.Forms
_instance = this; _instance = this;
EditorInitialize.Initialize();
// Factory for surface objects // Factory for surface objects
ISurface SurfaceFactory() => new Surface(); ISurface SurfaceFactory() => new Surface();
@ -923,10 +927,10 @@ namespace Greenshot.Forms
Hide(); Hide();
ShowInTaskbar = false; ShowInTaskbar = false;
// TODO: Do we really need this?
using var loProcess = Process.GetCurrentProcess(); //using var loProcess = Process.GetCurrentProcess();
loProcess.MaxWorkingSet = (IntPtr)750000; //loProcess.MaxWorkingSet = (IntPtr)750000;
loProcess.MinWorkingSet = (IntPtr)300000; //loProcess.MinWorkingSet = (IntPtr)300000;
} }
private void CaptureRegion() private void CaptureRegion()
@ -936,9 +940,12 @@ namespace Greenshot.Forms
private void CaptureFile(IDestination destination = null) 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 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) if (openFileDialog.ShowDialog() != DialogResult.OK)
{ {
@ -1904,7 +1911,7 @@ namespace Greenshot.Forms
LOG.Error("Error closing application!", e); LOG.Error("Error closing application!", e);
} }
ImageOutput.RemoveTmpFiles(); ImageIO.RemoveTmpFiles();
// Store any open configuration changes // Store any open configuration changes
try try

View file

@ -89,7 +89,7 @@ namespace Greenshot.Forms
this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink";
this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23); this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23);
this.checkboxAllowShrink.Name = "checkboxAllowShrink"; 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.Size = new System.Drawing.Size(168, 17);
this.checkboxAllowShrink.TabIndex = 2; this.checkboxAllowShrink.TabIndex = 2;
this.checkboxAllowShrink.Text = "Shrink printout to fit paper size"; this.checkboxAllowShrink.Text = "Shrink printout to fit paper size";
@ -103,7 +103,7 @@ namespace Greenshot.Forms
this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge";
this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46); this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46);
this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge"; 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.Size = new System.Drawing.Size(174, 17);
this.checkboxAllowEnlarge.TabIndex = 3; this.checkboxAllowEnlarge.TabIndex = 3;
this.checkboxAllowEnlarge.Text = "Enlarge printout to fit paper size"; this.checkboxAllowEnlarge.Text = "Enlarge printout to fit paper size";
@ -117,7 +117,7 @@ namespace Greenshot.Forms
this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter";
this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92); this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92);
this.checkboxAllowCenter.Name = "checkboxAllowCenter"; 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.Size = new System.Drawing.Size(137, 17);
this.checkboxAllowCenter.TabIndex = 5; this.checkboxAllowCenter.TabIndex = 5;
this.checkboxAllowCenter.Text = "Center printout on page"; this.checkboxAllowCenter.Text = "Center printout on page";
@ -131,7 +131,7 @@ namespace Greenshot.Forms
this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate";
this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69); this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69);
this.checkboxAllowRotate.Name = "checkboxAllowRotate"; 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.Size = new System.Drawing.Size(187, 17);
this.checkboxAllowRotate.TabIndex = 4; this.checkboxAllowRotate.TabIndex = 4;
this.checkboxAllowRotate.Text = "Rotate printout to page orientation"; this.checkboxAllowRotate.Text = "Rotate printout to page orientation";
@ -158,7 +158,7 @@ namespace Greenshot.Forms
this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; this.checkboxDateTime.LanguageKey = "printoptions_timestamp";
this.checkboxDateTime.Location = new System.Drawing.Point(13, 115); this.checkboxDateTime.Location = new System.Drawing.Point(13, 115);
this.checkboxDateTime.Name = "checkboxDateTime"; 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.Size = new System.Drawing.Size(187, 17);
this.checkboxDateTime.TabIndex = 6; this.checkboxDateTime.TabIndex = 6;
this.checkboxDateTime.Text = "Print date / time at bottom of page"; this.checkboxDateTime.Text = "Print date / time at bottom of page";
@ -184,7 +184,7 @@ namespace Greenshot.Forms
this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; this.checkboxPrintInverted.LanguageKey = "printoptions_inverted";
this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88); this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88);
this.checkboxPrintInverted.Name = "checkboxPrintInverted"; 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.Size = new System.Drawing.Size(141, 17);
this.checkboxPrintInverted.TabIndex = 14; this.checkboxPrintInverted.TabIndex = 14;
this.checkboxPrintInverted.Text = "Print with inverted colors"; this.checkboxPrintInverted.Text = "Print with inverted colors";
@ -198,7 +198,7 @@ namespace Greenshot.Forms
this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale";
this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42); this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42);
this.radioBtnGrayScale.Name = "radioBtnGrayScale"; 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.Size = new System.Drawing.Size(137, 17);
this.radioBtnGrayScale.TabIndex = 12; this.radioBtnGrayScale.TabIndex = 12;
this.radioBtnGrayScale.Text = "Force grayscale printing"; this.radioBtnGrayScale.Text = "Force grayscale printing";
@ -212,7 +212,7 @@ namespace Greenshot.Forms
this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome";
this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65); this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65);
this.radioBtnMonochrome.Name = "radioBtnMonochrome"; 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.Size = new System.Drawing.Size(148, 17);
this.radioBtnMonochrome.TabIndex = 13; this.radioBtnMonochrome.TabIndex = 13;
this.radioBtnMonochrome.Text = "Force black/white printing"; this.radioBtnMonochrome.Text = "Force black/white printing";
@ -255,7 +255,6 @@ namespace Greenshot.Forms
this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor";
this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19); this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19);
this.radioBtnColorPrint.Name = "radioBtnColorPrint"; this.radioBtnColorPrint.Name = "radioBtnColorPrint";
this.radioBtnColorPrint.PropertyName = "OutputPrintColor";
this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17); this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17);
this.radioBtnColorPrint.TabIndex = 11; this.radioBtnColorPrint.TabIndex = 11;
this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft;

View file

@ -20,6 +20,8 @@
*/ */
using Greenshot.Base.Controls; using Greenshot.Base.Controls;
using Greenshot.Base.Core;
using Greenshot.Editor.Configuration;
using Greenshot.Editor.Controls; using Greenshot.Editor.Controls;
namespace Greenshot.Forms { namespace Greenshot.Forms {
@ -235,7 +237,7 @@ namespace Greenshot.Forms {
// //
this.textbox_screenshotname.Location = new System.Drawing.Point(138, 41); this.textbox_screenshotname.Location = new System.Drawing.Point(138, 41);
this.textbox_screenshotname.Name = "textbox_screenshotname"; 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(233, 20); this.textbox_screenshotname.Size = new System.Drawing.Size(233, 20);
this.textbox_screenshotname.TabIndex = 3; this.textbox_screenshotname.TabIndex = 3;
this.textbox_screenshotname.TextChanged += new System.EventHandler(this.FilenamePatternChanged); this.textbox_screenshotname.TextChanged += new System.EventHandler(this.FilenamePatternChanged);
@ -264,7 +266,7 @@ namespace Greenshot.Forms {
this.combobox_primaryimageformat.FormattingEnabled = true; this.combobox_primaryimageformat.FormattingEnabled = true;
this.combobox_primaryimageformat.Location = new System.Drawing.Point(138, 64); this.combobox_primaryimageformat.Location = new System.Drawing.Point(138, 64);
this.combobox_primaryimageformat.Name = "combobox_primaryimageformat"; 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(268, 21); this.combobox_primaryimageformat.Size = new System.Drawing.Size(268, 21);
this.combobox_primaryimageformat.TabIndex = 5; this.combobox_primaryimageformat.TabIndex = 5;
// //
@ -309,7 +311,7 @@ namespace Greenshot.Forms {
this.checkbox_copypathtoclipboard.LanguageKey = "settings_copypathtoclipboard"; this.checkbox_copypathtoclipboard.LanguageKey = "settings_copypathtoclipboard";
this.checkbox_copypathtoclipboard.Location = new System.Drawing.Point(12, 89); this.checkbox_copypathtoclipboard.Location = new System.Drawing.Point(12, 89);
this.checkbox_copypathtoclipboard.Name = "checkbox_copypathtoclipboard"; 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(394, 24); this.checkbox_copypathtoclipboard.Size = new System.Drawing.Size(394, 24);
this.checkbox_copypathtoclipboard.TabIndex = 6; this.checkbox_copypathtoclipboard.TabIndex = 6;
this.checkbox_copypathtoclipboard.UseVisualStyleBackColor = true; this.checkbox_copypathtoclipboard.UseVisualStyleBackColor = true;
@ -374,7 +376,7 @@ namespace Greenshot.Forms {
this.checkbox_reducecolors.LanguageKey = "settings_reducecolors"; this.checkbox_reducecolors.LanguageKey = "settings_reducecolors";
this.checkbox_reducecolors.Location = new System.Drawing.Point(12, 72); this.checkbox_reducecolors.Location = new System.Drawing.Point(12, 72);
this.checkbox_reducecolors.Name = "checkbox_reducecolors"; 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(394, 25); this.checkbox_reducecolors.Size = new System.Drawing.Size(394, 25);
this.checkbox_reducecolors.TabIndex = 10; this.checkbox_reducecolors.TabIndex = 10;
this.checkbox_reducecolors.UseVisualStyleBackColor = true; this.checkbox_reducecolors.UseVisualStyleBackColor = true;
@ -384,7 +386,7 @@ namespace Greenshot.Forms {
this.checkbox_alwaysshowqualitydialog.LanguageKey = "settings_alwaysshowqualitydialog"; this.checkbox_alwaysshowqualitydialog.LanguageKey = "settings_alwaysshowqualitydialog";
this.checkbox_alwaysshowqualitydialog.Location = new System.Drawing.Point(12, 50); this.checkbox_alwaysshowqualitydialog.Location = new System.Drawing.Point(12, 50);
this.checkbox_alwaysshowqualitydialog.Name = "checkbox_alwaysshowqualitydialog"; 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(394, 25); this.checkbox_alwaysshowqualitydialog.Size = new System.Drawing.Size(394, 25);
this.checkbox_alwaysshowqualitydialog.TabIndex = 9; this.checkbox_alwaysshowqualitydialog.TabIndex = 9;
this.checkbox_alwaysshowqualitydialog.UseVisualStyleBackColor = true; this.checkbox_alwaysshowqualitydialog.UseVisualStyleBackColor = true;
@ -526,7 +528,7 @@ namespace Greenshot.Forms {
this.checkbox_usedefaultproxy.LanguageKey = "settings_usedefaultproxy"; this.checkbox_usedefaultproxy.LanguageKey = "settings_usedefaultproxy";
this.checkbox_usedefaultproxy.Location = new System.Drawing.Point(7, 11); this.checkbox_usedefaultproxy.Location = new System.Drawing.Point(7, 11);
this.checkbox_usedefaultproxy.Name = "checkbox_usedefaultproxy"; 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(397, 25); this.checkbox_usedefaultproxy.Size = new System.Drawing.Size(397, 25);
this.checkbox_usedefaultproxy.TabIndex = 7; this.checkbox_usedefaultproxy.TabIndex = 7;
this.checkbox_usedefaultproxy.UseVisualStyleBackColor = true; this.checkbox_usedefaultproxy.UseVisualStyleBackColor = true;
@ -564,7 +566,7 @@ namespace Greenshot.Forms {
this.lastregion_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.lastregion_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None;
this.lastregion_hotkeyControl.Location = new System.Drawing.Point(224, 94); this.lastregion_hotkeyControl.Location = new System.Drawing.Point(224, 94);
this.lastregion_hotkeyControl.Name = "lastregion_hotkeyControl"; 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(179, 20); this.lastregion_hotkeyControl.Size = new System.Drawing.Size(179, 20);
this.lastregion_hotkeyControl.TabIndex = 5; this.lastregion_hotkeyControl.TabIndex = 5;
// //
@ -582,7 +584,7 @@ namespace Greenshot.Forms {
this.ie_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.ie_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None;
this.ie_hotkeyControl.Location = new System.Drawing.Point(224, 120); this.ie_hotkeyControl.Location = new System.Drawing.Point(224, 120);
this.ie_hotkeyControl.Name = "ie_hotkeyControl"; 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(179, 20); this.ie_hotkeyControl.Size = new System.Drawing.Size(179, 20);
this.ie_hotkeyControl.TabIndex = 6; this.ie_hotkeyControl.TabIndex = 6;
// //
@ -616,7 +618,7 @@ namespace Greenshot.Forms {
this.region_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.region_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None;
this.region_hotkeyControl.Location = new System.Drawing.Point(224, 68); this.region_hotkeyControl.Location = new System.Drawing.Point(224, 68);
this.region_hotkeyControl.Name = "region_hotkeyControl"; 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(179, 20); this.region_hotkeyControl.Size = new System.Drawing.Size(179, 20);
this.region_hotkeyControl.TabIndex = 4; this.region_hotkeyControl.TabIndex = 4;
// //
@ -626,7 +628,7 @@ namespace Greenshot.Forms {
this.window_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.window_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None;
this.window_hotkeyControl.Location = new System.Drawing.Point(224, 42); this.window_hotkeyControl.Location = new System.Drawing.Point(224, 42);
this.window_hotkeyControl.Name = "window_hotkeyControl"; 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(179, 20); this.window_hotkeyControl.Size = new System.Drawing.Size(179, 20);
this.window_hotkeyControl.TabIndex = 3; this.window_hotkeyControl.TabIndex = 3;
// //
@ -636,7 +638,7 @@ namespace Greenshot.Forms {
this.fullscreen_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.fullscreen_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None;
this.fullscreen_hotkeyControl.Location = new System.Drawing.Point(224, 16); this.fullscreen_hotkeyControl.Location = new System.Drawing.Point(224, 16);
this.fullscreen_hotkeyControl.Name = "fullscreen_hotkeyControl"; 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(179, 20); this.fullscreen_hotkeyControl.Size = new System.Drawing.Size(179, 20);
this.fullscreen_hotkeyControl.TabIndex = 2; this.fullscreen_hotkeyControl.TabIndex = 2;
// //
@ -668,7 +670,7 @@ namespace Greenshot.Forms {
this.checkbox_editor_match_capture_size.LanguageKey = "editor_match_capture_size"; this.checkbox_editor_match_capture_size.LanguageKey = "editor_match_capture_size";
this.checkbox_editor_match_capture_size.Location = new System.Drawing.Point(6, 19); this.checkbox_editor_match_capture_size.Location = new System.Drawing.Point(6, 19);
this.checkbox_editor_match_capture_size.Name = "checkbox_editor_match_capture_size"; 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.SectionName = "Editor";
this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(397, 24); this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(397, 24);
this.checkbox_editor_match_capture_size.TabIndex = 11; this.checkbox_editor_match_capture_size.TabIndex = 11;
@ -689,7 +691,7 @@ namespace Greenshot.Forms {
this.checkbox_ie_capture.LanguageKey = "settings_iecapture"; this.checkbox_ie_capture.LanguageKey = "settings_iecapture";
this.checkbox_ie_capture.Location = new System.Drawing.Point(6, 19); this.checkbox_ie_capture.Location = new System.Drawing.Point(6, 19);
this.checkbox_ie_capture.Name = "checkbox_ie_capture"; 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(404, 24); this.checkbox_ie_capture.Size = new System.Drawing.Size(404, 24);
this.checkbox_ie_capture.TabIndex = 10; this.checkbox_ie_capture.TabIndex = 10;
this.checkbox_ie_capture.UseVisualStyleBackColor = true; this.checkbox_ie_capture.UseVisualStyleBackColor = true;
@ -732,7 +734,7 @@ namespace Greenshot.Forms {
this.radiobuttonInteractiveCapture.LanguageKey = "settings_capture_windows_interactive"; this.radiobuttonInteractiveCapture.LanguageKey = "settings_capture_windows_interactive";
this.radiobuttonInteractiveCapture.Location = new System.Drawing.Point(11, 20); this.radiobuttonInteractiveCapture.Location = new System.Drawing.Point(11, 20);
this.radiobuttonInteractiveCapture.Name = "radiobuttonInteractiveCapture"; this.radiobuttonInteractiveCapture.Name = "radiobuttonInteractiveCapture";
this.radiobuttonInteractiveCapture.PropertyName = "CaptureWindowsInteractive"; this.radiobuttonInteractiveCapture.PropertyName = nameof(CoreConfiguration.CaptureWindowsInteractive);
this.radiobuttonInteractiveCapture.Size = new System.Drawing.Size(203, 17); this.radiobuttonInteractiveCapture.Size = new System.Drawing.Size(203, 17);
this.radiobuttonInteractiveCapture.TabIndex = 6; this.radiobuttonInteractiveCapture.TabIndex = 6;
this.radiobuttonInteractiveCapture.TabStop = true; this.radiobuttonInteractiveCapture.TabStop = true;
@ -770,7 +772,7 @@ namespace Greenshot.Forms {
this.checkbox_zoomer.LanguageKey = "settings_zoom"; this.checkbox_zoomer.LanguageKey = "settings_zoom";
this.checkbox_zoomer.Location = new System.Drawing.Point(11, 79); this.checkbox_zoomer.Location = new System.Drawing.Point(11, 79);
this.checkbox_zoomer.Name = "checkbox_zoomer"; 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(399, 24); this.checkbox_zoomer.Size = new System.Drawing.Size(399, 24);
this.checkbox_zoomer.TabIndex = 4; this.checkbox_zoomer.TabIndex = 4;
this.checkbox_zoomer.UseVisualStyleBackColor = true; this.checkbox_zoomer.UseVisualStyleBackColor = true;
@ -780,7 +782,7 @@ namespace Greenshot.Forms {
this.checkbox_notifications.LanguageKey = "settings_shownotify"; this.checkbox_notifications.LanguageKey = "settings_shownotify";
this.checkbox_notifications.Location = new System.Drawing.Point(11, 59); this.checkbox_notifications.Location = new System.Drawing.Point(11, 59);
this.checkbox_notifications.Name = "checkbox_notifications"; 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(399, 24); this.checkbox_notifications.Size = new System.Drawing.Size(399, 24);
this.checkbox_notifications.TabIndex = 3; this.checkbox_notifications.TabIndex = 3;
this.checkbox_notifications.UseVisualStyleBackColor = true; this.checkbox_notifications.UseVisualStyleBackColor = true;
@ -790,7 +792,7 @@ namespace Greenshot.Forms {
this.checkbox_playsound.LanguageKey = "settings_playsound"; this.checkbox_playsound.LanguageKey = "settings_playsound";
this.checkbox_playsound.Location = new System.Drawing.Point(11, 39); this.checkbox_playsound.Location = new System.Drawing.Point(11, 39);
this.checkbox_playsound.Name = "checkbox_playsound"; 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(399, 24); this.checkbox_playsound.Size = new System.Drawing.Size(399, 24);
this.checkbox_playsound.TabIndex = 2; this.checkbox_playsound.TabIndex = 2;
this.checkbox_playsound.UseVisualStyleBackColor = true; this.checkbox_playsound.UseVisualStyleBackColor = true;
@ -800,7 +802,7 @@ namespace Greenshot.Forms {
this.checkbox_capture_mousepointer.LanguageKey = "settings_capture_mousepointer"; this.checkbox_capture_mousepointer.LanguageKey = "settings_capture_mousepointer";
this.checkbox_capture_mousepointer.Location = new System.Drawing.Point(11, 19); this.checkbox_capture_mousepointer.Location = new System.Drawing.Point(11, 19);
this.checkbox_capture_mousepointer.Name = "checkbox_capture_mousepointer"; 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(394, 24); this.checkbox_capture_mousepointer.Size = new System.Drawing.Size(394, 24);
this.checkbox_capture_mousepointer.TabIndex = 1; this.checkbox_capture_mousepointer.TabIndex = 1;
this.checkbox_capture_mousepointer.UseVisualStyleBackColor = true; this.checkbox_capture_mousepointer.UseVisualStyleBackColor = true;
@ -887,7 +889,7 @@ namespace Greenshot.Forms {
this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; this.checkboxPrintInverted.LanguageKey = "printoptions_inverted";
this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88); this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88);
this.checkboxPrintInverted.Name = "checkboxPrintInverted"; 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.Size = new System.Drawing.Size(141, 17);
this.checkboxPrintInverted.TabIndex = 14; this.checkboxPrintInverted.TabIndex = 14;
this.checkboxPrintInverted.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxPrintInverted.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -900,7 +902,6 @@ namespace Greenshot.Forms {
this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor";
this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19); this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19);
this.radioBtnColorPrint.Name = "radioBtnColorPrint"; this.radioBtnColorPrint.Name = "radioBtnColorPrint";
this.radioBtnColorPrint.PropertyName = "OutputPrintColor";
this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17); this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17);
this.radioBtnColorPrint.TabIndex = 11; this.radioBtnColorPrint.TabIndex = 11;
this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -913,7 +914,7 @@ namespace Greenshot.Forms {
this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale";
this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42); this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42);
this.radioBtnGrayScale.Name = "radioBtnGrayScale"; 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.Size = new System.Drawing.Size(137, 17);
this.radioBtnGrayScale.TabIndex = 12; this.radioBtnGrayScale.TabIndex = 12;
this.radioBtnGrayScale.Text = "Force grayscale printing"; this.radioBtnGrayScale.Text = "Force grayscale printing";
@ -927,7 +928,7 @@ namespace Greenshot.Forms {
this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome";
this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65); this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65);
this.radioBtnMonochrome.Name = "radioBtnMonochrome"; 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.Size = new System.Drawing.Size(148, 17);
this.radioBtnMonochrome.TabIndex = 13; this.radioBtnMonochrome.TabIndex = 13;
this.radioBtnMonochrome.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnMonochrome.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -954,7 +955,7 @@ namespace Greenshot.Forms {
this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; this.checkboxDateTime.LanguageKey = "printoptions_timestamp";
this.checkboxDateTime.Location = new System.Drawing.Point(13, 115); this.checkboxDateTime.Location = new System.Drawing.Point(13, 115);
this.checkboxDateTime.Name = "checkboxDateTime"; 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.Size = new System.Drawing.Size(187, 17);
this.checkboxDateTime.TabIndex = 6; this.checkboxDateTime.TabIndex = 6;
this.checkboxDateTime.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxDateTime.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -967,7 +968,7 @@ namespace Greenshot.Forms {
this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink";
this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23); this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23);
this.checkboxAllowShrink.Name = "checkboxAllowShrink"; 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.Size = new System.Drawing.Size(168, 17);
this.checkboxAllowShrink.TabIndex = 2; this.checkboxAllowShrink.TabIndex = 2;
this.checkboxAllowShrink.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowShrink.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -980,7 +981,7 @@ namespace Greenshot.Forms {
this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge";
this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46); this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46);
this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge"; 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.Size = new System.Drawing.Size(174, 17);
this.checkboxAllowEnlarge.TabIndex = 3; this.checkboxAllowEnlarge.TabIndex = 3;
this.checkboxAllowEnlarge.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowEnlarge.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -993,7 +994,7 @@ namespace Greenshot.Forms {
this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate";
this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69); this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69);
this.checkboxAllowRotate.Name = "checkboxAllowRotate"; 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.Size = new System.Drawing.Size(187, 17);
this.checkboxAllowRotate.TabIndex = 4; this.checkboxAllowRotate.TabIndex = 4;
this.checkboxAllowRotate.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowRotate.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -1006,7 +1007,7 @@ namespace Greenshot.Forms {
this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter";
this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92); this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92);
this.checkboxAllowCenter.Name = "checkboxAllowCenter"; 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.Size = new System.Drawing.Size(137, 17);
this.checkboxAllowCenter.TabIndex = 5; this.checkboxAllowCenter.TabIndex = 5;
this.checkboxAllowCenter.TextAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowCenter.TextAlign = System.Drawing.ContentAlignment.TopLeft;
@ -1017,7 +1018,7 @@ namespace Greenshot.Forms {
this.checkbox_alwaysshowprintoptionsdialog.LanguageKey = "settings_alwaysshowprintoptionsdialog"; this.checkbox_alwaysshowprintoptionsdialog.LanguageKey = "settings_alwaysshowprintoptionsdialog";
this.checkbox_alwaysshowprintoptionsdialog.Location = new System.Drawing.Point(19, 293); this.checkbox_alwaysshowprintoptionsdialog.Location = new System.Drawing.Point(19, 293);
this.checkbox_alwaysshowprintoptionsdialog.Name = "checkbox_alwaysshowprintoptionsdialog"; 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(394, 20); this.checkbox_alwaysshowprintoptionsdialog.Size = new System.Drawing.Size(394, 20);
this.checkbox_alwaysshowprintoptionsdialog.TabIndex = 15; this.checkbox_alwaysshowprintoptionsdialog.TabIndex = 15;
this.checkbox_alwaysshowprintoptionsdialog.Text = "Show print options dialog every time an image is printed"; this.checkbox_alwaysshowprintoptionsdialog.Text = "Show print options dialog every time an image is printed";
@ -1114,7 +1115,7 @@ namespace Greenshot.Forms {
this.checkbox_reuseeditor.LanguageKey = "expertsettings_reuseeditorifpossible"; this.checkbox_reuseeditor.LanguageKey = "expertsettings_reuseeditorifpossible";
this.checkbox_reuseeditor.Location = new System.Drawing.Point(10, 225); this.checkbox_reuseeditor.Location = new System.Drawing.Point(10, 225);
this.checkbox_reuseeditor.Name = "checkbox_reuseeditor"; 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.SectionName = "Editor";
this.checkbox_reuseeditor.Size = new System.Drawing.Size(394, 24); this.checkbox_reuseeditor.Size = new System.Drawing.Size(394, 24);
this.checkbox_reuseeditor.TabIndex = 9; this.checkbox_reuseeditor.TabIndex = 9;
@ -1125,7 +1126,7 @@ namespace Greenshot.Forms {
this.checkbox_minimizememoryfootprint.LanguageKey = "expertsettings_minimizememoryfootprint"; this.checkbox_minimizememoryfootprint.LanguageKey = "expertsettings_minimizememoryfootprint";
this.checkbox_minimizememoryfootprint.Location = new System.Drawing.Point(10, 206); this.checkbox_minimizememoryfootprint.Location = new System.Drawing.Point(10, 206);
this.checkbox_minimizememoryfootprint.Name = "checkbox_minimizememoryfootprint"; 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(394, 24); this.checkbox_minimizememoryfootprint.Size = new System.Drawing.Size(394, 24);
this.checkbox_minimizememoryfootprint.TabIndex = 8; this.checkbox_minimizememoryfootprint.TabIndex = 8;
this.checkbox_minimizememoryfootprint.UseVisualStyleBackColor = true; this.checkbox_minimizememoryfootprint.UseVisualStyleBackColor = true;
@ -1135,7 +1136,7 @@ namespace Greenshot.Forms {
this.checkbox_checkunstableupdates.LanguageKey = "expertsettings_checkunstableupdates"; this.checkbox_checkunstableupdates.LanguageKey = "expertsettings_checkunstableupdates";
this.checkbox_checkunstableupdates.Location = new System.Drawing.Point(10, 187); this.checkbox_checkunstableupdates.Location = new System.Drawing.Point(10, 187);
this.checkbox_checkunstableupdates.Name = "checkbox_checkunstableupdates"; 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(394, 24); this.checkbox_checkunstableupdates.Size = new System.Drawing.Size(394, 24);
this.checkbox_checkunstableupdates.TabIndex = 7; this.checkbox_checkunstableupdates.TabIndex = 7;
this.checkbox_checkunstableupdates.UseVisualStyleBackColor = true; this.checkbox_checkunstableupdates.UseVisualStyleBackColor = true;
@ -1145,7 +1146,7 @@ namespace Greenshot.Forms {
this.checkbox_suppresssavedialogatclose.LanguageKey = "expertsettings_suppresssavedialogatclose"; this.checkbox_suppresssavedialogatclose.LanguageKey = "expertsettings_suppresssavedialogatclose";
this.checkbox_suppresssavedialogatclose.Location = new System.Drawing.Point(10, 168); this.checkbox_suppresssavedialogatclose.Location = new System.Drawing.Point(10, 168);
this.checkbox_suppresssavedialogatclose.Name = "checkbox_suppresssavedialogatclose"; 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.SectionName = "Editor";
this.checkbox_suppresssavedialogatclose.Size = new System.Drawing.Size(394, 24); this.checkbox_suppresssavedialogatclose.Size = new System.Drawing.Size(394, 24);
this.checkbox_suppresssavedialogatclose.TabIndex = 6; this.checkbox_suppresssavedialogatclose.TabIndex = 6;
@ -1163,7 +1164,7 @@ namespace Greenshot.Forms {
// //
this.textbox_counter.Location = new System.Drawing.Point(259, 282); this.textbox_counter.Location = new System.Drawing.Point(259, 282);
this.textbox_counter.Name = "textbox_counter"; 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(141, 20); this.textbox_counter.Size = new System.Drawing.Size(141, 20);
this.textbox_counter.TabIndex = 11; this.textbox_counter.TabIndex = 11;
// //
@ -1180,7 +1181,7 @@ namespace Greenshot.Forms {
// //
this.textbox_footerpattern.Location = new System.Drawing.Point(138, 256); this.textbox_footerpattern.Location = new System.Drawing.Point(138, 256);
this.textbox_footerpattern.Name = "textbox_footerpattern"; 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(262, 20); this.textbox_footerpattern.Size = new System.Drawing.Size(262, 20);
this.textbox_footerpattern.TabIndex = 10; this.textbox_footerpattern.TabIndex = 10;
// //
@ -1189,7 +1190,7 @@ namespace Greenshot.Forms {
this.checkbox_thumbnailpreview.LanguageKey = "expertsettings_thumbnailpreview"; this.checkbox_thumbnailpreview.LanguageKey = "expertsettings_thumbnailpreview";
this.checkbox_thumbnailpreview.Location = new System.Drawing.Point(10, 149); this.checkbox_thumbnailpreview.Location = new System.Drawing.Point(10, 149);
this.checkbox_thumbnailpreview.Name = "checkbox_thumbnailpreview"; 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(394, 24); this.checkbox_thumbnailpreview.Size = new System.Drawing.Size(394, 24);
this.checkbox_thumbnailpreview.TabIndex = 5; this.checkbox_thumbnailpreview.TabIndex = 5;
this.checkbox_thumbnailpreview.UseVisualStyleBackColor = true; this.checkbox_thumbnailpreview.UseVisualStyleBackColor = true;
@ -1199,7 +1200,7 @@ namespace Greenshot.Forms {
this.checkbox_optimizeforrdp.LanguageKey = "expertsettings_optimizeforrdp"; this.checkbox_optimizeforrdp.LanguageKey = "expertsettings_optimizeforrdp";
this.checkbox_optimizeforrdp.Location = new System.Drawing.Point(10, 130); this.checkbox_optimizeforrdp.Location = new System.Drawing.Point(10, 130);
this.checkbox_optimizeforrdp.Name = "checkbox_optimizeforrdp"; 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(394, 24); this.checkbox_optimizeforrdp.Size = new System.Drawing.Size(394, 24);
this.checkbox_optimizeforrdp.TabIndex = 4; this.checkbox_optimizeforrdp.TabIndex = 4;
this.checkbox_optimizeforrdp.UseVisualStyleBackColor = true; this.checkbox_optimizeforrdp.UseVisualStyleBackColor = true;
@ -1209,7 +1210,7 @@ namespace Greenshot.Forms {
this.checkbox_autoreducecolors.LanguageKey = "expertsettings_autoreducecolors"; this.checkbox_autoreducecolors.LanguageKey = "expertsettings_autoreducecolors";
this.checkbox_autoreducecolors.Location = new System.Drawing.Point(10, 111); this.checkbox_autoreducecolors.Location = new System.Drawing.Point(10, 111);
this.checkbox_autoreducecolors.Name = "checkbox_autoreducecolors"; 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(408, 24); this.checkbox_autoreducecolors.Size = new System.Drawing.Size(408, 24);
this.checkbox_autoreducecolors.TabIndex = 3; this.checkbox_autoreducecolors.TabIndex = 3;
this.checkbox_autoreducecolors.UseVisualStyleBackColor = true; this.checkbox_autoreducecolors.UseVisualStyleBackColor = true;
@ -1257,7 +1258,7 @@ namespace Greenshot.Forms {
// //
// SettingsForm // SettingsForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(451, 431); this.ClientSize = new System.Drawing.Size(451, 431);
this.Controls.Add(this.tabcontrol); this.Controls.Add(this.tabcontrol);

View file

@ -37,7 +37,6 @@ using Greenshot.Base.Interfaces;
using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.Interfaces.Plugin;
using Greenshot.Base.UnmanagedHelpers; using Greenshot.Base.UnmanagedHelpers;
using Greenshot.Configuration; using Greenshot.Configuration;
using Greenshot.Destinations;
using Greenshot.Helpers; using Greenshot.Helpers;
using log4net; using log4net;
@ -320,7 +319,7 @@ namespace Greenshot.Forms
combobox_language.SelectedValue = Language.CurrentLanguage; 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; combobox_language.SelectedIndexChanged += Combobox_languageSelectedIndexChanged;
UpdateDestinationDescriptions(); UpdateDestinationDescriptions();
UpdateClipboardFormatDescriptions(); UpdateClipboardFormatDescriptions();
@ -829,22 +828,19 @@ namespace Greenshot.Forms
{ {
public int Compare(object x, object y) public int Compare(object x, object y)
{ {
if (!(x is ListViewItem)) if (x is not ListViewItem listViewItemX)
{ {
return 0; return 0;
} }
if (!(y is ListViewItem)) if (y is not ListViewItem listViewItemY)
{ {
return 0; return 0;
} }
ListViewItem l1 = (ListViewItem) x; IDestination firstDestination = listViewItemX.Tag as IDestination;
ListViewItem l2 = (ListViewItem) y;
IDestination firstDestination = l1.Tag as IDestination; if (listViewItemY.Tag is not IDestination secondDestination)
if (!(l2.Tag is IDestination secondDestination))
{ {
return 1; return 1;
} }

View file

@ -389,6 +389,7 @@ namespace Greenshot.Helpers
HandleCapture(); HandleCapture();
break; break;
case CaptureMode.Clipboard: case CaptureMode.Clipboard:
// TODO: Fix getting image vs. drawablecontainer
Image clipboardImage = ClipboardHelper.GetImage(); Image clipboardImage = ClipboardHelper.GetImage();
if (clipboardImage != null) if (clipboardImage != null)
{ {
@ -430,12 +431,13 @@ namespace Greenshot.Helpers
if (!string.IsNullOrEmpty(filename)) if (!string.IsNullOrEmpty(filename))
{ {
// TODO: Fix that the Greenshot format needs a separate code path
try try
{ {
if (filename.ToLower().EndsWith("." + OutputFormat.greenshot)) if (filename.ToLower().EndsWith("." + OutputFormat.greenshot))
{ {
ISurface surface = new Surface(); ISurface surface = new Surface();
surface = ImageOutput.LoadGreenshotSurface(filename, surface); surface = ImageIO.LoadGreenshotSurface(filename, surface);
surface.CaptureDetails = _capture.CaptureDetails; surface.CaptureDetails = _capture.CaptureDetails;
DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails); DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails);
break; break;
@ -447,9 +449,10 @@ namespace Greenshot.Helpers
MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename));
} }
// TODO: Remove Image loading for here
try try
{ {
fileImage = ImageHelper.LoadImage(filename); fileImage = ImageIO.LoadImage(filename);
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -82,7 +82,7 @@ namespace Greenshot.Helpers
/// <param name="captureDetails">ICaptureDetails</param> /// <param name="captureDetails">ICaptureDetails</param>
public static void SendImage(ISurface surface, ICaptureDetails captureDetails) 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; if (tmpFile == null) return;

View file

@ -187,7 +187,7 @@ namespace Greenshot.Helpers
ApplyEffects(printOutputSettings); ApplyEffects(printOutputSettings);
bool disposeImage = ImageOutput.CreateImageFromSurface(_surface, printOutputSettings, out var image); bool disposeImage = ImageIO.CreateImageFromSurface(_surface, printOutputSettings, out var image);
try try
{ {
ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft; ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft;