diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs index 1b2e6ab68..aca8ae47d 100644 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/Greenshot/Drawing/Filters/BlurFilter.cs @@ -25,13 +25,10 @@ using Greenshot.Plugin.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.UnmanagedHelpers; using System.Drawing.Drawing2D; -using log4net; namespace Greenshot.Drawing.Filters { - [Serializable()] + [Serializable] public class BlurFilter : AbstractFilter { - private static ILog LOG = LogManager.GetLogger(typeof(BlurFilter)); - public double previewQuality; public double PreviewQuality { get { return previewQuality; } @@ -43,7 +40,7 @@ namespace Greenshot.Drawing.Filters { AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); } - public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { @@ -54,7 +51,7 @@ namespace Greenshot.Drawing.Filters { graphics.SetClip(applyRect); graphics.ExcludeClip(rect); } - if (GDIplus.isBlurPossible(blurRadius)) { + if (GDIplus.IsBlurPossible(blurRadius)) { GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); } else { using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { @@ -63,7 +60,6 @@ namespace Greenshot.Drawing.Filters { } } graphics.Restore(state); - return; } } } diff --git a/Greenshot/releases/additional_files/readme.txt.template b/Greenshot/releases/additional_files/readme.txt.template index 0881700f2..ae0f98504 100644 --- a/Greenshot/releases/additional_files/readme.txt.template +++ b/Greenshot/releases/additional_files/readme.txt.template @@ -7,8 +7,17 @@ CHANGE LOG: All details to our tickets can be found here: https://greenshot.atlassian.net + @DETAILVERSION@ +Changes for this release: +This has Imgur improvements for the newer API version, this is a backport from Greenshot 1.2.9 +With the move to a new hosting platform, we also noticed our update checks are way to often, this needed to be reduced. + + + +1.2.8.12-cab854b RELEASE + There were some major issues with the authenticated (non anonymous) uploads to Imgur. After contacting Imgur they told us that their old API was deprecated or disabled, unfortunately this was not communicated. Although we are working hard on Greenshot 1.3, where we changed most of the Imgur code already, we can't release it. diff --git a/GreenshotImgurPlugin/Forms/ImgurForm.cs b/GreenshotImgurPlugin/Forms/ImgurForm.cs index d476f9313..00d3c01fd 100644 --- a/GreenshotImgurPlugin/Forms/ImgurForm.cs +++ b/GreenshotImgurPlugin/Forms/ImgurForm.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -19,7 +19,6 @@ * along with this program. If not, see . */ -using System; using GreenshotPlugin.Controls; namespace GreenshotImgurPlugin { @@ -27,7 +26,5 @@ namespace GreenshotImgurPlugin { /// This class is needed for design-time resolving of the language files /// public class ImgurForm : GreenshotForm { - public ImgurForm() : base() { - } } } diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs index f3d3d221f..b9945c0a3 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs +++ b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.cs b/GreenshotImgurPlugin/Forms/ImgurHistory.cs index 064fcc21f..4d67ab528 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.cs +++ b/GreenshotImgurPlugin/Forms/ImgurHistory.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -31,24 +31,24 @@ namespace GreenshotImgurPlugin { /// /// Description of ImgurHistory. /// - public partial class ImgurHistory : ImgurForm { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImgurHistory)); - private GreenshotColumnSorter columnSorter; - private static ImgurConfiguration config = IniConfig.GetIniSection(); - private static ImgurHistory instance; + public sealed partial class ImgurHistory : ImgurForm { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory)); + private readonly GreenshotColumnSorter _columnSorter; + private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); + private static ImgurHistory _instance; public static void ShowHistory() { // Make sure the history is loaded, will be done only once ImgurUtils.LoadHistory(); - if (instance == null) { - instance = new ImgurHistory(); + if (_instance == null) { + _instance = new ImgurHistory(); } - instance.Show(); - instance.redraw(); + _instance.Show(); + _instance.Redraw(); } private ImgurHistory() { - this.ManualLanguageApply = true; + ManualLanguageApply = true; // // The InitializeComponent() call is required for Windows Forms designer support. // @@ -56,21 +56,21 @@ namespace GreenshotImgurPlugin { AcceptButton = finishedButton; CancelButton = finishedButton; // Init sorting - columnSorter = new GreenshotColumnSorter(); - this.listview_imgur_uploads.ListViewItemSorter = columnSorter; - columnSorter.SortColumn = 3; - columnSorter.Order = SortOrder.Descending; - redraw(); + _columnSorter = new GreenshotColumnSorter(); + listview_imgur_uploads.ListViewItemSorter = _columnSorter; + _columnSorter.SortColumn = 3; + _columnSorter.Order = SortOrder.Descending; + Redraw(); if (listview_imgur_uploads.Items.Count > 0) { listview_imgur_uploads.Items[0].Selected = true; } ApplyLanguage(); - if (config.Credits > 0) { - this.Text = this.Text + " (" + config.Credits + " credits)"; + if (Config.Credits > 0) { + Text = Text + " (" + Config.Credits + " credits)"; } } - private void redraw() { + private void Redraw() { // Should fix Bug #3378699 pictureBox1.Image = pictureBox1.ErrorImage; listview_imgur_uploads.BeginUpdate(); @@ -80,9 +80,11 @@ namespace GreenshotImgurPlugin { foreach (string column in columns) { listview_imgur_uploads.Columns.Add(column); } - foreach (ImgurInfo imgurInfo in config.runtimeImgurHistory.Values) { - ListViewItem item = new ListViewItem(imgurInfo.Hash); - item.Tag = imgurInfo; + foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values) { + var item = new ListViewItem(imgurInfo.Hash) + { + Tag = imgurInfo + }; item.SubItems.Add(imgurInfo.Title); item.SubItems.Add(imgurInfo.DeleteHash); item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo)); @@ -101,7 +103,7 @@ namespace GreenshotImgurPlugin { private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e) { pictureBox1.Image = pictureBox1.ErrorImage; - if (listview_imgur_uploads.SelectedItems != null && listview_imgur_uploads.SelectedItems.Count > 0) { + if (listview_imgur_uploads.SelectedItems.Count > 0) { deleteButton.Enabled = true; openButton.Enabled = true; clipboardButton.Enabled = true; @@ -118,40 +120,39 @@ namespace GreenshotImgurPlugin { } private void DeleteButtonClick(object sender, EventArgs e) { - if (listview_imgur_uploads.SelectedItems != null && listview_imgur_uploads.SelectedItems.Count > 0) { + if (listview_imgur_uploads.SelectedItems.Count > 0) { for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title), Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (result == DialogResult.Yes) { - // Should fix Bug #3378699 - pictureBox1.Image = pictureBox1.ErrorImage; - try { - new PleaseWaitForm().ShowAndWait(ImgurPlugin.Attributes.Name, Language.GetString("imgur", LangKey.communication_wait), - delegate() { - ImgurUtils.DeleteImgurImage(imgurInfo); - } - ); - } catch (Exception ex) { - LOG.Warn("Problem communicating with Imgur: ", ex); - } - - imgurInfo.Dispose(); + if (result != DialogResult.Yes) + { + continue; } + // Should fix Bug #3378699 + pictureBox1.Image = pictureBox1.ErrorImage; + try { + new PleaseWaitForm().ShowAndWait(ImgurPlugin.Attributes.Name, Language.GetString("imgur", LangKey.communication_wait), + delegate { + ImgurUtils.DeleteImgurImage(imgurInfo); + } + ); + } catch (Exception ex) { + Log.Warn("Problem communicating with Imgur: ", ex); + } + + imgurInfo.Dispose(); } } - redraw(); + Redraw(); } private void ClipboardButtonClick(object sender, EventArgs e) { StringBuilder links = new StringBuilder(); - if (listview_imgur_uploads.SelectedItems != null && listview_imgur_uploads.SelectedItems.Count > 0) { - for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { + if (listview_imgur_uploads.SelectedItems.Count > 0) { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; - if (config.UsePageLink) { - links.AppendLine(imgurInfo.Page); - } else { - links.AppendLine(imgurInfo.Original); - } + links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original); } } ClipboardHelper.SetClipboardData(links.ToString()); @@ -160,20 +161,20 @@ namespace GreenshotImgurPlugin { private void ClearHistoryButtonClick(object sender, EventArgs e) { DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { - config.runtimeImgurHistory.Clear(); - config.ImgurUploadHistory.Clear(); + Config.runtimeImgurHistory.Clear(); + Config.ImgurUploadHistory.Clear(); IniConfig.Save(); - redraw(); + Redraw(); } } private void FinishedButtonClick(object sender, EventArgs e) { - this.Hide(); + Hide(); } private void OpenButtonClick(object sender, EventArgs e) { - if (listview_imgur_uploads.SelectedItems != null && listview_imgur_uploads.SelectedItems.Count > 0) { + if (listview_imgur_uploads.SelectedItems.Count > 0) { for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; System.Diagnostics.Process.Start(imgurInfo.Page); @@ -183,27 +184,23 @@ namespace GreenshotImgurPlugin { private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e) { // Determine if clicked column is already the column that is being sorted. - if (e.Column == columnSorter.SortColumn) { + if (e.Column == _columnSorter.SortColumn) { // Reverse the current sort direction for this column. - if (columnSorter.Order == SortOrder.Ascending) { - columnSorter.Order = SortOrder.Descending; - } else { - columnSorter.Order = SortOrder.Ascending; - } + _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; } else { // Set the column number that is to be sorted; default to ascending. - columnSorter.SortColumn = e.Column; - columnSorter.Order = SortOrder.Ascending; + _columnSorter.SortColumn = e.Column; + _columnSorter.Order = SortOrder.Ascending; } // Perform the sort with these new sort options. - this.listview_imgur_uploads.Sort(); + listview_imgur_uploads.Sort(); } - - void ImgurHistoryFormClosing(object sender, FormClosingEventArgs e) + + private void ImgurHistoryFormClosing(object sender, FormClosingEventArgs e) { - instance = null; + _instance = null; } } } diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs index c24d1f67d..6f867efc8 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.cs b/GreenshotImgurPlugin/Forms/SettingsForm.cs index 8a35fc06e..e7afda70c 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.cs +++ b/GreenshotImgurPlugin/Forms/SettingsForm.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -19,16 +19,14 @@ * along with this program. If not, see . */ using System; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Controls; namespace GreenshotImgurPlugin { /// /// Description of PasswordRequestForm. /// public partial class SettingsForm : ImgurForm { - public SettingsForm(ImgurConfiguration config) : base() { + public SettingsForm(ImgurConfiguration config) + { // // The InitializeComponent() call is required for Windows Forms designer support. // @@ -38,14 +36,10 @@ namespace GreenshotImgurPlugin { ImgurUtils.LoadHistory(); - if (config.runtimeImgurHistory.Count > 0) { - historyButton.Enabled = true; - } else { - historyButton.Enabled = false; - } + historyButton.Enabled = config.runtimeImgurHistory.Count > 0; } - - void ButtonHistoryClick(object sender, EventArgs e) { + + private void ButtonHistoryClick(object sender, EventArgs e) { ImgurHistory.ShowHistory(); } } diff --git a/GreenshotImgurPlugin/ImgurConfiguration.cs b/GreenshotImgurPlugin/ImgurConfiguration.cs index 104839352..2889c9501 100644 --- a/GreenshotImgurPlugin/ImgurConfiguration.cs +++ b/GreenshotImgurPlugin/ImgurConfiguration.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -32,47 +32,45 @@ namespace GreenshotImgurPlugin { /// [IniSection("Imgur", Description="Greenshot Imgur Plugin configuration")] public class ImgurConfiguration : IniSection { - [IniProperty("ImgurApiUrl", Description="Url to Imgur system.", DefaultValue= "http://api.imgur.com/2")] - public string ImgurApiUrl; [IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")] - public string ImgurApi3Url; + public string ImgurApi3Url { get; set; } [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat; + public OutputFormat UploadFormat { get; set; } [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality; + public int UploadJpegQuality { get; set; } [IniProperty("UploadReduceColors", Description="Reduce color amount of the uploaded image to 256", DefaultValue="False")] - public bool UploadReduceColors; + public bool UploadReduceColors { get; set; } [IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")] - public bool CopyLinkToClipboard; + public bool CopyLinkToClipboard { get; set; } [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] - public bool UsePageLink; + public bool UsePageLink { get; set; } [IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue="true")] - public bool AnonymousAccess; + public bool AnonymousAccess { get; set; } [IniProperty("RefreshToken", Description = "Imgur refresh Token", Encrypted = true, ExcludeIfNull = true)] - public string RefreshToken; + public string RefreshToken { get; set; } /// /// AccessToken, not stored /// - public string AccessToken; + public string AccessToken { get; set; } /// /// AccessTokenExpires, not stored /// - public DateTimeOffset AccessTokenExpires; + public DateTimeOffset AccessTokenExpires { get; set; } [IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")] - public bool AddTitle; + public bool AddTitle { get; set; } [IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")] - public bool AddFilename; + public bool AddFilename { get; set; } [IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")] - public string FilenamePattern; + public string FilenamePattern { get; set; } [IniProperty("ImgurUploadHistory", Description="Imgur upload history (ImgurUploadHistory.hash=deleteHash)")] - public Dictionary ImgurUploadHistory; - + public Dictionary ImgurUploadHistory { get; set; } + // Not stored, only run-time! public Dictionary runtimeImgurHistory = new Dictionary(); public int Credits { @@ -100,7 +98,7 @@ namespace GreenshotImgurPlugin { SettingsForm settingsForm = null; new PleaseWaitForm().ShowAndWait(ImgurPlugin.Attributes.Name, Language.GetString("imgur", LangKey.communication_wait), - delegate() { + delegate { settingsForm = new SettingsForm(this); } ); diff --git a/GreenshotImgurPlugin/ImgurCredentials.cs b/GreenshotImgurPlugin/ImgurCredentials.cs index 4eee20fba..159a4e08a 100644 --- a/GreenshotImgurPlugin/ImgurCredentials.cs +++ b/GreenshotImgurPlugin/ImgurCredentials.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 diff --git a/GreenshotImgurPlugin/ImgurDestination.cs b/GreenshotImgurPlugin/ImgurDestination.cs index 9002463f3..030a6e81a 100644 --- a/GreenshotImgurPlugin/ImgurDestination.cs +++ b/GreenshotImgurPlugin/ImgurDestination.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -20,7 +20,6 @@ */ using System.ComponentModel; using System.Drawing; -using Greenshot.IniFile; using Greenshot.Plugin; using GreenshotPlugin.Core; @@ -29,25 +28,15 @@ namespace GreenshotImgurPlugin { /// Description of ImgurDestination. /// public class ImgurDestination : AbstractDestination { - private static log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImgurDestination)); - private static ImgurConfiguration config = IniConfig.GetIniSection(); - private ImgurPlugin plugin = null; + private readonly ImgurPlugin _plugin; public ImgurDestination(ImgurPlugin plugin) { - this.plugin = plugin; + _plugin = plugin; } - public override string Designation { - get { - return "Imgur"; - } - } + public override string Designation => "Imgur"; - public override string Description { - get { - return Language.GetString("imgur", LangKey.upload_menu_item); - } - } + public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); public override Image DisplayIcon { get { @@ -57,10 +46,10 @@ namespace GreenshotImgurPlugin { } public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(this.Designation, this.Description); - string uploadURL = null; - exportInformation.ExportMade = plugin.Upload(captureDetails, surface, out uploadURL); - exportInformation.Uri = uploadURL; + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string uploadUrl; + exportInformation.ExportMade = _plugin.Upload(captureDetails, surface, out uploadUrl); + exportInformation.Uri = uploadUrl; ProcessExport(exportInformation, surface); return exportInformation; } diff --git a/GreenshotImgurPlugin/ImgurInfo.cs b/GreenshotImgurPlugin/ImgurInfo.cs index 37e5a3ce8..61f16a17e 100644 --- a/GreenshotImgurPlugin/ImgurInfo.cs +++ b/GreenshotImgurPlugin/ImgurInfo.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -27,8 +27,9 @@ namespace GreenshotImgurPlugin /// /// Description of ImgurInfo. /// - public class ImgurInfo : IDisposable { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImgurInfo)); + public class ImgurInfo : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo)); public string Hash { @@ -36,11 +37,13 @@ namespace GreenshotImgurPlugin set; } - private string deleteHash; - public string DeleteHash { - get {return deleteHash;} - set { - deleteHash = value; + private string _deleteHash; + public string DeleteHash + { + get { return _deleteHash; } + set + { + _deleteHash = value; DeletePage = "https://imgur.com/delete/" + value; } } @@ -93,25 +96,23 @@ namespace GreenshotImgurPlugin set; } - private Image image; - public Image Image { - get {return image;} - set { - if (image != null) { - image.Dispose(); - } - image = value; + private Image _image; + public Image Image + { + get { return _image; } + set + { + _image?.Dispose(); + _image = value; } } - public ImgurInfo() { - } - /// /// The public accessible Dispose /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice /// - public void Dispose() { + public void Dispose() + { Dispose(true); GC.SuppressFinalize(this); } @@ -121,16 +122,17 @@ namespace GreenshotImgurPlugin /// When disposing==true all non-managed resources should be freed too! /// /// - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (image != null) { - image.Dispose(); - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _image?.Dispose(); } - image = null; + _image = null; } - public static ImgurInfo ParseResponse(string response) { - LOG.Debug(response); + public static ImgurInfo ParseResponse(string response) + { + Log.Debug(response); // This is actually a hack for BUG-1695 // The problem is the (C) sign, we send it HTML encoded "®" to Imgur and get it HTML encoded in the XML back // Added all the encodings I found quickly, I guess these are not all... but it should fix the issue for now. @@ -142,35 +144,41 @@ namespace GreenshotImgurPlugin response = response.Replace("®", "®"); ImgurInfo imgurInfo = new ImgurInfo(); - try { + try + { XmlDocument doc = new XmlDocument(); doc.LoadXml(response); XmlNodeList nodes = doc.GetElementsByTagName("id"); - if(nodes.Count > 0) { - imgurInfo.Hash = nodes.Item(0).InnerText; + if (nodes.Count > 0) + { + imgurInfo.Hash = nodes.Item(0)?.InnerText; } nodes = doc.GetElementsByTagName("hash"); if (nodes.Count > 0) { - imgurInfo.Hash = nodes.Item(0).InnerText; + imgurInfo.Hash = nodes.Item(0)?.InnerText; } nodes = doc.GetElementsByTagName("deletehash"); - if(nodes.Count > 0) { - imgurInfo.DeleteHash = nodes.Item(0).InnerText; + if (nodes.Count > 0) + { + imgurInfo.DeleteHash = nodes.Item(0)?.InnerText; } nodes = doc.GetElementsByTagName("type"); - if(nodes.Count > 0) { - imgurInfo.ImageType = nodes.Item(0).InnerText; + if (nodes.Count > 0) + { + imgurInfo.ImageType = nodes.Item(0)?.InnerText; } nodes = doc.GetElementsByTagName("title"); - if(nodes.Count > 0) { - imgurInfo.Title = nodes.Item(0).InnerText; + if (nodes.Count > 0) + { + imgurInfo.Title = nodes.Item(0)?.InnerText; } nodes = doc.GetElementsByTagName("datetime"); - if(nodes.Count > 0) { + if (nodes.Count > 0) + { // Version 3 has seconds since Epoch double secondsSince; - if (double.TryParse(nodes.Item(0).InnerText, out secondsSince)) + if (double.TryParse(nodes.Item(0)?.InnerText, out secondsSince)) { var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime; @@ -179,35 +187,30 @@ namespace GreenshotImgurPlugin nodes = doc.GetElementsByTagName("original"); if (nodes.Count > 0) { - imgurInfo.Original = nodes.Item(0).InnerText.Replace("http:", "https:"); + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); } // Version 3 API only has Link nodes = doc.GetElementsByTagName("link"); if (nodes.Count > 0) { - imgurInfo.Original = nodes.Item(0).InnerText.Replace("http:", "https:"); + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); } nodes = doc.GetElementsByTagName("imgur_page"); if (nodes.Count > 0) { - imgurInfo.Page = nodes.Item(0).InnerText.Replace("http:", "https:"); + imgurInfo.Page = nodes.Item(0)?.InnerText.Replace("http:", "https:"); } else { // Version 3 doesn't have a page link in the response - imgurInfo.Page = string.Format("https://imgur.com/{0}", imgurInfo.Hash); + imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}"; } nodes = doc.GetElementsByTagName("small_square"); - if(nodes.Count > 0) { - imgurInfo.SmallSquare = nodes.Item(0).InnerText; - } - nodes = doc.GetElementsByTagName("large_thumbnail"); - if(nodes.Count > 0) - { - imgurInfo.LargeThumbnail = nodes.Item(0).InnerText.Replace("http:", "https:"); - } - } catch(Exception e) { - LOG.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); + imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png"; + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); } return imgurInfo; } diff --git a/GreenshotImgurPlugin/ImgurPlugin.cs b/GreenshotImgurPlugin/ImgurPlugin.cs index c5c354eec..93b8ede40 100644 --- a/GreenshotImgurPlugin/ImgurPlugin.cs +++ b/GreenshotImgurPlugin/ImgurPlugin.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -35,13 +35,13 @@ namespace GreenshotImgurPlugin { /// This is the ImgurPlugin code /// public class ImgurPlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); - private static ImgurConfiguration config; + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); + private static ImgurConfiguration _config; public static PluginAttribute Attributes; - private IGreenshotHost host; - private ComponentResourceManager resources; - private ToolStripMenuItem historyMenuItem = null; - private ToolStripMenuItem itemPlugInConfig; + private IGreenshotHost _host; + private ComponentResourceManager _resources; + private ToolStripMenuItem _historyMenuItem; + private ToolStripMenuItem _itemPlugInConfig; public void Dispose() { Dispose(true); @@ -50,20 +50,17 @@ namespace GreenshotImgurPlugin { protected virtual void Dispose(bool disposing) { if (disposing) { - if (historyMenuItem != null) { - historyMenuItem.Dispose(); - historyMenuItem = null; + if (_historyMenuItem != null) { + _historyMenuItem.Dispose(); + _historyMenuItem = null; } - if (itemPlugInConfig != null) { - itemPlugInConfig.Dispose(); - itemPlugInConfig = null; + if (_itemPlugInConfig != null) { + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; } } } - public ImgurPlugin() { - } - public IEnumerable Destinations() { yield return new ImgurDestination(this); } @@ -75,114 +72,112 @@ namespace GreenshotImgurPlugin { /// /// Implementation of the IGreenshotPlugin.Initialize /// - /// Use the IGreenshotPluginHost interface to register events - /// Use the ICaptureHost interface to register in the MainContextMenu - /// My own attributes + /// Use the IGreenshotPluginHost interface to register events + /// My own attributes /// true if plugin is initialized, false if not (doesn't show) public virtual bool Initialize(IGreenshotHost pluginHost, PluginAttribute myAttributes) { - this.host = (IGreenshotHost)pluginHost; + _host = pluginHost; Attributes = myAttributes; // Get configuration - config = IniConfig.GetIniSection(); - resources = new ComponentResourceManager(typeof(ImgurPlugin)); - - ToolStripMenuItem itemPlugInRoot = new ToolStripMenuItem("Imgur"); - itemPlugInRoot.Image = (Image)resources.GetObject("Imgur"); + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(ImgurPlugin)); - historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history)); - historyMenuItem.Tag = host; - historyMenuItem.Click += delegate { + ToolStripMenuItem itemPlugInRoot = new ToolStripMenuItem("Imgur") + { + Image = (Image) _resources.GetObject("Imgur") + }; + + _historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history)) + { + Tag = _host + }; + _historyMenuItem.Click += delegate { ImgurHistory.ShowHistory(); }; - itemPlugInRoot.DropDownItems.Add(historyMenuItem); + itemPlugInRoot.DropDownItems.Add(_historyMenuItem); - itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure)); - itemPlugInConfig.Tag = host; - itemPlugInConfig.Click += delegate { - config.ShowConfigDialog(); + _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure)) + { + Tag = _host }; - itemPlugInRoot.DropDownItems.Add(itemPlugInConfig); + _itemPlugInConfig.Click += delegate { + _config.ShowConfigDialog(); + }; + itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig); - PluginUtils.AddToContextMenu(host, itemPlugInRoot); - Language.LanguageChanged += new LanguageChangedHandler(OnLanguageChanged); + PluginUtils.AddToContextMenu(_host, itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; // retrieve history in the background - Thread backgroundTask = new Thread (new ThreadStart(CheckHistory)); - backgroundTask.Name = "Imgur History"; - backgroundTask.IsBackground = true; + Thread backgroundTask = new Thread(CheckHistory) + { + Name = "Imgur History", + IsBackground = true + }; backgroundTask.SetApartmentState(ApartmentState.STA); backgroundTask.Start(); return true; } public void OnLanguageChanged(object sender, EventArgs e) { - if (itemPlugInConfig != null) { - itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); + if (_itemPlugInConfig != null) { + _itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); } - if (historyMenuItem != null) { - historyMenuItem.Text = Language.GetString("imgur", LangKey.history); + if (_historyMenuItem != null) { + _historyMenuItem.Text = Language.GetString("imgur", LangKey.history); } } private void CheckHistory() { try { ImgurUtils.LoadHistory(); - host.GreenshotForm.BeginInvoke((MethodInvoker)delegate { - if (config.ImgurUploadHistory.Count > 0) { - historyMenuItem.Enabled = true; + _host.GreenshotForm.BeginInvoke((MethodInvoker)delegate { + if (_config.ImgurUploadHistory.Count > 0) { + _historyMenuItem.Enabled = true; } else { - historyMenuItem.Enabled = false; + _historyMenuItem.Enabled = false; } }); } catch (Exception ex) { - LOG.Error("Error loading history", ex); - }; + Log.Error("Error loading history", ex); + } } public virtual void Shutdown() { - LOG.Debug("Imgur Plugin shutdown."); - Language.LanguageChanged -= new LanguageChangedHandler(OnLanguageChanged); + Log.Debug("Imgur Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; } /// /// Implementation of the IPlugin.Configure /// public virtual void Configure() { - config.ShowConfigDialog(); + _config.ShowConfigDialog(); } - /// - /// This will be called when Greenshot is shutting down - /// - /// - /// - public void Closing(object sender, FormClosingEventArgs e) { - LOG.Debug("Application closing, de-registering Imgur Plugin!"); - Shutdown(); - } - /// /// Upload the capture to imgur /// - /// - /// - /// out string for the url + /// ICaptureDetails + /// ISurface + /// out string for the url /// true if the upload succeeded - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadURL) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(config.UploadFormat, config.UploadJpegQuality, config.UploadReduceColors); + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); try { - string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(config.FilenamePattern, config.UploadFormat, captureDetails)); + string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails)); ImgurInfo imgurInfo = null; // Run upload in the background new PleaseWaitForm().ShowAndWait("Imgur plug-in", Language.GetString("imgur", LangKey.communication_wait), - delegate() { + delegate + { imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename); - if (imgurInfo != null && config.AnonymousAccess) { - LOG.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); - config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); - config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); + if (imgurInfo != null && _config.AnonymousAccess) { + Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); + _config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); + _config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); CheckHistory(); } } @@ -195,34 +190,34 @@ namespace GreenshotImgurPlugin { } IniConfig.Save(); - if (config.UsePageLink) + if (_config.UsePageLink) { - uploadURL = imgurInfo.Page; + uploadUrl = imgurInfo.Page; } else { - uploadURL = imgurInfo.Original; + uploadUrl = imgurInfo.Original; } - if (!string.IsNullOrEmpty(uploadURL) && config.CopyLinkToClipboard) + if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard) { try { - ClipboardHelper.SetClipboardData(uploadURL); + ClipboardHelper.SetClipboardData(uploadUrl); } catch (Exception ex) { - LOG.Error("Can't write to clipboard: ", ex); - uploadURL = null; + Log.Error("Can't write to clipboard: ", ex); + uploadUrl = null; } } return true; } } catch (Exception e) { - LOG.Error("Error uploading.", e); + Log.Error("Error uploading.", e); MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message); } - uploadURL = null; + uploadUrl = null; return false; } } diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/GreenshotImgurPlugin/ImgurUtils.cs index 3bb80e0f8..c32c0afba 100644 --- a/GreenshotImgurPlugin/ImgurUtils.cs +++ b/GreenshotImgurPlugin/ImgurUtils.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -32,7 +32,7 @@ namespace GreenshotImgurPlugin { /// Description of ImgurUtils. /// public static class ImgurUtils { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ImgurUtils)); + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); private const string AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}"; @@ -64,7 +64,7 @@ namespace GreenshotImgurPlugin { RetrieveImgurThumbnail(imgurInfo); Config.runtimeImgurHistory.Add(hash, imgurInfo); } else { - LOG.DebugFormat("Deleting not found ImgUr {0} from config.", hash); + Log.DebugFormat("Deleting not found ImgUr {0} from config.", hash); Config.ImgurUploadHistory.Remove(hash); saveNeeded = true; } @@ -74,16 +74,16 @@ namespace GreenshotImgurPlugin { HttpWebResponse response = ((HttpWebResponse)wE.Response); // Image no longer available if (response.StatusCode == HttpStatusCode.Redirect) { - LOG.InfoFormat("ImgUr image for hash {0} is no longer available", hash); + Log.InfoFormat("ImgUr image for hash {0} is no longer available", hash); Config.ImgurUploadHistory.Remove(hash); redirected = true; } } if (!redirected) { - LOG.Error("Problem loading ImgUr history for hash " + hash, wE); + Log.Error("Problem loading ImgUr history for hash " + hash, wE); } } catch (Exception e) { - LOG.Error("Problem loading ImgUr history for hash " + hash, e); + Log.Error("Problem loading ImgUr history for hash " + hash, e); } } if (saveNeeded) { @@ -119,7 +119,7 @@ namespace GreenshotImgurPlugin { if (filename != null && Config.AddFilename) { otherParameters.Add("name", filename); } - string responseString; + string responseString = null; if (Config.AnonymousAccess) { // add key, we only use the other parameters for the AnonymousAccess //otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); @@ -133,32 +133,40 @@ namespace GreenshotImgurPlugin { ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); } - using (WebResponse response = webRequest.GetResponse()) { - using (StreamReader reader = new StreamReader(response.GetResponseStream(), true)) { - responseString = reader.ReadToEnd(); - } + using (WebResponse response = webRequest.GetResponse()) + { LogRateLimitInfo(response); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using (StreamReader reader = new StreamReader(responseStream, true)) + { + responseString = reader.ReadToEnd(); + } + } } } catch (Exception ex) { - LOG.Error("Upload to imgur gave an exeption: ", ex); + Log.Error("Upload to imgur gave an exeption: ", ex); throw; } } else { - var oauth2Settings = new OAuth2Settings(); - oauth2Settings.AuthUrlPattern = AuthUrlPattern; - oauth2Settings.TokenUrl = TokenUrl; - oauth2Settings.RedirectUrl = "https://imgur.com"; - oauth2Settings.CloudServiceName = "Imgur"; - oauth2Settings.ClientId = ImgurCredentials.CONSUMER_KEY; - oauth2Settings.ClientSecret = ImgurCredentials.CONSUMER_SECRET; - oauth2Settings.AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser; - oauth2Settings.BrowserSize = new Size(680, 880); + var oauth2Settings = new OAuth2Settings + { + AuthUrlPattern = AuthUrlPattern, + TokenUrl = TokenUrl, + RedirectUrl = "https://imgur.com", + CloudServiceName = "Imgur", + ClientId = ImgurCredentials.CONSUMER_KEY, + ClientSecret = ImgurCredentials.CONSUMER_SECRET, + AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser, + BrowserSize = new Size(680, 880), + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; // Copy the settings from the config, which is kept in memory and on the disk - oauth2Settings.RefreshToken = Config.RefreshToken; - oauth2Settings.AccessToken = Config.AccessToken; - oauth2Settings.AccessTokenExpires = Config.AccessTokenExpires; try { @@ -179,6 +187,10 @@ namespace GreenshotImgurPlugin { IniConfig.Save(); } } + if (string.IsNullOrEmpty(responseString)) + { + return null; + } return ImgurInfo.ParseResponse(responseString); } @@ -188,19 +200,20 @@ namespace GreenshotImgurPlugin { /// public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) { if (imgurInfo.SmallSquare == null) { - LOG.Warn("Imgur URL was null, not retrieving thumbnail."); + Log.Warn("Imgur URL was null, not retrieving thumbnail."); return; } - LOG.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); + Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); webRequest.ServicePoint.Expect100Continue = false; - SetClientId(webRequest); + // Not for getting the thumbnail, in anonymous modus + //SetClientId(webRequest); using (WebResponse response = webRequest.GetResponse()) { LogRateLimitInfo(response); Stream responseStream = response.GetResponseStream(); if (responseStream != null) { - imgurInfo.Image = Image.FromStream(responseStream); + imgurInfo.Image = ImageHelper.FromStream(responseStream); } } } @@ -212,17 +225,22 @@ namespace GreenshotImgurPlugin { /// /// ImgurInfo public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) { - string url = Config.ImgurApiUrl + "/image/" + hash; - LOG.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); + string url = Config.ImgurApi3Url + "/image/" + hash + ".xml"; + Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); webRequest.ServicePoint.Expect100Continue = false; SetClientId(webRequest); - string responseString; + string responseString = null; try { using (WebResponse response = webRequest.GetResponse()) { LogRateLimitInfo(response); - using (StreamReader reader = new StreamReader(response.GetResponseStream(), true)) { - responseString = reader.ReadToEnd(); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using (StreamReader reader = new StreamReader(responseStream, true)) + { + responseString = reader.ReadToEnd(); + } } } } catch (WebException wE) { @@ -233,9 +251,13 @@ namespace GreenshotImgurPlugin { } throw; } - LOG.Debug(responseString); - ImgurInfo imgurInfo = ImgurInfo.ParseResponse(responseString); - imgurInfo.DeleteHash = deleteHash; + ImgurInfo imgurInfo = null; + if (responseString != null) + { + Log.Debug(responseString); + imgurInfo = ImgurInfo.ParseResponse(responseString); + imgurInfo.DeleteHash = deleteHash; + } return imgurInfo; } @@ -244,21 +266,26 @@ namespace GreenshotImgurPlugin { /// /// public static void DeleteImgurImage(ImgurInfo imgurInfo) { - LOG.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); + Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); try { - string url = Config.ImgurApiUrl + "/delete/" + imgurInfo.DeleteHash; - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); + string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); webRequest.ServicePoint.Expect100Continue = false; SetClientId(webRequest); - string responseString; + string responseString = null; using (WebResponse response = webRequest.GetResponse()) { LogRateLimitInfo(response); - using (StreamReader reader = new StreamReader(response.GetResponseStream(), true)) { - responseString = reader.ReadToEnd(); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using (StreamReader reader = new StreamReader(responseStream, true)) + { + responseString = reader.ReadToEnd(); + } } } - LOG.InfoFormat("Delete result: {0}", responseString); + Log.InfoFormat("Delete result: {0}", responseString); } catch (WebException wE) { // Allow "Bad request" this means we already deleted it if (wE.Status == WebExceptionStatus.ProtocolError) { @@ -280,7 +307,7 @@ namespace GreenshotImgurPlugin { /// private static void LogHeader(IDictionary nameValues, string key) { if (nameValues.ContainsKey(key)) { - LOG.InfoFormat("key={0}", nameValues[key]); + Log.InfoFormat("key={0}", nameValues[key]); } } diff --git a/GreenshotImgurPlugin/LanguageKeys.cs b/GreenshotImgurPlugin/LanguageKeys.cs index b5d81646e..fbee74ad7 100644 --- a/GreenshotImgurPlugin/LanguageKeys.cs +++ b/GreenshotImgurPlugin/LanguageKeys.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 diff --git a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs b/GreenshotImgurPlugin/Properties/AssemblyInfo.cs index 06afabdf8..f0234c49c 100644 --- a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotImgurPlugin/Properties/AssemblyInfo.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -22,7 +22,6 @@ using Greenshot.Plugin; using System.Reflection; using System.Runtime.InteropServices; -using System.Security; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -32,7 +31,7 @@ using System.Security; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Greenshot")] [assembly: AssemblyProduct("Imgur Plugin")] -[assembly: AssemblyCopyright("Copyright (C) 2007-2015")] +[assembly: AssemblyCopyright("Copyright (C) 2007-2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // The PluginAttribute describes the "entryType" and if the plugin is configurable diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index b5bff9abb..039fbb4de 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -174,7 +174,7 @@ namespace GreenshotPlugin.Core { [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] public List ExcludeDestinations; - [IniProperty("UpdateCheckInterval", Description="How many days between every update check? (0=no checks)", DefaultValue="1")] + [IniProperty("UpdateCheckInterval", Description="How many days between every update check? (0=no checks)", DefaultValue="14")] public int UpdateCheckInterval; [IniProperty("LastUpdateCheck", Description="Last update check")] public DateTime LastUpdateCheck; @@ -430,12 +430,18 @@ namespace GreenshotPlugin.Core { // Store version, this can be used later to fix settings after an update LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); } catch { - + // Ignore } // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others OutputFileAutoReduceColors = false; } + // Force update check to 14 days, but only if it's not turned off + if (UpdateCheckInterval < 7 && UpdateCheckInterval > 0) + { + UpdateCheckInterval = 14; + } + // Enable OneNote if upgrading from 1.1 if(ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) { if(LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) { diff --git a/GreenshotPlugin/Core/Func.cs b/GreenshotPlugin/Core/Func.cs new file mode 100644 index 000000000..9c15475ca --- /dev/null +++ b/GreenshotPlugin/Core/Func.cs @@ -0,0 +1,29 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://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 . + */ + +namespace GreenshotPlugin.Core +{ + public delegate TResult Func(); + public delegate TResult Func(T arg); + public delegate TResult Func(T1 arg1, T2 arg2); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); +} diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index 86abd0dab..aca597df2 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -18,17 +18,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; -using System.Runtime.InteropServices; using Greenshot.IniFile; using GreenshotPlugin.UnmanagedHelpers; -using Greenshot.Plugin; using Greenshot.Core; +using Greenshot.Plugin; using log4net; namespace GreenshotPlugin.Core { @@ -48,30 +48,109 @@ namespace GreenshotPlugin.Core { /// Description of ImageHelper. /// public static class ImageHelper { - private static ILog LOG = LogManager.GetLogger(typeof(ImageHelper)); - private static CoreConfiguration conf = IniConfig.GetIniSection(); - private const int EXIF_ORIENTATION_ID = 0x0112; + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const int ExifOrientationId = 0x0112; + + /// + /// This is a factory method to create a surface, set from the Greenshot main project + /// + public static Func SurfaceFactory { get; set; } + + static ImageHelper() + { + StreamConverters["greenshot"] = (stream, s) => + { + var surface = SurfaceFactory(); + return surface.GetImageForExport(); + }; + + Func defaultConverter = (stream, 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[""] = 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> StreamConverters { get; } = new Dictionary>(); /// /// Make sure the image is orientated correctly /// /// - public static void Orientate(Image image) { - if (!conf.ProcessEXIFOrientation) { + public static void Orientate(Image image) + { + if (!CoreConfig.ProcessEXIFOrientation) + { return; } - try { + try + { // Get the index of the orientation property. - int orientationIndex = Array.IndexOf(image.PropertyIdList, EXIF_ORIENTATION_ID); + int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); // If there is no such property, return Unknown. - if (orientationIndex < 0) { + if (orientationIndex < 0) + { return; } - PropertyItem item = image.GetPropertyItem(EXIF_ORIENTATION_ID); + PropertyItem item = image.GetPropertyItem(ExifOrientationId); ExifOrientations orientation = (ExifOrientations)item.Value[0]; // Orient the image. - switch (orientation) { + switch (orientation) + { case ExifOrientations.Unknown: case ExifOrientations.TopLeft: break; @@ -100,20 +179,11 @@ namespace GreenshotPlugin.Core { // Set the orientation to be normal, as we rotated the image. item.Value[0] = (byte)ExifOrientations.TopLeft; image.SetPropertyItem(item); - } catch (Exception orientEx) { - LOG.Warn("Problem orientating the image: ", orientEx); } - } - - /// - /// Create a thumbnail from an image - /// - /// - /// - /// - /// - public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight) { - return CreateThumbnail(image, thumbWidth, thumbHeight, -1, -1); + catch (Exception orientEx) + { + Log.Warn("Problem orientating the image: ", orientEx); + } } /// @@ -125,53 +195,61 @@ namespace GreenshotPlugin.Core { /// /// /// - public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth, int maxHeight) { - int srcWidth=image.Width; - int srcHeight=image.Height; - if (thumbHeight < 0) { + public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) + { + int srcWidth = image.Width; + int srcHeight = image.Height; + if (thumbHeight < 0) + { thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); } - if (thumbWidth < 0) { + if (thumbWidth < 0) + { thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); } - if (maxWidth > 0 && thumbWidth > maxWidth) { + if (maxWidth > 0 && thumbWidth > maxWidth) + { thumbWidth = Math.Min(thumbWidth, maxWidth); thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); } - if (maxHeight > 0 && thumbHeight > maxHeight) { + if (maxHeight > 0 && thumbHeight > maxHeight) + { thumbHeight = Math.Min(thumbHeight, maxHeight); thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); } Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); - using (Graphics graphics = Graphics.FromImage(bmp)) { + using (Graphics graphics = Graphics.FromImage(bmp)) + { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); - graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); + graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); } return bmp; } - + /// /// Crops the image to the specified rectangle /// /// Image to crop /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) { - Image returnImage = null; - if (image != null && image is Bitmap && ((image.Width * image.Height) > 0)) { - cropRectangle.Intersect(new Rectangle(0,0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) { - returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); + public static bool Crop(ref Image image, ref Rectangle cropRectangle) + { + if (image is Bitmap && (image.Width * image.Height > 0)) + { + cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); + if (cropRectangle.Width != 0 || cropRectangle.Height != 0) + { + Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); image.Dispose(); image = returnImage; return true; } } - LOG.Warn("Can't crop a null/zero size image!"); + Log.Warn("Can't crop a null/zero size image!"); return false; } @@ -182,20 +260,25 @@ namespace GreenshotPlugin.Core { /// /// /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) { + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + { Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); Point max = new Point(int.MinValue, int.MinValue); - if (cropDifference > 0) { - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { + if (cropDifference > 0) + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { Color currentColor = fastBitmap.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffB = Math.Abs(currentColor.B - referenceColor.B); - if (((diffR + diffG + diffB)/3) <= cropDifference) { + if ((diffR + diffG + diffB) / 3 <= cropDifference) + { continue; } if (x < min.X) min.X = x; @@ -204,11 +287,16 @@ namespace GreenshotPlugin.Core { if (y > max.Y) max.Y = y; } } - } else { - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { + } + else + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { Color currentColor = fastBitmap.GetColorAt(x, y); - if (!referenceColor.Equals(currentColor)) { + if (!referenceColor.Equals(currentColor)) + { continue; } if (x < min.X) min.X = x; @@ -219,8 +307,10 @@ namespace GreenshotPlugin.Core { } } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) { - if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { + if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + { + if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) + { cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); } } @@ -233,115 +323,90 @@ namespace GreenshotPlugin.Core { /// /// /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) { + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + { Rectangle cropRectangle = Rectangle.Empty; - Rectangle currentRectangle; - List checkPoints = new List(); + var checkPoints = new List + { + new Point(0, 0), + new Point(0, image.Height - 1), + new Point(image.Width - 1, 0), + new Point(image.Width - 1, image.Height - 1) + }; // Top Left - checkPoints.Add(new Point(0, 0)); // Bottom Left - checkPoints.Add(new Point(0, image.Height - 1)); // Top Right - checkPoints.Add(new Point(image.Width - 1, 0)); // Bottom Right - checkPoints.Add(new Point(image.Width - 1, image.Height - 1)); - using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) { + using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) + { // find biggest area - foreach(Point checkPoint in checkPoints) { - currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); - if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { + foreach (Point checkPoint in checkPoints) + { + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) + { cropRectangle = currentRectangle; } } } return cropRectangle; } - + /// /// Load an image from file /// /// /// - public static Image LoadImage(string filename) { - if (string.IsNullOrEmpty(filename)) { + public static Image LoadImage(string filename) + { + if (string.IsNullOrEmpty(filename)) + { return null; } - if (!File.Exists(filename)) { + if (!File.Exists(filename)) + { return null; } - Image fileImage = null; - LOG.InfoFormat("Loading image from file {0}", filename); + Image fileImage; + Log.InfoFormat("Loading image from file {0}", filename); // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(filename)) { - // And fixed problem that the bitmap stream is disposed... by Cloning the image - // This also ensures the bitmap is correctly created - - if (filename.EndsWith(".ico")) { - // Icon logic, try to get the Vista icon, else the biggest possible - try { - using (Image tmpImage = ExtractVistaIcon(imageFileStream)) { - if (tmpImage != null) { - fileImage = Clone(tmpImage); - } - } - } catch (Exception vistaIconException) { - LOG.Warn("Can't read icon from " + filename, vistaIconException); - } - if (fileImage == null) { - try { - // No vista icon, try normal icon - imageFileStream.Position = 0; - // We create a copy of the bitmap, so everything else can be disposed - using (Icon tmpIcon = new Icon(imageFileStream, new Size(1024,1024))) { - using (Image tmpImage = tmpIcon.ToBitmap()) { - fileImage = Clone(tmpImage); - } - } - } catch (Exception iconException) { - LOG.Warn("Can't read icon from " + filename, iconException); - } - } - } - if (fileImage == null) { - // We create a copy of the bitmap, so everything else can be disposed - imageFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(imageFileStream, true, true)) { - LOG.DebugFormat("Loaded {0} with Size {1}x{2} and PixelFormat {3}", filename, tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - fileImage = Clone(tmpImage); - } - } + 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); + 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); } - // Make sure the orientation is set correctly so Greenshot can process the image correctly - Orientate(fileImage); return fileImage; } - /// /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx /// /// Stream with the icon information /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) { - const int SizeICONDIR = 6; - const int SizeICONDIRENTRY = 16; + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; Bitmap bmpPngExtracted = null; - try { + 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 /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx /// - /// The icon to /// The file (EXE or DLL) to get the icon from /// Index of the icon /// true if the large icon is wanted /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) { + public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) + { IntPtr large; IntPtr small; Shell32.ExtractIconEx(location, index, out large, out small, 1); Icon returnIcon = null; bool isLarge = false; bool isSmall = false; - try { - if (takeLarge && !IntPtr.Zero.Equals(large)) { + try + { + if (takeLarge && !IntPtr.Zero.Equals(large)) + { returnIcon = Icon.FromHandle(large); isLarge = true; - } else if (!IntPtr.Zero.Equals(small)) { + } + else if (!IntPtr.Zero.Equals(small)) + { returnIcon = Icon.FromHandle(small); isSmall = true; - } else if (!IntPtr.Zero.Equals(large)) { + } + else if (!IntPtr.Zero.Equals(large)) + { returnIcon = Icon.FromHandle(large); isLarge = true; } - } finally { - if (isLarge && !IntPtr.Zero.Equals(small)) { + } + finally + { + if (isLarge && !IntPtr.Zero.Equals(small)) + { User32.DestroyIcon(small); } - if (isSmall && !IntPtr.Zero.Equals(large)) { + if (isSmall && !IntPtr.Zero.Equals(large)) + { User32.DestroyIcon(large); } } @@ -397,7 +474,8 @@ namespace GreenshotPlugin.Core { /// /// Location of the EXE or DLL /// - public static int CountAssociatedIcons(string location) { + public static int CountAssociatedIcons(string location) + { IntPtr large; IntPtr small; return Shell32.ExtractIconEx(location, -1, out large, out small, 0); @@ -410,9 +488,9 @@ namespace GreenshotPlugin.Core { /// IEffect /// /// Bitmap - public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) { - List effects = new List(); - effects.Add(effect); + public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) + { + var effects = new List { effect }; return ApplyEffects(sourceImage, effects, matrix); } @@ -420,20 +498,23 @@ namespace GreenshotPlugin.Core { /// Apply the effects in the supplied order to the bitmap /// /// Bitmap - /// List + /// List of IEffect /// /// Bitmap - public static Image ApplyEffects(Image sourceImage, List effects, Matrix matrix) { - Image currentImage = sourceImage; + public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) + { + var currentImage = sourceImage; bool disposeImage = false; - foreach (IEffect effect in effects) { - Image tmpImage = effect.Apply(currentImage, matrix); - if (tmpImage != null) { - if (disposeImage) { + foreach (var effect in effects) + { + var tmpImage = effect.Apply(currentImage, matrix); + if (tmpImage != null) + { + if (disposeImage) + { currentImage.Dispose(); } currentImage = tmpImage; - tmpImage = null; // Make sure the "new" image is disposed disposeImage = true; } @@ -446,10 +527,12 @@ namespace GreenshotPlugin.Core { /// /// Path to draw to /// Points for the lines to draw - private static void DrawLines(GraphicsPath path, List points) { + private static void DrawLines(GraphicsPath path, List points) + { path.AddLine(points[0], points[1]); - for (int i = 0; i < points.Count-1; i++) { - path.AddLine(points[i], points[i+1]); + for (int i = 0; i < points.Count - 1; i++) + { + path.AddLine(points[i], points[i + 1]); } } @@ -462,9 +545,11 @@ namespace GreenshotPlugin.Core { /// How wide is a vertical tooth /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left /// Changed bitmap - 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, sourceImage.VerticalResolution); - using (GraphicsPath path = new GraphicsPath()) { + using (var path = new GraphicsPath()) + { Random random = new Random(); int horizontalRegions = (int)Math.Round((float)sourceImage.Width / horizontalToothRange); int verticalRegions = (int)Math.Round((float)sourceImage.Height / verticalToothRange); @@ -476,53 +561,72 @@ namespace GreenshotPlugin.Core { List points = new List(); - if (edges[0]) { + if (edges[0]) + { // calculate starting point only if the left edge is torn - if (!edges[3]) { + if (!edges[3]) + { points.Add(topLeft); - } else { + } + else + { points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); } - for (int i = 1; i < horizontalRegions-1; i++) { - points.Add(new Point(i*horizontalToothRange, random.Next(1, toothHeight))); + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); } points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); - } else { + } + else + { // set start & endpoint to be the default "whole-line" points.Add(topLeft); points.Add(topRight); } // Right - if (edges[1]) { - for (int i = 1; i < verticalRegions-1; i++) { + if (edges[1]) + { + for (int i = 1; i < verticalRegions - 1; i++) + { points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); } points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } else { + } + else + { // correct previous ending point points[points.Count - 1] = topRight; // set endpoint to be the default "whole-line" points.Add(bottomRight); } // Bottom - if (edges[2]) { - for (int i = 1; i < horizontalRegions -1; i++) { + if (edges[2]) + { + for (int i = 1; i < horizontalRegions - 1; i++) + { points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); } points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } else { + } + else + { // correct previous ending point points[points.Count - 1] = bottomRight; // set endpoint to be the default "whole-line" points.Add(bottomLeft); } // Left - if (edges[3]) { + if (edges[3]) + { // One fewer as the end point is the starting point - for (int i = 1; i < verticalRegions -1; i++) { + for (int i = 1; i < verticalRegions - 1; i++) + { points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); } - } else { + } + else + { // correct previous ending point points[points.Count - 1] = bottomLeft; // set endpoint to be the default "whole-line" @@ -536,12 +640,14 @@ namespace GreenshotPlugin.Core { path.CloseFigure(); // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing - using (Graphics graphics = Graphics.FromImage(returnImage)) { + using (Graphics graphics = Graphics.FromImage(returnImage)) + { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (Brush brush = new TextureBrush(sourceImage)) { + using (Brush brush = new TextureBrush(sourceImage)) + { // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! graphics.FillPath(brush, path); } @@ -555,9 +661,11 @@ namespace GreenshotPlugin.Core { /// /// Bitmap to blur /// Must be ODD! - public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) { + public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) + { // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) - using (IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap)) { + using (IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap)) + { ApplyBoxBlur(fastBitmap, range); } } @@ -567,24 +675,30 @@ namespace GreenshotPlugin.Core { /// /// IFastBitmap to blur /// Must be ODD! - public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) { + public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) + { // Range must be odd! - if ((range & 1) == 0) { + if ((range & 1) == 0) + { range++; } - if (range <= 1) { + if (range <= 1) + { return; } // Box blurs are frequently used to approximate a Gaussian blur. // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. // (Might also be a mistake in our blur, but for now it looks great) - if (fastBitmap.hasAlphaChannel) { + if (fastBitmap.hasAlphaChannel) + { BoxBlurHorizontalAlpha(fastBitmap, range); BoxBlurVerticalAlpha(fastBitmap, range); BoxBlurHorizontalAlpha(fastBitmap, range); BoxBlurVerticalAlpha(fastBitmap, range); - } else { + } + else + { BoxBlurHorizontal(fastBitmap, range); BoxBlurVertical(fastBitmap, range); BoxBlurHorizontal(fastBitmap, range); @@ -597,21 +711,26 @@ namespace GreenshotPlugin.Core { /// /// Target BitmapBuffer /// Range must be odd! - private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) { - if (targetFastBitmap.hasAlphaChannel) { + private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.hasAlphaChannel) + { throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); } int halfRange = range / 2; Color[] newColors = new Color[targetFastBitmap.Width]; byte[] tmpColor = new byte[3]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { int hits = 0; int r = 0; int g = 0; int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) { + if (oldPixel >= targetFastBitmap.Left) + { targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); r -= tmpColor[FastBitmap.COLOR_INDEX_R]; g -= tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -620,7 +739,8 @@ namespace GreenshotPlugin.Core { } int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) { + if (newPixel < targetFastBitmap.Right) + { targetFastBitmap.GetColorAt(newPixel, y, tmpColor); r += tmpColor[FastBitmap.COLOR_INDEX_R]; g += tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -628,11 +748,13 @@ namespace GreenshotPlugin.Core { hits++; } - if (x >= targetFastBitmap.Left) { + if (x >= targetFastBitmap.Left) + { newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); } } @@ -642,22 +764,27 @@ namespace GreenshotPlugin.Core { /// /// Target BitmapBuffer /// Range must be odd! - private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) { - if (!targetFastBitmap.hasAlphaChannel) { + private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.hasAlphaChannel) + { throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); } int halfRange = range / 2; Color[] newColors = new Color[targetFastBitmap.Width]; byte[] tmpColor = new byte[4]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { int hits = 0; int a = 0; int r = 0; int g = 0; int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) { + if (oldPixel >= targetFastBitmap.Left) + { targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); a -= tmpColor[FastBitmap.COLOR_INDEX_A]; r -= tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -667,7 +794,8 @@ namespace GreenshotPlugin.Core { } int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) { + if (newPixel < targetFastBitmap.Right) + { targetFastBitmap.GetColorAt(newPixel, y, tmpColor); a += tmpColor[FastBitmap.COLOR_INDEX_A]; r += tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -676,11 +804,13 @@ namespace GreenshotPlugin.Core { hits++; } - if (x >= targetFastBitmap.Left) { + if (x >= targetFastBitmap.Left) + { newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); } } @@ -691,21 +821,26 @@ namespace GreenshotPlugin.Core { /// /// BitmapBuffer which previously was created with BoxBlurHorizontal /// Range must be odd! - private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) { - if (targetFastBitmap.hasAlphaChannel) { + private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.hasAlphaChannel) + { throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); } int halfRange = range / 2; Color[] newColors = new Color[targetFastBitmap.Height]; byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { int hits = 0; int r = 0; int g = 0; int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) { + if (oldPixel >= targetFastBitmap.Top) + { targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); r -= tmpColor[FastBitmap.COLOR_INDEX_R]; g -= tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -714,7 +849,8 @@ namespace GreenshotPlugin.Core { } int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) { + if (newPixel < targetFastBitmap.Bottom) + { targetFastBitmap.GetColorAt(x, newPixel, tmpColor); r += tmpColor[FastBitmap.COLOR_INDEX_R]; g += tmpColor[FastBitmap.COLOR_INDEX_G]; @@ -722,12 +858,14 @@ namespace GreenshotPlugin.Core { hits++; } - if (y >= targetFastBitmap.Top) { + if (y >= targetFastBitmap.Top) + { newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); } } @@ -738,23 +876,28 @@ namespace GreenshotPlugin.Core { /// /// BitmapBuffer which previously was created with BoxBlurHorizontal /// Range must be odd! - private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) { - if (!targetFastBitmap.hasAlphaChannel) { + private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.hasAlphaChannel) + { throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); } int halfRange = range / 2; Color[] newColors = new Color[targetFastBitmap.Height]; byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) { + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { int hits = 0; int a = 0; int r = 0; int g = 0; int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) { + if (oldPixel >= targetFastBitmap.Top) + { targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); a -= tmpColor[FastBitmap.COLOR_INDEX_A]; r -= tmpColor[FastBitmap.COLOR_INDEX_R]; @@ -764,7 +907,8 @@ namespace GreenshotPlugin.Core { } int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) { + if (newPixel < targetFastBitmap.Bottom) + { //int colorg = pixels[index + newPixelOffset]; targetFastBitmap.GetColorAt(x, newPixel, tmpColor); a += tmpColor[FastBitmap.COLOR_INDEX_A]; @@ -774,12 +918,14 @@ namespace GreenshotPlugin.Core { hits++; } - if (y >= targetFastBitmap.Top) { + if (y >= targetFastBitmap.Top) + { newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); } } - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) { + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); } } @@ -794,11 +940,15 @@ namespace GreenshotPlugin.Core { /// /// /// - public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) { + public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) + { Rectangle myRect; - if (invert) { + if (invert) + { myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - } else { + } + else + { Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); myRect.Intersect(applyRect); @@ -816,51 +966,63 @@ namespace GreenshotPlugin.Core { /// /// The transform matrix which describes how the elements need to be transformed to stay at the same location /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) { + public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) + { Point offset = shadowOffset; offset.X += shadowSize - 1; offset.Y += shadowSize - 1; matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); // Create a new "clean" image - Bitmap returnImage = CreateEmpty(sourceBitmap.Width + (shadowSize * 2), sourceBitmap.Height + (shadowSize * 2), targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); // Make sure the shadow is odd, there is no reason for an even blur! - if ((shadowSize & 1) == 0) { + if ((shadowSize & 1) == 0) + { shadowSize++; } - bool useGDIBlur = GDIplus.isBlurPossible(shadowSize); + bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); // Create "mask" for the shadow - ColorMatrix maskMatrix = new ColorMatrix(); - maskMatrix.Matrix00 = 0; - maskMatrix.Matrix11 = 0; - maskMatrix.Matrix22 = 0; - if (useGDIBlur) { + ColorMatrix maskMatrix = new ColorMatrix + { + Matrix00 = 0, + Matrix11 = 0, + Matrix22 = 0 + }; + if (useGdiBlur) + { maskMatrix.Matrix33 = darkness + 0.1f; - } else { + } + else + { maskMatrix.Matrix33 = darkness; } Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); ApplyColorMatrix((Bitmap)sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); // blur "shadow", apply to whole new image - if (useGDIBlur) { + if (useGdiBlur) + { // Use GDI Blur Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize+1, false); - } else { + GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); + } + else + { // try normal software blur //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); ApplyBoxBlur(returnImage, shadowSize); } // Draw the original image over the shadow - using (Graphics graphics = Graphics.FromImage(returnImage)) { + using (Graphics graphics = Graphics.FromImage(returnImage)) + { // Make sure we draw with the best quality! graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; // draw original with a TextureBrush so we have nice antialiasing! - using (Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp)) { + using (Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp)) + { // We need to do a translate-transform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); @@ -874,14 +1036,15 @@ namespace GreenshotPlugin.Core { /// /// Bitmap to create a negative off /// Negative bitmap - public static Bitmap CreateNegative(Image sourceImage) { + public static Bitmap CreateNegative(Image sourceImage) + { Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix invertMatrix = new ColorMatrix(new[] { - new float[] {-1, 0, 0, 0, 0}, - new float[] {0, -1, 0, 0, 0}, - new float[] {0, 0, -1, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {1, 1, 1, 1, 1} + ColorMatrix invertMatrix = new ColorMatrix(new[] { + new float[] {-1, 0, 0, 0, 0}, + new float[] {0, -1, 0, 0, 0}, + new float[] {0, 0, -1, 0, 0}, + new float[] {0, 0, 0, 1, 0}, + new float[] {1, 1, 1, 1, 1} }); ApplyColorMatrix(clone, invertMatrix); return clone; @@ -891,7 +1054,8 @@ namespace GreenshotPlugin.Core { /// /// Image to apply matrix to /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) { + public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) + { ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); } @@ -903,20 +1067,23 @@ namespace GreenshotPlugin.Core { /// Rectangle to copy to /// Image to copy to /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) { - using (ImageAttributes imageAttributes = new ImageAttributes()) { + public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) + { + using (ImageAttributes imageAttributes = new ImageAttributes()) + { imageAttributes.ClearColorMatrix(); imageAttributes.SetColorMatrix(colorMatrix); ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); } } - + /// /// Apply image attributes to the image /// /// Image to apply matrix to /// ImageAttributes to apply - public static void ApplyColorMatrix(Bitmap source, ImageAttributes imageAttributes) { + public static void ApplyColorMatrix(Bitmap source, ImageAttributes imageAttributes) + { ApplyImageAttributes(source, Rectangle.Empty, source, Rectangle.Empty, imageAttributes); } @@ -928,17 +1095,22 @@ namespace GreenshotPlugin.Core { /// Rectangle to copy to /// Image to copy to /// ImageAttributes to apply - public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) { - if (sourceRect == Rectangle.Empty) { + public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) + { + if (sourceRect == Rectangle.Empty) + { sourceRect = new Rectangle(0, 0, source.Width, source.Height); } - if (dest == null) { + if (dest == null) + { dest = source; } - if (destRect == Rectangle.Empty) { + if (destRect == Rectangle.Empty) + { destRect = new Rectangle(0, 0, dest.Width, dest.Height); } - using (Graphics graphics = Graphics.FromImage(dest)) { + using (Graphics graphics = Graphics.FromImage(dest)) + { // Make sure we draw with the best quality! graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; @@ -949,19 +1121,23 @@ namespace GreenshotPlugin.Core { graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); } } - + /// /// Returns a b/w of Bitmap /// /// Bitmap to create a b/w of /// Threshold for monochrome filter (0 - 255), lower value means less black /// b/w bitmap - public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) { - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) { - for (int y = 0; y < fastBitmap.Height; y++) { - for (int x = 0; x < fastBitmap.Width; x++) { + public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) + { + using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat)) + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { Color color = fastBitmap.GetColorAt(x, y); - int colorBrightness = ((color.R + color.G + color.B) / 3 > threshold) ? 255 : 0; + int colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); fastBitmap.SetColorAt(x, y, monoColor); } @@ -979,22 +1155,26 @@ namespace GreenshotPlugin.Core { /// What pixel format must the returning bitmap have /// The transform matrix which describes how the elements need to be transformed to stay at the same location /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) { + public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) + { // "return" the shifted offset, so the caller can e.g. move elements Point offset = new Point(borderSize, borderSize); matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); // Create a new "clean" image - Bitmap newImage = CreateEmpty(sourceImage.Width + (borderSize * 2), sourceImage.Height + (borderSize * 2), targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newImage)) { + Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newImage)) + { // Make sure we draw with the best quality! graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (GraphicsPath path = new GraphicsPath()) { - path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - (borderSize), newImage.Height - (borderSize))); - using (Pen pen = new Pen(borderColor, borderSize)) { + using (GraphicsPath path = new GraphicsPath()) + { + path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); + using (Pen pen = new Pen(borderColor, borderSize)) + { pen.LineJoin = LineJoin.Round; pen.StartCap = LineCap.Round; pen.EndCap = LineCap.Round; @@ -1002,7 +1182,8 @@ namespace GreenshotPlugin.Core { } } // draw original with a TextureBrush so we have nice antialiasing! - using (Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp)) { + using (Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp)) + { // We need to do a translate-tranform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); @@ -1018,15 +1199,17 @@ namespace GreenshotPlugin.Core { /// /// /// ImageAttributes - public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) { + public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) + { float adjustedBrightness = brightness - 1.0f; ColorMatrix applyColorMatrix = new ColorMatrix( - new float[][] { - new float[] {contrast, 0, 0, 0, 0}, // scale red - new float[] {0, contrast, 0, 0, 0}, // scale green - new float[] {0, 0, contrast, 0, 0}, // scale blue - new float[] {0, 0, 0, 1.0f, 0}, // don't scale alpha - new float[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1} + new[] + { + new[] {contrast, 0, 0, 0, 0}, // scale red + new[] {0, contrast, 0, 0, 0}, // scale green + new[] {0, 0, contrast, 0, 0}, // scale blue + new[] {0, 0, 0, 1.0f, 0}, // don't scale alpha + new[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1} }); //create some image attributes @@ -1046,12 +1229,14 @@ namespace GreenshotPlugin.Core { /// /// /// Bitmap with grayscale - public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) { + public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) + { //create a blank bitmap the same size as original // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) { - ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); + using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) + { + ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); } return newBitmap; } @@ -1061,12 +1246,14 @@ namespace GreenshotPlugin.Core { /// /// Original bitmap /// Bitmap with grayscale - public static Image CreateGrayscale(Image sourceImage) { + public static Image CreateGrayscale(Image sourceImage) + { Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix grayscaleMatrix = new ColorMatrix( new float[][] { - new float[] {.3f, .3f, .3f, 0, 0}, - new float[] {.59f, .59f, .59f, 0, 0}, - new float[] {.11f, .11f, .11f, 0, 0}, + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] {.3f, .3f, .3f, 0, 0}, + new[] {.59f, .59f, .59f, 0, 0}, + new[] {.11f, .11f, .11f, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }); @@ -1079,7 +1266,8 @@ namespace GreenshotPlugin.Core { /// /// bitmap to check /// bool if we support it - public static bool SupportsPixelFormat(Image image) { + public static bool SupportsPixelFormat(Image image) + { return SupportsPixelFormat(image.PixelFormat); } @@ -1088,11 +1276,12 @@ namespace GreenshotPlugin.Core { /// /// PixelFormat to check /// bool if we support it - public static bool SupportsPixelFormat(PixelFormat pixelformat) { - return (pixelformat.Equals(PixelFormat.Format32bppArgb) || + public static bool SupportsPixelFormat(PixelFormat pixelformat) + { + return pixelformat.Equals(PixelFormat.Format32bppArgb) || pixelformat.Equals(PixelFormat.Format32bppPArgb) || pixelformat.Equals(PixelFormat.Format32bppRgb) || - pixelformat.Equals(PixelFormat.Format24bppRgb)); + pixelformat.Equals(PixelFormat.Format24bppRgb); } /// @@ -1100,8 +1289,10 @@ namespace GreenshotPlugin.Core { /// /// Image to clone /// Bitmap with clone image data - public static Image Clone(Image sourceImage) { - if (sourceImage is Metafile) { + public static Image Clone(Image sourceImage) + { + if (sourceImage is Metafile) + { return (Image)sourceImage.Clone(); } return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); @@ -1113,7 +1304,8 @@ namespace GreenshotPlugin.Core { /// Image to clone /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) /// Bitmap with clone image data - public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) { + public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) + { return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); } @@ -1128,35 +1320,42 @@ namespace GreenshotPlugin.Core { /// Rectangle to copy from the source, use Rectangle.Empty for all /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) /// - public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) { - Bitmap newImage = null; + public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) + { + Bitmap newImage; Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); // Make sure the source is not Rectangle.Empty - if (Rectangle.Empty.Equals(sourceRect)) { + if (Rectangle.Empty.Equals(sourceRect)) + { sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - } else { + } + else + { sourceRect.Intersect(bitmapRect); } // If no pixelformat is supplied - if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) { - if (SupportsPixelFormat(sourceImage.PixelFormat)) { + if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) + { + if (SupportsPixelFormat(sourceImage.PixelFormat)) + { targetFormat = sourceImage.PixelFormat; - } else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) { + } + else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) + { targetFormat = PixelFormat.Format32bppArgb; - } else { + } + else + { targetFormat = PixelFormat.Format24bppRgb; } } // check the target format - if (!SupportsPixelFormat(targetFormat)) { - if (Image.IsAlphaPixelFormat(targetFormat)) { - targetFormat = PixelFormat.Format32bppArgb; - } else { - targetFormat = PixelFormat.Format24bppRgb; - } + if (!SupportsPixelFormat(targetFormat)) + { + targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; } bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); @@ -1164,64 +1363,77 @@ namespace GreenshotPlugin.Core { bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; bool isBitmap = sourceImage is Bitmap; bool isAreaEqual = sourceRect.Equals(bitmapRect); - if (isAreaEqual || fromTransparentToNon || !isBitmap) { + if (isAreaEqual || fromTransparentToNon || !isBitmap) + { // Rule 1: if the areas are equal, always copy ourselves newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); // Make sure both images have the same resolution newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - - using (Graphics graphics = Graphics.FromImage(newImage)) { - if (fromTransparentToNon) { + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + if (fromTransparentToNon) + { // Rule 2: Make sure the background color is white graphics.Clear(Color.White); } // decide fastest copy method - if (isAreaEqual) { + if (isAreaEqual) + { graphics.DrawImageUnscaled(sourceImage, 0, 0); - } else { + } + else + { graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); } } - } else { + } + else + { // Let GDI+ decide how to convert, need to test what is quicker... newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); // Make sure both images have the same resolution newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); } // Clone property items (EXIF information etc) - if (sourceImage.PropertyItems != null) { - foreach (var propertyItem in sourceImage.PropertyItems) { - try { - newImage.SetPropertyItem(propertyItem); - } catch (Exception ex) { - LOG.Warn("Problem cloning a propertyItem.", ex); - } + foreach (var propertyItem in sourceImage.PropertyItems) + { + try + { + newImage.SetPropertyItem(propertyItem); + } + catch (Exception ex) + { + Log.Warn("Problem cloning a propertyItem.", ex); } } return newImage; } - + /// /// Rotate the bitmap /// /// /// /// - public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) { + public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) + { Image returnImage = Clone(sourceImage); returnImage.RotateFlip(rotateFlipType); return returnImage; } - + /// /// A generic way to create an empty image /// /// the source bitmap as the specifications for the new bitmap /// The color to fill with, or Color.Empty to take the default depending on the pixel format /// - public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) { + public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) + { PixelFormat pixelFormat = sourceImage.PixelFormat; - if (backgroundColor.A < 255) { + if (backgroundColor.A < 255) + { pixelFormat = PixelFormat.Format32bppArgb; } return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); @@ -1237,41 +1449,51 @@ namespace GreenshotPlugin.Core { /// /// /// Bitmap - 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, float verticalResolution) + { // Create a new "clean" image Bitmap newImage = new Bitmap(width, height, format); newImage.SetResolution(horizontalResolution, verticalResolution); - if (format != PixelFormat.Format8bppIndexed) { - using (Graphics graphics = Graphics.FromImage(newImage)) { + if (format != PixelFormat.Format8bppIndexed) + { + using (Graphics graphics = Graphics.FromImage(newImage)) + { // Make sure the background color is what we want (transparent or white, depending on the pixel format) - if (!Color.Empty.Equals(backgroundColor)) { + if (!Color.Empty.Equals(backgroundColor)) + { graphics.Clear(backgroundColor); - } else if (Image.IsAlphaPixelFormat(format)) { + } + else if (Image.IsAlphaPixelFormat(format)) + { graphics.Clear(Color.Transparent); - } else { + } + else + { graphics.Clear(Color.White); } } } return newImage; } - + /// /// Get a scaled version of the sourceBitmap /// /// /// 1-99 to make smaller, use 101 and more to make the picture bigger /// - public static Bitmap ScaleByPercent(Bitmap sourceBitmap, int percent) { - float nPercent = ((float)percent/100); - + public static Bitmap ScaleByPercent(Bitmap sourceBitmap, int percent) + { + float nPercent = (float)percent / 100; + int sourceWidth = sourceBitmap.Width; int sourceHeight = sourceBitmap.Height; - int destWidth = (int)(sourceWidth * nPercent); + int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); - + Bitmap scaledBitmap = CreateEmpty(destWidth, destHeight, sourceBitmap.PixelFormat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(scaledBitmap)) { + using (Graphics graphics = Graphics.FromImage(scaledBitmap)) + { graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, sourceWidth, sourceHeight), GraphicsUnit.Pixel); } @@ -1289,10 +1511,12 @@ namespace GreenshotPlugin.Core { /// /// /// a new bitmap with the source copied on it - public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) { + public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) + { matrix.Translate(left, top, MatrixOrder.Append); Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newBitmap)) { + using (Graphics graphics = Graphics.FromImage(newBitmap)) + { graphics.DrawImageUnscaled(sourceImage, left, top); } return newBitmap; @@ -1307,7 +1531,8 @@ namespace GreenshotPlugin.Core { /// /// /// - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) { + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) + { return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); } @@ -1318,20 +1543,27 @@ namespace GreenshotPlugin.Core { /// Color to count /// true if Alpha needs to be checked /// int with the number of pixels which have colorToCount - public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) { + public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) + { int colors = 0; int toCount = colorToCount.ToArgb(); - if (!includeAlpha) { + if (!includeAlpha) + { toCount = toCount & 0xffffff; } - using (IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage)) { - for (int y = 0; y < bb.Height; y++) { - for (int x = 0; x < bb.Width; x++) { + using (IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage)) + { + for (int y = 0; y < bb.Height; y++) + { + for (int x = 0; x < bb.Width; x++) + { int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); - if (!includeAlpha) { + if (!includeAlpha) + { bitmapcolor = bitmapcolor & 0xffffff; } - if (bitmapcolor == toCount) { + if (bitmapcolor == toCount) + { colors++; } } @@ -1345,74 +1577,179 @@ namespace GreenshotPlugin.Core { /// /// Image to scale /// true to maintain the aspect ratio - /// + /// Makes the image maintain aspect ratio, but the canvas get's the specified size /// The color to fill with, or Color.Empty to take the default depending on the pixel format /// new width /// new height /// /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) { + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) + { int destX = 0; int destY = 0; - - float nPercentW = 0; - float nPercentH = 0; - - nPercentW = (newWidth / (float)sourceImage.Width); - nPercentH = (newHeight / (float)sourceImage.Height); - if (maintainAspectRatio) { - if (nPercentW == 1) { + + var nPercentW = newWidth / (float)sourceImage.Width; + var nPercentH = newHeight / (float)sourceImage.Height; + if (maintainAspectRatio) + { + if ((int)nPercentW == 1) + { nPercentW = nPercentH; - if (canvasUseNewSize) { - destX = Math.Max(0, Convert.ToInt32((newWidth - (sourceImage.Width * nPercentW)) / 2)); - } - } else if (nPercentH == 1) { - nPercentH = nPercentW; - if (canvasUseNewSize) { - destY = Math.Max(0, Convert.ToInt32((newHeight - (sourceImage.Height * nPercentH)) / 2)); - } - } else if (nPercentH != 0 && nPercentH < nPercentW) { - nPercentW = nPercentH; - if (canvasUseNewSize) { - destX = Math.Max(0, Convert.ToInt32((newWidth - (sourceImage.Width * nPercentW)) / 2)); - } - } else { - nPercentH = nPercentW; - if (canvasUseNewSize) { - destY = Math.Max(0, Convert.ToInt32((newHeight - (sourceImage.Height * nPercentH)) / 2)); + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); } } - } - - int destWidth = (int)(sourceImage.Width * nPercentW); - int destHeight = (int)(sourceImage.Height * nPercentH); - if (newWidth == 0) { - newWidth = destWidth; - } - if (newHeight == 0) { - newHeight = destHeight; - } - Image newImage = null; - if (maintainAspectRatio && canvasUseNewSize) { - newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - if (matrix != null) { - matrix.Scale((float)newWidth / sourceImage.Width, (float)newHeight / sourceImage.Height, MatrixOrder.Append); + else if ((int)nPercentH == 1) + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } } - } else { - newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - if (matrix != null) { - matrix.Scale((float)destWidth / sourceImage.Width, (float)destHeight / sourceImage.Height, MatrixOrder.Append); + else if ((int)nPercentH != 0 && nPercentH < nPercentW) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } } } - using (Graphics graphics = Graphics.FromImage(newImage)) { + int destWidth = (int)(sourceImage.Width * nPercentW); + int destHeight = (int)(sourceImage.Height * nPercentH); + if (newWidth == 0) + { + newWidth = destWidth; + } + if (newHeight == 0) + { + newHeight = destHeight; + } + Image newImage; + if (maintainAspectRatio && canvasUseNewSize) + { + newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float)newWidth / sourceImage.Width, (float)newHeight / sourceImage.Height, MatrixOrder.Append); + } + else + { + newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float)destWidth / sourceImage.Width, (float)destHeight / sourceImage.Height, MatrixOrder.Append); + } + + using (Graphics graphics = Graphics.FromImage(newImage)) + { graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (ImageAttributes wrapMode = new ImageAttributes()) { + using (ImageAttributes wrapMode = new ImageAttributes()) + { wrapMode.SetWrapMode(WrapMode.TileFlipXY); graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); } } return newImage; } + + /// + /// Load a Greenshot surface from a stream + /// + /// Stream + /// + /// ISurface + 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 = 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; + } + + /// + /// Create an image from a stream, if an extension is supplied more formats are supported. + /// + /// Stream + /// + /// Image + public static Image FromStream(Stream stream, string extension = null) + { + if (stream == null) + { + return null; + } + if (!string.IsNullOrEmpty(extension)) + { + extension = extension.Replace(".", ""); + } + + // Make sure we can try multiple times + if (!stream.CanSeek) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + stream = memoryStream; + } + + Image returnImage = null; + Func converter; + if (StreamConverters.TryGetValue(extension ?? "", out converter)) + { + returnImage = converter(stream, extension); + } + // Fallback + if (returnImage == null) + { + // We create a copy of the bitmap, so everything else can be disposed + 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; + } } } diff --git a/GreenshotPlugin/Core/SourceForgeHelper.cs b/GreenshotPlugin/Core/SourceForgeHelper.cs index 3a027cbbb..3f330dc13 100644 --- a/GreenshotPlugin/Core/SourceForgeHelper.cs +++ b/GreenshotPlugin/Core/SourceForgeHelper.cs @@ -41,10 +41,6 @@ namespace GreenshotPlugin.Core { public string Link { get {return _link;} } - private readonly string _directLink; - public string DirectLink { - get {return _directLink;} - } private Version _version; public Version Version { get {return _version;} @@ -85,11 +81,10 @@ namespace GreenshotPlugin.Core { } } - public SourceforgeFile(string file, string pubdate, string link, string directLink) { + public SourceforgeFile(string file, string pubdate, string link) { this._file = file; DateTime.TryParse(pubdate, out _pubdate); this._link = link; - this._directLink = directLink; } } /// @@ -180,9 +175,6 @@ namespace GreenshotPlugin.Core { string subdir = match.Groups[2].Value; string type = match.Groups[3].Value; string file = match.Groups[4].Value; - // !!! Change this to the mirror !!! - string mirror = "kent"; - string directLink = Uri.EscapeUriString("http://"+mirror+".dl.sourceforge.net/project/"+project+"/"+subdir+"/"+type+"/"+file); Dictionary filesForType; if (rssFiles.ContainsKey(type)) { filesForType = rssFiles[type]; @@ -190,7 +182,7 @@ namespace GreenshotPlugin.Core { filesForType = new Dictionary(); rssFiles.Add(type, filesForType); } - SourceforgeFile rssFile = new SourceforgeFile(file, pubdate, sfLink, directLink); + SourceforgeFile rssFile = new SourceforgeFile(file, pubdate, sfLink); if (file.EndsWith(".exe") ||file.EndsWith(".zip")) { string version = Regex.Replace(file, @".*[a-zA-Z_]\-", ""); version = version.Replace(@"\-[a-zA-Z]+.*",""); diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 917a12654..70ae6ddb6 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -42,6 +42,7 @@ + diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs index dd446b425..f8671f335 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs @@ -1,9 +1,9 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * 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 @@ -21,9 +21,7 @@ using System; using System.Drawing; using System.Runtime.InteropServices; -using System.Security; using log4net; -using Microsoft.Win32.SafeHandles; using System.Reflection; using System.Drawing.Drawing2D; using System.Drawing.Imaging; @@ -94,7 +92,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// GDIplus Helpers /// public static class GDIplus { - private static ILog LOG = LogManager.GetLogger(typeof(GDIplus)); + private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); @@ -107,7 +105,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] private static extern int GdipDeleteEffect(IntPtr effect); - private static Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); + private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); // Constant "FieldInfo" for getting the nativeImage from the Bitmap private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); @@ -118,7 +116,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - private static bool isBlurEnabled = Environment.OSVersion.Version.Major >= 6; + private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; /// /// Get the nativeImage field from the bitmap /// @@ -172,14 +170,12 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c /// /// - /// - public static bool isBlurPossible(int radius) { - if (!isBlurEnabled) { - return false; - } else if (Environment.OSVersion.Version.Minor >= 2 && radius < 20) { + /// false if blur is not possible + public static bool IsBlurPossible(int radius) { + if (!_isBlurEnabled) { return false; } - return true; + return Environment.OSVersion.Version.Minor < 2 || radius >= 20; } /// @@ -191,25 +187,31 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// bool true if the edges are expanded with the radius /// false if there is no GDI+ available or an exception occured public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) { - if (!isBlurPossible(radius)) { + if (!IsBlurPossible(radius)) { return false; } IntPtr hBlurParams = IntPtr.Zero; IntPtr hEffect = IntPtr.Zero; try { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } // Create a BlurParams struct and set the values - BlurParams blurParams = new BlurParams(); - blurParams.Radius = radius; - blurParams.ExpandEdges = expandEdges; + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = expandEdges + }; // Allocate space in unmanaged memory hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); // Copy the structure to the unmanaged memory Marshal.StructureToPtr(blurParams, hBlurParams, false); - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); // Set the blurParams to the effect GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); @@ -226,8 +228,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { // Everything worked, return true return true; } catch (Exception ex) { - isBlurEnabled = false; - LOG.Error("Problem using GdipBitmapApplyEffect: ", ex); + _isBlurEnabled = false; + Log.Error("Problem using GdipBitmapApplyEffect: ", ex); return false; } finally { try { @@ -240,8 +242,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { Marshal.FreeHGlobal(hBlurParams); } } catch (Exception ex) { - isBlurEnabled = false; - LOG.Error("Problem cleaning up ApplyBlur: ", ex); + _isBlurEnabled = false; + Log.Error("Problem cleaning up ApplyBlur: ", ex); } } } @@ -251,7 +253,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// /// false if there is no GDI+ available or an exception occured public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) { - if (!isBlurPossible(radius)) { + if (!IsBlurPossible(radius)) { return false; } @@ -259,20 +261,26 @@ namespace GreenshotPlugin.UnmanagedHelpers { IntPtr hEffect = IntPtr.Zero; try { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + // Create a BlurParams struct and set the values - BlurParams blurParams = new BlurParams(); - blurParams.Radius = radius; + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = false + }; //blurParams.Padding = radius; - blurParams.ExpandEdges = false; // Allocate space in unmanaged memory hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); // Copy the structure to the unmanaged memory Marshal.StructureToPtr(blurParams, hBlurParams, true); - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - // Set the blurParams to the effect GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); @@ -284,15 +292,15 @@ namespace GreenshotPlugin.UnmanagedHelpers { IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); // Create a RECT from the Rectangle - RECTF sourceRECF = new RECTF(source); + RECTF sourceRecf = new RECTF(source); // Apply the effect to the bitmap in the specified area - GdipDrawImageFX(hGraphics, hBitmap, ref sourceRECF, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); + GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); // Everything worked, return true return true; } catch (Exception ex) { - isBlurEnabled = false; - LOG.Error("Problem using GdipDrawImageFX: ", ex); + _isBlurEnabled = false; + Log.Error("Problem using GdipDrawImageFX: ", ex); return false; } finally { try { @@ -305,8 +313,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { Marshal.FreeHGlobal(hBlurParams); } } catch (Exception ex) { - isBlurEnabled = false; - LOG.Error("Problem cleaning up DrawWithBlur: ", ex); + _isBlurEnabled = false; + Log.Error("Problem cleaning up DrawWithBlur: ", ex); } } } diff --git a/appveyor12.yml b/appveyor12.yml index e8532425e..246b577fa 100644 --- a/appveyor12.yml +++ b/appveyor12.yml @@ -67,12 +67,14 @@ deploy: auth_token: secure: 4sYcNGg7byBFtR7EkJHS8d3H3qP0u0LodlJWCV7g/4jEyv3vvVxqzh19zZ6Zgrf1 prerelease: true + draft: true on: build_type: UNSTABLE - provider: GitHub tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) auth_token: secure: 4sYcNGg7byBFtR7EkJHS8d3H3qP0u0LodlJWCV7g/4jEyv3vvVxqzh19zZ6Zgrf1 + draft: true on: build_type: RELEASE notifications: