diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs
index 6b5b47566..47ddf210b 100644
--- a/GreenshotPlugin/Core/ClipboardHelper.cs
+++ b/GreenshotPlugin/Core/ClipboardHelper.cs
@@ -22,6 +22,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
+using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Threading;
@@ -311,25 +312,43 @@ EndSelection:<<<<<<<4
try {
MemoryStream imageStream = null;
- if (!isValidStream(imageStream) && formats.Contains(FORMAT_PNG)) {
+ if (formats.Contains(FORMAT_PNG)) {
imageStream = GetFromDataObject(dataObject, FORMAT_PNG) as MemoryStream;
- }
- if (!isValidStream(imageStream) && formats.Contains(FORMAT_JPG)) {
- imageStream = GetFromDataObject(dataObject, FORMAT_JPG) as MemoryStream;
- }
- if (!isValidStream(imageStream) && formats.Contains(DataFormats.Tiff)) {
- imageStream = GetFromDataObject(dataObject, DataFormats.Tiff) as MemoryStream;
- }
-
- if (isValidStream(imageStream)) {
- try {
- using (Image tmpImage = Image.FromStream(imageStream)) {
- return ImageHelper.Clone(tmpImage);
+ if (isValidStream(imageStream)) {
+ try {
+ using (Image tmpImage = Image.FromStream(imageStream)) {
+ return ImageHelper.Clone(tmpImage);
+ }
+ } catch (Exception streamImageEx) {
+ LOG.Error("Problem retrieving PNG image from clipboard.", streamImageEx);
}
- } catch (Exception streamImageEx) {
- LOG.Error("Problem retrieving Image from clipboard.", streamImageEx);
}
}
+ if (formats.Contains(FORMAT_JPG)) {
+ imageStream = GetFromDataObject(dataObject, FORMAT_JPG) as MemoryStream;
+ if (isValidStream(imageStream)) {
+ try {
+ using (Image tmpImage = Image.FromStream(imageStream)) {
+ return ImageHelper.Clone(tmpImage);
+ }
+ } catch (Exception streamImageEx) {
+ LOG.Error("Problem retrieving JPG image from clipboard.", streamImageEx);
+ }
+ }
+ }
+ if (formats.Contains(DataFormats.Tiff)) {
+ imageStream = GetFromDataObject(dataObject, DataFormats.Tiff) as MemoryStream;
+ if (isValidStream(imageStream)) {
+ try {
+ using (Image tmpImage = Image.FromStream(imageStream)) {
+ return ImageHelper.Clone(tmpImage);
+ }
+ } catch (Exception streamImageEx) {
+ LOG.Error("Problem retrieving TIFF image from clipboard.", streamImageEx);
+ }
+ }
+ }
+
// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1
try {
// If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from:
@@ -466,14 +485,19 @@ EndSelection:<<<<<<<4
MemoryStream dibStream = null;
MemoryStream pngStream = null;
+ Image imageToSave = null;
+ bool disposeImage = false;
try {
+ SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
+ // Create the image which is going to be saved so we don't create it multiple times
+ disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave);
try {
// Create PNG stream
if (config.ClipboardFormats.Contains(ClipboardFormat.PNG)) {
pngStream = new MemoryStream();
// PNG works for e.g. Powerpoint
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
- ImageOutput.SaveToStream(surface, pngStream, pngOutputSettings);
+ ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
pngStream.Seek(0, SeekOrigin.Begin);
// Set the PNG stream
ido.SetData(FORMAT_PNG, false, pngStream);
@@ -482,13 +506,12 @@ EndSelection:<<<<<<<4
LOG.Error("Error creating PNG for the Clipboard.", pngEX);
}
-
try {
if (config.ClipboardFormats.Contains(ClipboardFormat.DIB)) {
using (MemoryStream tmpBmpStream = new MemoryStream()) {
// Save image as BMP
SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false);
- ImageOutput.SaveToStream(surface, tmpBmpStream, bmpOutputSettings);
+ ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings);
dibStream = new MemoryStream();
// Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14
@@ -514,7 +537,12 @@ EndSelection:<<<<<<<4
// Do not allow to reduce the colors, some applications dislike 256 color images
// reported with bug #3594681
pngOutputSettings.DisableReduceColors = true;
- ImageOutput.SaveToStream(surface, tmpPNGStream, pngOutputSettings);
+ // Check if we can use the previously used image
+ if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) {
+ ImageOutput.SaveToStream(imageToSave, surface, tmpPNGStream, pngOutputSettings);
+ } else {
+ ImageOutput.SaveToStream(surface, tmpPNGStream, pngOutputSettings);
+ }
html = getHTMLDataURLString(surface, tmpPNGStream);
}
ido.SetText(html, TextDataFormat.Html);
@@ -523,11 +551,9 @@ EndSelection:<<<<<<<4
// we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone!
// Check if Bitmap is wanted
if (config.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) {
- using (Image tmpImage = surface.GetImageForExport()) {
- ido.SetImage(tmpImage);
- // Place the DataObject to the clipboard
- SetDataObject(ido, true);
- }
+ ido.SetImage(imageToSave);
+ // Place the DataObject to the clipboard
+ SetDataObject(ido, true);
} else {
// Place the DataObject to the clipboard
SetDataObject(ido, true);
@@ -542,6 +568,10 @@ EndSelection:<<<<<<<4
dibStream.Dispose();
dibStream = null;
}
+ // cleanup if needed
+ if (disposeImage && imageToSave != null) {
+ imageToSave.Dispose();
+ }
}
}
diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs
index 7f710af4c..2fa7a4808 100644
--- a/GreenshotPlugin/Core/ImageOutput.cs
+++ b/GreenshotPlugin/Core/ImageOutput.cs
@@ -69,117 +69,65 @@ namespace GreenshotPlugin.Core {
return propertyItem;
}
#region save
+ ///
+ /// Saves ISurface to stream with specified output settings
+ ///
+ /// ISurface to save
+ /// Stream to save to
+ /// SurfaceOutputSettings
+ public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) {
+ Image imageToSave = null;
+ bool disposeImage = CreateImageFromSurface(surface, outputSettings, out imageToSave);
+ SaveToStream(imageToSave, surface, stream, outputSettings);
+ // cleanup if needed
+ if (disposeImage && imageToSave != null) {
+ imageToSave.Dispose();
+ }
+ }
///
/// Saves image to stream with specified quality
/// To prevent problems with GDI version of before Windows 7:
/// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used.
///
- public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) {
+ /// image to save
+ /// surface for the elements, if the greenshot format is used
+ /// Stream to save to
+ /// SurfaceOutputSettings
+ public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) {
ImageFormat imageFormat = null;
- bool disposeImage = false;
bool useMemoryStream = false;
MemoryStream memoryStream = null;
- switch (outputSettings.Format) {
- case OutputFormat.bmp:
- imageFormat = ImageFormat.Bmp;
- break;
- case OutputFormat.gif:
- imageFormat = ImageFormat.Gif;
- break;
- case OutputFormat.jpg:
- imageFormat = ImageFormat.Jpeg;
- break;
- case OutputFormat.tiff:
- imageFormat = ImageFormat.Tiff;
- break;
- case OutputFormat.greenshot:
- case OutputFormat.png:
- default:
- // Problem with non-seekable streams most likely doesn't happen with Windows 7 (OS Version 6.1 and later)
- // http://stackoverflow.com/questions/8349260/generic-gdi-error-on-one-machine-but-not-the-other
- if (!stream.CanSeek) {
- int majorVersion = Environment.OSVersion.Version.Major;
- int minorVersion = Environment.OSVersion.Version.Minor;
- if (majorVersion < 6 || (majorVersion == 6 && minorVersion == 0)) {
- useMemoryStream = true;
- LOG.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
- }
- }
- imageFormat = ImageFormat.Png;
- break;
- }
-
- // check what image we want to save
- Image imageToSave = null;
- if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) {
- // We save the image of the surface, this should not be disposed
- imageToSave = surface.Image;
- } else {
- // We create the export image of the surface to save
- imageToSave = surface.GetImageForExport();
- disposeImage = true;
- }
-
try {
- // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise!
- if (outputSettings.Format != OutputFormat.greenshot) {
- Image tmpImage;
- if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) {
- // apply effects, if there are any
- Point ignoreOffset;
- tmpImage = ImageHelper.ApplyEffects((Bitmap)imageToSave, outputSettings.Effects, out ignoreOffset);
- if (tmpImage != null) {
- if (disposeImage) {
- imageToSave.Dispose();
- }
- imageToSave = tmpImage;
- disposeImage = true;
- }
- }
-
- // Removing transparency if it's not supported in the output
- if (imageFormat != ImageFormat.Png && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) {
- Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
- if (disposeImage) {
- imageToSave.Dispose();
- }
- // Make sure the image is disposed!
- disposeImage = true;
- imageToSave = nonAlphaImage;
- }
-
- // check for color reduction, forced or automatically, only when the DisableReduceColors is false
- if (!outputSettings.DisableReduceColors && (conf.OutputFileAutoReduceColors || outputSettings.ReduceColors)) {
- WuQuantizer quantizer = new WuQuantizer((Bitmap)imageToSave);
- int colorCount = quantizer.GetColorCount();
- LOG.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount);
- if (outputSettings.ReduceColors || colorCount < 256) {
- try {
- LOG.Info("Reducing colors on bitmap to 255.");
- tmpImage = quantizer.GetQuantizedImage(255);
- if (disposeImage) {
- imageToSave.Dispose();
- }
- imageToSave = tmpImage;
- // Make sure the "new" image is disposed
- disposeImage = true;
- } catch (Exception e) {
- LOG.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e);
+ switch (outputSettings.Format) {
+ case OutputFormat.bmp:
+ imageFormat = ImageFormat.Bmp;
+ break;
+ case OutputFormat.gif:
+ imageFormat = ImageFormat.Gif;
+ break;
+ case OutputFormat.jpg:
+ imageFormat = ImageFormat.Jpeg;
+ break;
+ case OutputFormat.tiff:
+ imageFormat = ImageFormat.Tiff;
+ break;
+ case OutputFormat.greenshot:
+ case OutputFormat.png:
+ default:
+ // Problem with non-seekable streams most likely doesn't happen with Windows 7 (OS Version 6.1 and later)
+ // http://stackoverflow.com/questions/8349260/generic-gdi-error-on-one-machine-but-not-the-other
+ if (!stream.CanSeek) {
+ int majorVersion = Environment.OSVersion.Version.Major;
+ int minorVersion = Environment.OSVersion.Version.Minor;
+ if (majorVersion < 6 || (majorVersion == 6 && minorVersion == 0)) {
+ useMemoryStream = true;
+ LOG.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
}
}
- }
-
- // Create meta-data
- PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot");
- if (softwareUsedPropertyItem != null) {
- try {
- imageToSave.SetPropertyItem(softwareUsedPropertyItem);
- } catch (ArgumentException) {
- LOG.WarnFormat("Image of type {0} do not support property {1}", imageFormat, softwareUsedPropertyItem.Id);
- }
- }
+ imageFormat = ImageFormat.Png;
+ break;
}
LOG.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat);
@@ -197,7 +145,17 @@ namespace GreenshotPlugin.Core {
if (imageCodec.FormatID == imageFormat.Guid) {
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality);
- imageToSave.Save(targetStream, imageCodec, parameters);
+ // 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();
+ nonAlphaImage = null;
+ } else {
+ AddTag(imageToSave);
+ imageToSave.Save(targetStream, imageCodec, parameters);
+ }
foundEncoder = true;
break;
}
@@ -206,7 +164,17 @@ namespace GreenshotPlugin.Core {
throw new ApplicationException("No JPG encoder found, this should not happen.");
}
} else {
- imageToSave.Save(targetStream, imageFormat);
+ // Removing transparency if it's not supported in the output
+ if (imageFormat != ImageFormat.Png && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) {
+ Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
+ AddTag(nonAlphaImage);
+ nonAlphaImage.Save(targetStream, imageFormat);
+ nonAlphaImage.Dispose();
+ nonAlphaImage = null;
+ } else {
+ AddTag(imageToSave);
+ imageToSave.Save(targetStream, imageFormat);
+ }
}
// If we used a memory stream, we need to stream the memory stream to the original stream.
@@ -231,9 +199,100 @@ namespace GreenshotPlugin.Core {
if (memoryStream != null) {
memoryStream.Dispose();
}
- // cleanup if needed
- if (disposeImage && imageToSave != null) {
- imageToSave.Dispose();
+ }
+ }
+
+ ///
+ /// Create an image from a surface with the settings from the output settings applied
+ ///
+ ///
+ ///
+ ///
+ /// true if the image must be disposed
+ public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) {
+ bool disposeImage = false;
+ ImageFormat imageFormat = null;
+ switch (outputSettings.Format) {
+ case OutputFormat.bmp:
+ imageFormat = ImageFormat.Bmp;
+ break;
+ case OutputFormat.gif:
+ imageFormat = ImageFormat.Gif;
+ break;
+ case OutputFormat.jpg:
+ imageFormat = ImageFormat.Jpeg;
+ break;
+ case OutputFormat.tiff:
+ imageFormat = ImageFormat.Tiff;
+ break;
+ case OutputFormat.greenshot:
+ case OutputFormat.png:
+ default:
+ imageFormat = ImageFormat.Png;
+ break;
+ }
+
+ if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) {
+ // We save the image of the surface, this should not be disposed
+ imageToSave = surface.Image;
+ } else {
+ // We create the export image of the surface to save
+ imageToSave = surface.GetImageForExport();
+ disposeImage = true;
+ }
+
+ // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise!
+ if (outputSettings.Format != OutputFormat.greenshot) {
+ Image tmpImage;
+ if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) {
+ // apply effects, if there are any
+ Point ignoreOffset;
+ tmpImage = ImageHelper.ApplyEffects((Bitmap)imageToSave, outputSettings.Effects, out ignoreOffset);
+ if (tmpImage != null) {
+ if (disposeImage) {
+ imageToSave.Dispose();
+ }
+ imageToSave = tmpImage;
+ disposeImage = true;
+ }
+ }
+
+ // check for color reduction, forced or automatically, only when the DisableReduceColors is false
+ if (!outputSettings.DisableReduceColors && (conf.OutputFileAutoReduceColors || outputSettings.ReduceColors)) {
+ WuQuantizer quantizer = new WuQuantizer((Bitmap)imageToSave);
+ int colorCount = quantizer.GetColorCount();
+ LOG.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount);
+ if (outputSettings.ReduceColors || colorCount < 256) {
+ try {
+ LOG.Info("Reducing colors on bitmap to 255.");
+ tmpImage = quantizer.GetQuantizedImage(255);
+ if (disposeImage) {
+ imageToSave.Dispose();
+ }
+ imageToSave = tmpImage;
+ // Make sure the "new" image is disposed
+ disposeImage = true;
+ } catch (Exception e) {
+ LOG.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e);
+ }
+ }
+ }
+ }
+ return disposeImage;
+ }
+
+ ///
+ /// Add the greenshot property!
+ ///
+ ///
+ private static void AddTag(Image imageToSave) {
+ // Create meta-data
+ PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot");
+ if (softwareUsedPropertyItem != null) {
+ try {
+ imageToSave.SetPropertyItem(softwareUsedPropertyItem);
+ } catch (Exception) {
+ LOG.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
}
}
}