diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs index 139a8df32..4c074408e 100644 --- a/Greenshot/Destinations/EmailDestination.cs +++ b/Greenshot/Destinations/EmailDestination.cs @@ -102,10 +102,8 @@ namespace Greenshot.Destinations { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); - using (Image image = surface.GetImageForExport()) { - MapiMailMessage.SendImage(image, captureDetails); - exportInformation.ExportMade = true; - } + MapiMailMessage.SendImage(surface, captureDetails); + exportInformation.ExportMade = true; ProcessExport(exportInformation, surface); return exportInformation; } diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs index 0f2ad6c5a..5f661b25c 100644 --- a/Greenshot/Destinations/FileDestination.cs +++ b/Greenshot/Destinations/FileDestination.cs @@ -29,6 +29,7 @@ using GreenshotPlugin.Core; using Greenshot.Plugin; using Greenshot.Helpers; using Greenshot.IniFile; +using GreenshotPlugin.Controls; namespace Greenshot.Destinations { /// @@ -74,12 +75,15 @@ namespace Greenshot.Destinations { bool outputMade; bool overwrite; string fullPath; + // Get output settings from the configuration + OutputSettings outputSettings = new OutputSettings(); - if (captureDetails.Filename != null) { + if (captureDetails != null && captureDetails.Filename != null) { // As we save a pre-selected file, allow to overwrite. overwrite = true; LOG.InfoFormat("Using previous filename"); fullPath = captureDetails.Filename; + outputSettings.Format = ImageOutput.FormatForFilename(fullPath); } else { LOG.InfoFormat("Creating new filename"); string pattern = conf.OutputFileFilenamePattern; @@ -92,26 +96,29 @@ namespace Greenshot.Destinations { // As we generate a file, the configuration tells us if we allow to overwrite overwrite = conf.OutputFileAllowOverwrite; } + if (conf.OutputFilePromptQuality) { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + // Catching any exception to prevent that the user can't write in the directory. // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - using (Image image = surface.GetImageForExport()) { - try { - ImageOutput.Save(image, fullPath, overwrite); - outputMade = true; - } catch (ArgumentException ex1) { - // Our generated filename exists, display 'save-as' - LOG.InfoFormat("Not overwriting: {0}", ex1.Message); - // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(image, captureDetails); - outputMade = (fullPath != null); - } catch (Exception ex2) { - LOG.Error("Error saving screenshot!", ex2); - // Show the problem - MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(image, captureDetails); - outputMade = (fullPath != null); - } + try { + ImageOutput.Save(surface, fullPath, overwrite, outputSettings, conf.OutputFileCopyPathToClipboard); + outputMade = true; + } catch (ArgumentException ex1) { + // Our generated filename exists, display 'save-as' + LOG.InfoFormat("Not overwriting: {0}", ex1.Message); + // when we don't allow to overwrite present a new SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = (fullPath != null); + } catch (Exception ex2) { + LOG.Error("Error saving screenshot!", ex2); + // Show the problem + MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); + // when save failed we present a SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = (fullPath != null); } // Don't overwite filename if no output is made if (outputMade) { @@ -119,6 +126,7 @@ namespace Greenshot.Destinations { exportInformation.Filepath = fullPath; captureDetails.Filename = fullPath; } + ProcessExport(exportInformation, surface); return exportInformation; } diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs index bcb5fb878..9f0fd1682 100644 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/Greenshot/Destinations/FileWithDialogDestination.cs @@ -72,14 +72,12 @@ namespace Greenshot.Destinations { public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); string savedTo = null; - using (Image image = surface.GetImageForExport()) { - // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - savedTo = ImageOutput.SaveWithDialog(image, captureDetails); - if (savedTo != null) { - exportInformation.ExportMade = true; - exportInformation.Filepath = savedTo; - captureDetails.Filename = savedTo; - } + // Bug #2918756 don't overwrite path if SaveWithDialog returns null! + savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); + if (savedTo != null) { + exportInformation.ExportMade = true; + exportInformation.Filepath = savedTo; + captureDetails.Filename = savedTo; } ProcessExport(exportInformation, surface); return exportInformation; diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 7c8bba123..ead8ea08d 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -232,6 +232,7 @@ namespace Greenshot.Drawing { } set { image = value; + Size = image.Size; } } diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 935a93e3b..d9157a282 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -336,6 +336,10 @@ namespace Greenshot { } } + /// + /// This is called when the size of the surface chances, used for resizing and displaying the size information + /// + /// private void SurfaceSizeChanged(object source) { if (editorConfiguration.MatchSizeToCapture) { // Set editor's initial size to the size of the surface plus the size of the chrome diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index fd7561192..1127e8ffc 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -593,7 +593,7 @@ namespace Greenshot { void CaptureFile() { OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = "Image files (*.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf"; + openFileDialog.Filter = "Image files (*.greenshot, *.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.greenshot; *.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf"; if (openFileDialog.ShowDialog() == DialogResult.OK) { if (File.Exists(openFileDialog.FileName)) { CaptureHelper.CaptureFile(openFileDialog.FileName); diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 1d602a1df..202ee5a99 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -331,11 +331,10 @@ namespace Greenshot.Helpers { if (!string.IsNullOrEmpty(filename)) { try { - if (filename.EndsWith(".gsf")) { - + if (filename.ToLower().EndsWith("." + OutputFormat.greenshot)) { ISurface surface = new Surface(); - surface = ImageOutput.LoadGreenshotSurface(filename, surface); + surface.CaptureDetails = capture.CaptureDetails; DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, capture.CaptureDetails); break; } diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index 811af7cd5..238189be7 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -64,8 +64,8 @@ namespace Greenshot.Helpers { /// /// The image to send /// ICaptureDetails - public static void SendImage(Image image, ICaptureDetails captureDetails) { - string tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, new OutputSettings()); + public static void SendImage(ISurface surface, ICaptureDetails captureDetails) { + string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new OutputSettings()); if (tmpFile != null) { // Store the list of currently active windows, so we can make sure we show the email window later! diff --git a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs index 45bcd9e8d..1a76e1582 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs @@ -74,9 +74,7 @@ namespace ExternalCommand { bool runInBackground = config.runInbackground[presetCommand]; string fullPath = captureDetails.Filename; if (fullPath == null) { - using (Image image = surface.GetImageForExport()) { - fullPath = ImageOutput.SaveNamedTmpFile(image, captureDetails, outputSettings); - } + fullPath = ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); } string output = null; diff --git a/GreenshotOfficePlugin/Destinations/ExcelDestination.cs b/GreenshotOfficePlugin/Destinations/ExcelDestination.cs index e80fb0ddc..c37626c43 100644 --- a/GreenshotOfficePlugin/Destinations/ExcelDestination.cs +++ b/GreenshotOfficePlugin/Destinations/ExcelDestination.cs @@ -111,9 +111,7 @@ namespace GreenshotOfficePlugin { ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); string tmpFile = captureDetails.Filename; if (tmpFile == null || surface.Modified) { - using (Image image = surface.GetImageForExport()) { - tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, new OutputSettings()); - } + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new OutputSettings(OutputFormat.png)); } if (workbookName != null) { ExcelExporter.InsertIntoExistingWorkbook(workbookName, tmpFile); diff --git a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs index 1ce1d0e63..6616596e5 100644 --- a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs +++ b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs @@ -153,9 +153,7 @@ namespace GreenshotOfficePlugin { // Outlook logic string tmpFile = captureDetails.Filename; if (tmpFile == null || surface.Modified) { - using (Image image = surface.GetImageForExport()) { - tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, new OutputSettings()); - } + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new OutputSettings()); } else { LOG.InfoFormat("Using already available file: {0}", tmpFile); } diff --git a/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs b/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs index 18d100f91..bd89a0777 100644 --- a/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs +++ b/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs @@ -113,10 +113,8 @@ namespace GreenshotOfficePlugin { string tmpFile = captureDetails.Filename; Size imageSize = Size.Empty; if (tmpFile == null || surface.Modified) { - using (Image image = surface.GetImageForExport()) { - tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, new OutputSettings()); - imageSize = image.Size; - } + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new OutputSettings()); + imageSize = surface.Image.Size; } if (presentationName != null) { exportInformation.ExportMade = PowerpointExporter.ExportToPresentation(presentationName, tmpFile, imageSize, captureDetails.Title); diff --git a/GreenshotOfficePlugin/Destinations/WordDestination.cs b/GreenshotOfficePlugin/Destinations/WordDestination.cs index 1dd269bb2..c1fafe86d 100644 --- a/GreenshotOfficePlugin/Destinations/WordDestination.cs +++ b/GreenshotOfficePlugin/Destinations/WordDestination.cs @@ -112,9 +112,7 @@ namespace GreenshotOfficePlugin { ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); string tmpFile = captureDetails.Filename; if (tmpFile == null || surface.Modified) { - using (Image image = surface.GetImageForExport()) { - tmpFile = ImageOutput.SaveNamedTmpFile(image, captureDetails, new OutputSettings()); - } + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new OutputSettings(OutputFormat.png)); } if (documentCaption != null) { try { diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index 654b537c5..8c6c6670a 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -31,7 +31,7 @@ namespace GreenshotPlugin.Core { PNG, DIB, HTML, HTMLDATAURL } public enum OutputFormat { - bmp, gif, jpg, png, tiff + bmp, gif, jpg, png, tiff, greenshot } public enum WindowCaptureMode { Screen, GDI, Aero, AeroTransparent, Auto diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs index 7a7ee25e6..78f3cb1fb 100644 --- a/GreenshotPlugin/Core/ImageOutput.cs +++ b/GreenshotPlugin/Core/ImageOutput.cs @@ -216,6 +216,11 @@ namespace GreenshotPlugin.Core { long bytesWritten = surface.SaveElementsToStream(stream); using (BinaryWriter writer = new BinaryWriter(stream)) { writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + string marker = String.Format("Greenshot{0:00}.{1:00}", v.Major, v.Minor); + using (StreamWriter streamWriter = new StreamWriter(stream)) { + streamWriter.Write(marker); + } } } } @@ -232,25 +237,38 @@ namespace GreenshotPlugin.Core { Bitmap fileBitmap = null; LOG.InfoFormat("Loading image from file {0}", fullPath); // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(fullPath)) { + using (Stream surfaceFileStream = File.OpenRead(fullPath)) { // And 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 - imageFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) { + surfaceFileStream.Position = 0; + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) { LOG.DebugFormat("Loaded {0} with Size {1}x{2} and PixelFormat {3}", fullPath, tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); fileBitmap = ImageHelper.Clone(tmpImage); } - imageFileStream.Seek(-8, SeekOrigin.End); - long bytesWritten = 0; - using (BinaryReader reader = new BinaryReader(imageFileStream)) { - bytesWritten = reader.ReadInt64(); - imageFileStream.Seek(-(bytesWritten + 8), SeekOrigin.End); - returnSurface.LoadElementsFromStream(imageFileStream); + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + string greenshotMarker; + using (StreamReader streamReader = new StreamReader(surfaceFileStream)) { + greenshotMarker = streamReader.ReadToEnd(); + if (greenshotMarker == null || !greenshotMarker.StartsWith("Greenshot")) { + throw new ArgumentException(string.Format("{0} is not a Greenshot file!", fullPath)); + } + LOG.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + long bytesWritten = 0; + using (BinaryReader reader = new BinaryReader(surfaceFileStream)) { + bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } } } if (fileBitmap != null) { + returnSurface.Image = fileBitmap; LOG.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, fileBitmap.Width, fileBitmap.Height, fileBitmap.PixelFormat, fileBitmap.HorizontalResolution, fileBitmap.VerticalResolution); } return returnSurface; @@ -297,12 +315,46 @@ namespace GreenshotPlugin.Core { } /// - /// saves img to fullpath + /// Saves image to specific path with specified quality /// - /// the image to save - /// the absolute destination path including file name - /// true if overwrite is allowed, false if not - public static void Save(Image img, string fullPath, bool allowOverwrite) { + public static void Save(ISurface surface, string fullPath, bool allowOverwrite, OutputSettings outputSettings, bool copyPathToClipboard) { + fullPath = FilenameHelper.MakeFQFilenameSafe(fullPath); + string path = Path.GetDirectoryName(fullPath); + + // check whether path exists - if not create it + DirectoryInfo di = new DirectoryInfo(path); + if (!di.Exists) { + Directory.CreateDirectory(di.FullName); + } + + if (!allowOverwrite && File.Exists(fullPath)) { + ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); + throwingException.Data.Add("fullPath", fullPath); + throw throwingException; + } + LOG.DebugFormat("Saving image to {0}", fullPath); + // Create the stream and call SaveToStream + if (outputSettings.Format == OutputFormat.greenshot) { + SaveGreenshotSurface(surface, fullPath); + } else { + using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) { + using (Image image = surface.GetImageForExport()) { + SaveToStream(image, stream, outputSettings); + } + } + } + + if (copyPathToClipboard) { + ClipboardHelper.SetClipboardData(fullPath); + } + } + + /// + /// Get the OutputFormat for a filename + /// + /// filename (can be a complete path) + /// OutputFormat + public static OutputFormat FormatForFilename(string fullPath) { // Fix for bug 2912959 string extension = fullPath.Substring(fullPath.LastIndexOf(".") + 1); OutputFormat format = OutputFormat.png; @@ -313,6 +365,17 @@ namespace GreenshotPlugin.Core { } catch (ArgumentException ae) { LOG.Warn("Couldn't parse extension: " + extension, ae); } + return format; + } + + /// + /// saves img to fullpath + /// + /// the image to save + /// the absolute destination path including file name + /// true if overwrite is allowed, false if not + public static void Save(Image img, string fullPath, bool allowOverwrite) { + OutputFormat format = FormatForFilename(fullPath); // Get output settings from the configuration OutputSettings outputSettings = new OutputSettings(format); if (conf.OutputFilePromptQuality) { @@ -324,19 +387,27 @@ namespace GreenshotPlugin.Core { #endregion #region save-as - public static string SaveWithDialog(Image image) { - return SaveWithDialog(image, null); - } - public static string SaveWithDialog(Image image, ICaptureDetails captureDetails) { + /// + /// Save with showing a dialog + /// + /// + /// + /// Path to filename + public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) { string returnValue = null; SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails); DialogResult dialogResult = saveImageFileDialog.ShowDialog(); if (dialogResult.Equals(DialogResult.OK)) { try { string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - // TODO: For now we overwrite, should be changed - ImageOutput.Save(image, fileNameWithExtension, true); + OutputSettings outputSettings = new OutputSettings(FormatForFilename(fileNameWithExtension)); + if (conf.OutputFilePromptQuality) { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + // TODO: For now we always overwrite, should be changed + ImageOutput.Save(surface, fileNameWithExtension, true, outputSettings, conf.OutputFileCopyPathToClipboard); returnValue = fileNameWithExtension; conf.OutputFileAsFullpath = fileNameWithExtension; IniConfig.Save(); @@ -348,7 +419,15 @@ namespace GreenshotPlugin.Core { } #endregion - public static string SaveNamedTmpFile(Image image, ICaptureDetails captureDetails, OutputSettings outputSettings) { + /// + /// Create a tmpfile which has the name like in the configured pattern. + /// Used e.g. by the email export + /// + /// + /// + /// + /// Path to image file + public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, OutputSettings outputSettings) { string pattern = conf.OutputFileFilenamePattern; if (pattern == null || string.IsNullOrEmpty(pattern.Trim())) { pattern = "greenshot ${capturetime}"; @@ -365,13 +444,13 @@ namespace GreenshotPlugin.Core { // Catching any exception to prevent that the user can't write in the directory. // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 try { - ImageOutput.Save(image, tmpFile, true, outputSettings, false); + ImageOutput.Save(surface, tmpFile, true, outputSettings, false); tmpFileCache.Add(tmpFile, tmpFile); } catch (Exception e) { // Show the problem MessageBox.Show(e.Message, "Error"); // when save failed we present a SaveWithDialog - tmpFile = ImageOutput.SaveWithDialog(image, captureDetails); + tmpFile = ImageOutput.SaveWithDialog(surface, captureDetails); } return tmpFile; } diff --git a/GreenshotPlugin/Interfaces/Generic.cs b/GreenshotPlugin/Interfaces/Generic.cs index 00efc7dd5..df26ffd88 100644 --- a/GreenshotPlugin/Interfaces/Generic.cs +++ b/GreenshotPlugin/Interfaces/Generic.cs @@ -153,5 +153,10 @@ namespace Greenshot.Plugin { bool HasCursor { get; } + + ICaptureDetails CaptureDetails { + get; + set; + } } } \ No newline at end of file