Added the possibility to call optipng, or eventually other optimizers, on the PNG file. This can be used with any PNG file, it's not important if there is an upload or saving to file, as the optimizer runs on a temporary file which is read back and than deleted. Was requested with feature request [#267]. This change only enables the functionality, there is not yet a GUI entry for it.

git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@2535 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
RKrom 2013-03-25 13:42:21 +00:00
commit 7823138adc
2 changed files with 81 additions and 8 deletions

View file

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

View file

@ -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 {
/// <summary>
@ -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 {
}
}
}
/// <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(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;
}
/// <summary>
/// Create an image from a surface with the settings from the output settings applied
/// </summary>