diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index f6bc84ed7..51d09da11 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -237,6 +237,11 @@ namespace GreenshotPlugin.Core { [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] public string MailApiBCC; + [IniProperty("OptimizePNGCommand", Description = "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", DefaultValue = "")] + public string OptimizePNGCommand; + [IniProperty("OptimizePNGCommandArguments", Description = "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", DefaultValue = "\"{0}\"")] + public string OptimizePNGCommandArguments; + // Specifies what THIS build is public BuildStates BuildState = BuildStates.UNSTABLE; diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs index 4407a00da..9aaddd30c 100644 --- a/GreenshotPlugin/Core/ImageOutput.cs +++ b/GreenshotPlugin/Core/ImageOutput.cs @@ -29,6 +29,8 @@ using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.Controls; using Greenshot.Core; +using System.Diagnostics; +using System.Security.AccessControl; namespace GreenshotPlugin.Core { /// @@ -167,17 +169,25 @@ namespace GreenshotPlugin.Core { throw new ApplicationException("No JPG encoder found, this should not happen."); } } else { + bool needsDispose = false; // 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 = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + needsDispose = true; + } + AddTag(imageToSave); + // Added for OptiPNG + bool processed = false; + if (imageFormat == ImageFormat.Png && !string.IsNullOrEmpty(conf.OptimizePNGCommand)) { + processed = ProcessPNGImageExternally(imageToSave, targetStream); + } + if (!processed) { imageToSave.Save(targetStream, imageFormat); } + if (needsDispose) { + imageToSave.Dispose(); + imageToSave = null; + } } // If we used a memory stream, we need to stream the memory stream to the original stream. @@ -204,7 +214,65 @@ namespace GreenshotPlugin.Core { } } } - + + /// + /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream + /// + /// Image to pass to the external process + /// stream to write the processed image to + /// + private static bool ProcessPNGImageExternally(Image imageToProcess, Stream targetStream) { + if (string.IsNullOrEmpty(conf.OptimizePNGCommand)) { + return false; + } + if (!File.Exists(conf.OptimizePNGCommand)) { + LOG.WarnFormat("Can't find 'OptimizePNGCommand' {0}", conf.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}", conf.OptimizePNGCommand); + } + + ProcessStartInfo processStartInfo = new ProcessStartInfo(conf.OptimizePNGCommand); + processStartInfo.Arguments = string.Format(conf.OptimizePNGCommandArguments, tmpFileName); + processStartInfo.CreateNoWindow = true; + processStartInfo.RedirectStandardOutput = true; + processStartInfo.RedirectStandardError = true; + processStartInfo.UseShellExecute = false; + Process process = Process.Start(processStartInfo); + 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; + } + /// /// Create an image from a surface with the settings from the output settings applied ///