mirror of
https://github.com/greenshot/greenshot
synced 2025-07-14 00:53:51 -07:00
Made the supported image formats extendable, and supplied a SVG implementation right away with the jira addon.
This commit is contained in:
parent
9bf9c0e4e6
commit
fc192827f1
21 changed files with 1354 additions and 676 deletions
|
@ -36,7 +36,7 @@ namespace Greenshot.Drawing {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ImageContainer : DrawableContainer, IImageContainer {
|
public class ImageContainer : DrawableContainer, IImageContainer {
|
||||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(ImageContainer));
|
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer));
|
||||||
|
|
||||||
private Image image;
|
private Image image;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ namespace Greenshot.Drawing {
|
||||||
|
|
||||||
protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) {
|
protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) {
|
||||||
if (sender.Equals(this)) {
|
if (sender.Equals(this)) {
|
||||||
if (e.Field.FieldType == FieldType.SHADOW) {
|
if (FieldType.SHADOW.Equals(e.Field.FieldType)) {
|
||||||
ChangeShadowField();
|
ChangeShadowField();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,15 +140,11 @@ namespace Greenshot.Drawing {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeImage() {
|
private void DisposeImage() {
|
||||||
if (image != null) {
|
image?.Dispose();
|
||||||
image.Dispose();
|
|
||||||
}
|
|
||||||
image = null;
|
image = null;
|
||||||
}
|
}
|
||||||
private void DisposeShadow() {
|
private void DisposeShadow() {
|
||||||
if (_shadowBitmap != null) {
|
_shadowBitmap?.Dispose();
|
||||||
_shadowBitmap.Dispose();
|
|
||||||
}
|
|
||||||
_shadowBitmap = null;
|
_shadowBitmap = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,10 +158,11 @@ namespace Greenshot.Drawing {
|
||||||
int rotateAngle = CalculateAngle(matrix);
|
int rotateAngle = CalculateAngle(matrix);
|
||||||
// we currently assume only one transformation has been made.
|
// we currently assume only one transformation has been made.
|
||||||
if (rotateAngle != 0) {
|
if (rotateAngle != 0) {
|
||||||
LOG.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
|
Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle);
|
||||||
DisposeShadow();
|
DisposeShadow();
|
||||||
using (var tmpMatrix = new Matrix()) {
|
using (var tmpMatrix = new Matrix()) {
|
||||||
using (Image tmpImage = image) {
|
using (image)
|
||||||
|
{
|
||||||
image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix);
|
image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,14 +175,16 @@ namespace Greenshot.Drawing {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename"></param>
|
/// <param name="filename"></param>
|
||||||
public void Load(string filename) {
|
public void Load(string filename) {
|
||||||
if (File.Exists(filename)) {
|
if (!File.Exists(filename))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Always make sure ImageHelper.LoadBitmap results are disposed some time,
|
// Always make sure ImageHelper.LoadBitmap results are disposed some time,
|
||||||
// as we close the bitmap internally, we need to do it afterwards
|
// as we close the bitmap internally, we need to do it afterwards
|
||||||
using (Image tmpImage = ImageHelper.LoadImage(filename)) {
|
using (var tmpImage = ImageHelper.LoadImage(filename)) {
|
||||||
Image = tmpImage;
|
Image = tmpImage;
|
||||||
}
|
}
|
||||||
LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
|
Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -222,16 +221,8 @@ namespace Greenshot.Drawing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasDefaultSize {
|
public override bool HasDefaultSize => true;
|
||||||
get {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Size DefaultSize {
|
public override Size DefaultSize => image.Size;
|
||||||
get {
|
|
||||||
return image.Size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -436,7 +436,7 @@ namespace Greenshot.Drawing
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Property for accessing the URL to which the surface was recently uploaded
|
/// Property for accessing the URL to which the surface was recently uploaded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string UploadURL
|
public string UploadUrl
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
|
|
|
@ -41,6 +41,7 @@ using GreenshotPlugin.Controls;
|
||||||
using GreenshotPlugin.Core;
|
using GreenshotPlugin.Core;
|
||||||
using Greenshot.IniFile;
|
using Greenshot.IniFile;
|
||||||
using Greenshot.Destinations;
|
using Greenshot.Destinations;
|
||||||
|
using Greenshot.Drawing;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
@ -320,6 +321,9 @@ namespace Greenshot {
|
||||||
public MainForm(CopyDataTransport dataTransport) {
|
public MainForm(CopyDataTransport dataTransport) {
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
|
// Factory for surface objects
|
||||||
|
ImageHelper.SurfaceFactory = () => new Surface();
|
||||||
|
|
||||||
//
|
//
|
||||||
// The InitializeComponent() call is required for Windows Forms designer support.
|
// The InitializeComponent() call is required for Windows Forms designer support.
|
||||||
//
|
//
|
||||||
|
|
|
@ -549,8 +549,8 @@ namespace Greenshot.Helpers {
|
||||||
MessageBox.Show(string.Format("{0}\r\nexplorer.exe {1}", errorMessage, surface.LastSaveFullPath), "explorer.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(string.Format("{0}\r\nexplorer.exe {1}", errorMessage, surface.LastSaveFullPath), "explorer.exe", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (surface != null && !string.IsNullOrEmpty(surface.UploadURL)) {
|
} else if (surface != null && !string.IsNullOrEmpty(surface.UploadUrl)) {
|
||||||
Process.Start(surface.UploadURL);
|
Process.Start(surface.UploadUrl);
|
||||||
}
|
}
|
||||||
LOG.DebugFormat("Deregistering the BalloonTipClicked");
|
LOG.DebugFormat("Deregistering the BalloonTipClicked");
|
||||||
RemoveEventHandler(sender, e);
|
RemoveEventHandler(sender, e);
|
||||||
|
|
|
@ -36,11 +36,12 @@ namespace GreenshotConfluencePlugin {
|
||||||
/// Description of ConfluenceDestination.
|
/// Description of ConfluenceDestination.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ConfluenceDestination : AbstractDestination {
|
public class ConfluenceDestination : AbstractDestination {
|
||||||
private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceDestination));
|
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination));
|
||||||
private static readonly ConfluenceConfiguration config = IniConfig.GetIniSection<ConfluenceConfiguration>();
|
private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>();
|
||||||
private static readonly CoreConfiguration coreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||||
private static readonly Image confluenceIcon = null;
|
private static readonly Image ConfluenceIcon;
|
||||||
private readonly Page page;
|
private readonly Page _page;
|
||||||
|
|
||||||
public static bool IsInitialized {
|
public static bool IsInitialized {
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
|
@ -49,14 +50,14 @@ namespace GreenshotConfluencePlugin {
|
||||||
IsInitialized = false;
|
IsInitialized = false;
|
||||||
try {
|
try {
|
||||||
Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative);
|
Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative);
|
||||||
using (Stream iconStream = Application.GetResourceStream(confluenceIconUri).Stream) {
|
using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream)
|
||||||
using (Image tmpImage = Image.FromStream(iconStream)) {
|
{
|
||||||
confluenceIcon = ImageHelper.Clone(tmpImage);
|
// TODO: Check what to do with the IImage
|
||||||
}
|
ConfluenceIcon = ImageHelper.FromStream(iconStream);
|
||||||
}
|
}
|
||||||
IsInitialized = true;
|
IsInitialized = true;
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LOG.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message);
|
Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ namespace GreenshotConfluencePlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfluenceDestination(Page page) {
|
public ConfluenceDestination(Page page) {
|
||||||
this.page = page;
|
_page = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Designation {
|
public override string Designation {
|
||||||
|
@ -75,10 +76,10 @@ namespace GreenshotConfluencePlugin {
|
||||||
|
|
||||||
public override string Description {
|
public override string Description {
|
||||||
get {
|
get {
|
||||||
if (page == null) {
|
if (_page == null) {
|
||||||
return Language.GetString("confluence", LangKey.upload_menu_item);
|
return Language.GetString("confluence", LangKey.upload_menu_item);
|
||||||
} else {
|
} else {
|
||||||
return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + page.Title + "\"";
|
return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,13 +92,13 @@ namespace GreenshotConfluencePlugin {
|
||||||
|
|
||||||
public override bool isActive {
|
public override bool isActive {
|
||||||
get {
|
get {
|
||||||
return base.isActive && !string.IsNullOrEmpty(config.Url);
|
return base.isActive && !string.IsNullOrEmpty(ConfluenceConfig.Url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Image DisplayIcon {
|
public override Image DisplayIcon {
|
||||||
get {
|
get {
|
||||||
return confluenceIcon;
|
return ConfluenceIcon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +122,9 @@ namespace GreenshotConfluencePlugin {
|
||||||
return exportInformation;
|
return exportInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
Page selectedPage = page;
|
Page selectedPage = _page;
|
||||||
bool openPage = (page == null) && config.OpenPageAfterUpload;
|
bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload;
|
||||||
string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(coreConfig.OutputFileFilenamePattern, captureDetails);
|
string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails);
|
||||||
if (selectedPage == null) {
|
if (selectedPage == null) {
|
||||||
ConfluenceUpload confluenceUpload = new ConfluenceUpload(filename);
|
ConfluenceUpload confluenceUpload = new ConfluenceUpload(filename);
|
||||||
Nullable<bool> dialogResult = confluenceUpload.ShowDialog();
|
Nullable<bool> dialogResult = confluenceUpload.ShowDialog();
|
||||||
|
@ -135,18 +136,23 @@ namespace GreenshotConfluencePlugin {
|
||||||
filename = confluenceUpload.Filename;
|
filename = confluenceUpload.Filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string extension = "." + config.UploadFormat;
|
string extension = "." + ConfluenceConfig.UploadFormat;
|
||||||
if (!filename.ToLower().EndsWith(extension)) {
|
if (!filename.ToLower().EndsWith(extension)) {
|
||||||
filename = filename + extension;
|
filename = filename + extension;
|
||||||
}
|
}
|
||||||
if (selectedPage != null) {
|
if (selectedPage != null) {
|
||||||
string errorMessage;
|
string errorMessage;
|
||||||
bool uploaded = upload(surface, selectedPage, filename, out errorMessage);
|
bool uploaded = Upload(surface, selectedPage, filename, out errorMessage);
|
||||||
if (uploaded) {
|
if (uploaded) {
|
||||||
if (openPage) {
|
if (openPage) {
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Process.Start(selectedPage.Url);
|
Process.Start(selectedPage.Url);
|
||||||
} catch { }
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exportInformation.ExportMade = true;
|
exportInformation.ExportMade = true;
|
||||||
exportInformation.Uri = selectedPage.Url;
|
exportInformation.Uri = selectedPage.Url;
|
||||||
|
@ -158,17 +164,20 @@ namespace GreenshotConfluencePlugin {
|
||||||
return exportInformation;
|
return exportInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) {
|
private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) {
|
||||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(config.UploadFormat, config.UploadJpegQuality, config.UploadReduceColors);
|
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors);
|
||||||
errorMessage = null;
|
errorMessage = null;
|
||||||
try {
|
try {
|
||||||
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait),
|
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait),
|
||||||
delegate() {
|
delegate {
|
||||||
ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + config.UploadFormat.ToString().ToLower(), null, filename, new SurfaceContainer(surfaceToUpload, outputSettings, filename));
|
ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename, new SurfaceContainer(surfaceToUpload, outputSettings, filename));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
LOG.Debug("Uploaded to Confluence.");
|
Log.Debug("Uploaded to Confluence.");
|
||||||
if (config.CopyWikiMarkupForImageToClipboard) {
|
if (!ConfluenceConfig.CopyWikiMarkupForImageToClipboard)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
int retryCount = 2;
|
int retryCount = 2;
|
||||||
while (retryCount >= 0) {
|
while (retryCount >= 0) {
|
||||||
try {
|
try {
|
||||||
|
@ -176,7 +185,7 @@ namespace GreenshotConfluencePlugin {
|
||||||
break;
|
break;
|
||||||
} catch (Exception ee) {
|
} catch (Exception ee) {
|
||||||
if (retryCount == 0) {
|
if (retryCount == 0) {
|
||||||
LOG.Error(ee);
|
Log.Error(ee);
|
||||||
} else {
|
} else {
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
@ -184,7 +193,6 @@ namespace GreenshotConfluencePlugin {
|
||||||
--retryCount;
|
--retryCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
errorMessage = e.Message;
|
errorMessage = e.Message;
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace GreenshotImgurPlugin {
|
||||||
/// Description of ImgurUtils.
|
/// Description of ImgurUtils.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class 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 const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg";
|
||||||
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
|
private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>();
|
||||||
private const string AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}";
|
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);
|
RetrieveImgurThumbnail(imgurInfo);
|
||||||
Config.runtimeImgurHistory.Add(hash, imgurInfo);
|
Config.runtimeImgurHistory.Add(hash, imgurInfo);
|
||||||
} else {
|
} 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);
|
Config.ImgurUploadHistory.Remove(hash);
|
||||||
saveNeeded = true;
|
saveNeeded = true;
|
||||||
}
|
}
|
||||||
|
@ -74,16 +74,16 @@ namespace GreenshotImgurPlugin {
|
||||||
HttpWebResponse response = ((HttpWebResponse)wE.Response);
|
HttpWebResponse response = ((HttpWebResponse)wE.Response);
|
||||||
// Image no longer available
|
// Image no longer available
|
||||||
if (response.StatusCode == HttpStatusCode.Redirect) {
|
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);
|
Config.ImgurUploadHistory.Remove(hash);
|
||||||
redirected = true;
|
redirected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!redirected) {
|
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) {
|
} 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) {
|
if (saveNeeded) {
|
||||||
|
@ -146,7 +146,7 @@ namespace GreenshotImgurPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LOG.Error("Upload to imgur gave an exeption: ", ex);
|
Log.Error("Upload to imgur gave an exeption: ", ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -200,10 +200,10 @@ namespace GreenshotImgurPlugin {
|
||||||
/// <param name="imgurInfo"></param>
|
/// <param name="imgurInfo"></param>
|
||||||
public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) {
|
public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) {
|
||||||
if (imgurInfo.SmallSquare == null) {
|
if (imgurInfo.SmallSquare == null) {
|
||||||
LOG.Warn("Imgur URL was null, not retrieving thumbnail.");
|
Log.Warn("Imgur URL was null, not retrieving thumbnail.");
|
||||||
return;
|
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);
|
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET);
|
||||||
webRequest.ServicePoint.Expect100Continue = false;
|
webRequest.ServicePoint.Expect100Continue = false;
|
||||||
// Not for getting the thumbnail, in anonymous modus
|
// Not for getting the thumbnail, in anonymous modus
|
||||||
|
@ -213,7 +213,7 @@ namespace GreenshotImgurPlugin {
|
||||||
Stream responseStream = response.GetResponseStream();
|
Stream responseStream = response.GetResponseStream();
|
||||||
if (responseStream != null)
|
if (responseStream != null)
|
||||||
{
|
{
|
||||||
imgurInfo.Image = Image.FromStream(responseStream);
|
imgurInfo.Image = ImageHelper.FromStream(responseStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,18 +226,23 @@ namespace GreenshotImgurPlugin {
|
||||||
/// <returns>ImgurInfo</returns>
|
/// <returns>ImgurInfo</returns>
|
||||||
public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) {
|
public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) {
|
||||||
string url = Config.ImgurApi3Url + "/image/" + hash + ".xml";
|
string url = Config.ImgurApi3Url + "/image/" + hash + ".xml";
|
||||||
LOG.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url);
|
Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url);
|
||||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET);
|
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET);
|
||||||
webRequest.ServicePoint.Expect100Continue = false;
|
webRequest.ServicePoint.Expect100Continue = false;
|
||||||
SetClientId(webRequest);
|
SetClientId(webRequest);
|
||||||
string responseString;
|
string responseString = null;
|
||||||
try {
|
try {
|
||||||
using (WebResponse response = webRequest.GetResponse()) {
|
using (WebResponse response = webRequest.GetResponse()) {
|
||||||
LogRateLimitInfo(response);
|
LogRateLimitInfo(response);
|
||||||
using (StreamReader reader = new StreamReader(response.GetResponseStream(), true)) {
|
var responseStream = response.GetResponseStream();
|
||||||
|
if (responseStream != null)
|
||||||
|
{
|
||||||
|
using (StreamReader reader = new StreamReader(responseStream, true))
|
||||||
|
{
|
||||||
responseString = reader.ReadToEnd();
|
responseString = reader.ReadToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (WebException wE) {
|
} catch (WebException wE) {
|
||||||
if (wE.Status == WebExceptionStatus.ProtocolError) {
|
if (wE.Status == WebExceptionStatus.ProtocolError) {
|
||||||
if (((HttpWebResponse)wE.Response).StatusCode == HttpStatusCode.NotFound) {
|
if (((HttpWebResponse)wE.Response).StatusCode == HttpStatusCode.NotFound) {
|
||||||
|
@ -246,9 +251,13 @@ namespace GreenshotImgurPlugin {
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
LOG.Debug(responseString);
|
ImgurInfo imgurInfo = null;
|
||||||
ImgurInfo imgurInfo = ImgurInfo.ParseResponse(responseString);
|
if (responseString != null)
|
||||||
|
{
|
||||||
|
Log.Debug(responseString);
|
||||||
|
imgurInfo = ImgurInfo.ParseResponse(responseString);
|
||||||
imgurInfo.DeleteHash = deleteHash;
|
imgurInfo.DeleteHash = deleteHash;
|
||||||
|
}
|
||||||
return imgurInfo;
|
return imgurInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,21 +266,26 @@ namespace GreenshotImgurPlugin {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="imgurInfo"></param>
|
/// <param name="imgurInfo"></param>
|
||||||
public static void DeleteImgurImage(ImgurInfo imgurInfo) {
|
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 {
|
try {
|
||||||
string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml";
|
string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml";
|
||||||
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE);
|
HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE);
|
||||||
webRequest.ServicePoint.Expect100Continue = false;
|
webRequest.ServicePoint.Expect100Continue = false;
|
||||||
SetClientId(webRequest);
|
SetClientId(webRequest);
|
||||||
string responseString;
|
string responseString = null;
|
||||||
using (WebResponse response = webRequest.GetResponse()) {
|
using (WebResponse response = webRequest.GetResponse()) {
|
||||||
LogRateLimitInfo(response);
|
LogRateLimitInfo(response);
|
||||||
using (StreamReader reader = new StreamReader(response.GetResponseStream(), true)) {
|
var responseStream = response.GetResponseStream();
|
||||||
|
if (responseStream != null)
|
||||||
|
{
|
||||||
|
using (StreamReader reader = new StreamReader(responseStream, true))
|
||||||
|
{
|
||||||
responseString = reader.ReadToEnd();
|
responseString = reader.ReadToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.InfoFormat("Delete result: {0}", responseString);
|
}
|
||||||
|
Log.InfoFormat("Delete result: {0}", responseString);
|
||||||
} catch (WebException wE) {
|
} catch (WebException wE) {
|
||||||
// Allow "Bad request" this means we already deleted it
|
// Allow "Bad request" this means we already deleted it
|
||||||
if (wE.Status == WebExceptionStatus.ProtocolError) {
|
if (wE.Status == WebExceptionStatus.ProtocolError) {
|
||||||
|
@ -293,7 +307,7 @@ namespace GreenshotImgurPlugin {
|
||||||
/// <param name="key"></param>
|
/// <param name="key"></param>
|
||||||
private static void LogHeader(IDictionary<string, string> nameValues, string key) {
|
private static void LogHeader(IDictionary<string, string> nameValues, string key) {
|
||||||
if (nameValues.ContainsKey(key)) {
|
if (nameValues.ContainsKey(key)) {
|
||||||
LOG.InfoFormat("key={0}", nameValues[key]);
|
Log.InfoFormat("key={0}", nameValues[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
<Compile Include="Log4NetLogger.cs" />
|
<Compile Include="Log4NetLogger.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SvgBitmapHttpContentConverter.cs" />
|
<Compile Include="SvgBitmapHttpContentConverter.cs" />
|
||||||
|
<Compile Include="SvgImage.cs" />
|
||||||
<None Include="Languages\language_jiraplugin-de-DE.xml">
|
<None Include="Languages\language_jiraplugin-de-DE.xml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|
|
@ -118,12 +118,12 @@ namespace GreenshotJiraPlugin {
|
||||||
{
|
{
|
||||||
var surfaceContainer = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
var surfaceContainer = new SurfaceContainer(surfaceToUpload, outputSettings, filename);
|
||||||
await _jiraPlugin.JiraConnector.AttachAsync(_jiraIssue.Key, surfaceContainer);
|
await _jiraPlugin.JiraConnector.AttachAsync(_jiraIssue.Key, surfaceContainer);
|
||||||
surfaceToUpload.UploadURL = _jiraPlugin.JiraConnector.JiraBaseUri.AppendSegments("browse", _jiraIssue.Key).AbsoluteUri;
|
surfaceToUpload.UploadUrl = _jiraPlugin.JiraConnector.JiraBaseUri.AppendSegments("browse", _jiraIssue.Key).AbsoluteUri;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key);
|
Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key);
|
||||||
exportInformation.ExportMade = true;
|
exportInformation.ExportMade = true;
|
||||||
exportInformation.Uri = surfaceToUpload.UploadURL;
|
exportInformation.Uri = surfaceToUpload.UploadUrl;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
|
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ namespace GreenshotJiraPlugin {
|
||||||
var dialogResult = jiraForm.ShowDialog();
|
var dialogResult = jiraForm.ShowDialog();
|
||||||
if (dialogResult == DialogResult.OK) {
|
if (dialogResult == DialogResult.OK) {
|
||||||
try {
|
try {
|
||||||
surfaceToUpload.UploadURL = _jiraPlugin.JiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri;
|
surfaceToUpload.UploadUrl = _jiraPlugin.JiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri;
|
||||||
// Run upload in the background
|
// Run upload in the background
|
||||||
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait),
|
new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait),
|
||||||
async () =>
|
async () =>
|
||||||
|
@ -143,7 +143,7 @@ namespace GreenshotJiraPlugin {
|
||||||
);
|
);
|
||||||
Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key);
|
Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key);
|
||||||
exportInformation.ExportMade = true;
|
exportInformation.ExportMade = true;
|
||||||
exportInformation.Uri = surfaceToUpload.UploadURL;
|
exportInformation.Uri = surfaceToUpload.UploadUrl;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
|
MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,13 @@ using System.Windows.Forms;
|
||||||
using Greenshot.IniFile;
|
using Greenshot.IniFile;
|
||||||
using Greenshot.Plugin;
|
using Greenshot.Plugin;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dapplo.Log.Facade;
|
using Dapplo.Log.Facade;
|
||||||
using GreenshotJiraPlugin.Forms;
|
using GreenshotJiraPlugin.Forms;
|
||||||
|
using GreenshotPlugin.Core;
|
||||||
|
using Svg;
|
||||||
|
|
||||||
namespace GreenshotJiraPlugin {
|
namespace GreenshotJiraPlugin {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -95,6 +99,21 @@ namespace GreenshotJiraPlugin {
|
||||||
_config = IniConfig.GetIniSection<JiraConfiguration>();
|
_config = IniConfig.GetIniSection<JiraConfiguration>();
|
||||||
LogSettings.RegisterDefaultLogger<Log4NetLogger>();
|
LogSettings.RegisterDefaultLogger<Log4NetLogger>();
|
||||||
|
|
||||||
|
// Add a SVG converter, although it doesn't fit to the Jira plugin there is currently no other way
|
||||||
|
ImageHelper.StreamConverters["svg"] = (stream, s) =>
|
||||||
|
{
|
||||||
|
stream.Position = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return SvgImage.FromStream(stream).Image;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("Can't load SVG", ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -33,8 +32,6 @@ using Dapplo.HttpExtensions.Support;
|
||||||
using Dapplo.Log.Facade;
|
using Dapplo.Log.Facade;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using GreenshotPlugin.Core;
|
|
||||||
using Svg;
|
|
||||||
|
|
||||||
namespace GreenshotJiraPlugin
|
namespace GreenshotJiraPlugin
|
||||||
{
|
{
|
||||||
|
@ -86,12 +83,12 @@ namespace GreenshotJiraPlugin
|
||||||
using (var memoryStream = (MemoryStream) await StreamHttpContentConverter.Instance.ConvertFromHttpContentAsync(typeof(MemoryStream), httpContent, cancellationToken).ConfigureAwait(false))
|
using (var memoryStream = (MemoryStream) await StreamHttpContentConverter.Instance.ConvertFromHttpContentAsync(typeof(MemoryStream), httpContent, cancellationToken).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
Log.Debug().WriteLine("Creating a Bitmap from the SVG.");
|
Log.Debug().WriteLine("Creating a Bitmap from the SVG.");
|
||||||
var bitmap = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96);
|
var svgImage = new SvgImage(memoryStream)
|
||||||
var svgDoc = SvgDocument.Open<SvgDocument>(memoryStream);
|
{
|
||||||
svgDoc.Width = Width;
|
Height = Height,
|
||||||
svgDoc.Height = Height;
|
Width = Width
|
||||||
svgDoc.Draw(bitmap);
|
};
|
||||||
return bitmap;
|
return svgImage.Image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
118
GreenshotJiraPlugin/SvgImage.cs
Normal file
118
GreenshotJiraPlugin/SvgImage.cs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using GreenshotPlugin.Core;
|
||||||
|
using Svg;
|
||||||
|
|
||||||
|
namespace GreenshotJiraPlugin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create an image look like of the SVG
|
||||||
|
/// </summary>
|
||||||
|
public class SvgImage : IImage
|
||||||
|
{
|
||||||
|
private readonly SvgDocument _svgDocument;
|
||||||
|
|
||||||
|
private Image _imageClone;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory to create via a stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">Stream</param>
|
||||||
|
/// <returns>IImage</returns>
|
||||||
|
public static IImage FromStream(Stream stream)
|
||||||
|
{
|
||||||
|
return new SvgImage(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
public SvgImage(Stream stream)
|
||||||
|
{
|
||||||
|
_svgDocument = SvgDocument.Open<SvgDocument>(stream);
|
||||||
|
Height = (int)_svgDocument.ViewBox.Height;
|
||||||
|
Width = (int)_svgDocument.ViewBox.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Height of the image, can be set to change
|
||||||
|
/// </summary>
|
||||||
|
public int Height { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Width of the image, can be set to change.
|
||||||
|
/// </summary>
|
||||||
|
public int Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the image
|
||||||
|
/// </summary>
|
||||||
|
public Size Size => new Size(Width, Height);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pixelformat of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Horizontal resolution of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
public float HorizontalResolution => Image.HorizontalResolution;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertical resolution of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
public float VerticalResolution => Image.VerticalResolution;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unterlying image, or an on demand rendered version with different attributes as the original
|
||||||
|
/// </summary>
|
||||||
|
public Image Image
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||||
|
{
|
||||||
|
return _imageClone;
|
||||||
|
}
|
||||||
|
// Calculate new image clone
|
||||||
|
_imageClone?.Dispose();
|
||||||
|
_imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96);
|
||||||
|
_svgDocument.Draw((Bitmap)_imageClone);
|
||||||
|
return _imageClone;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_imageClone?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -123,7 +123,7 @@ namespace GreenshotPlugin.Core {
|
||||||
public void ProcessExport(ExportInformation exportInformation, ISurface surface) {
|
public void ProcessExport(ExportInformation exportInformation, ISurface surface) {
|
||||||
if (exportInformation != null && exportInformation.ExportMade) {
|
if (exportInformation != null && exportInformation.ExportMade) {
|
||||||
if (!string.IsNullOrEmpty(exportInformation.Uri)) {
|
if (!string.IsNullOrEmpty(exportInformation.Uri)) {
|
||||||
surface.UploadURL = exportInformation.Uri;
|
surface.UploadUrl = exportInformation.Uri;
|
||||||
surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription));
|
surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription));
|
||||||
} else if (!string.IsNullOrEmpty(exportInformation.Filepath)) {
|
} else if (!string.IsNullOrEmpty(exportInformation.Filepath)) {
|
||||||
surface.LastSaveFullPath = exportInformation.Filepath;
|
surface.LastSaveFullPath = exportInformation.Filepath;
|
||||||
|
|
|
@ -39,9 +39,9 @@ namespace GreenshotPlugin.Core {
|
||||||
/// Description of ClipboardHelper.
|
/// Description of ClipboardHelper.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ClipboardHelper {
|
public static class ClipboardHelper {
|
||||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(ClipboardHelper));
|
private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper));
|
||||||
private static readonly object clipboardLockObject = new object();
|
private static readonly object ClipboardLockObject = new object();
|
||||||
private static readonly CoreConfiguration config = IniConfig.GetIniSection<CoreConfiguration>();
|
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||||
private static readonly string FORMAT_FILECONTENTS = "FileContents";
|
private static readonly string FORMAT_FILECONTENTS = "FileContents";
|
||||||
private static readonly string FORMAT_PNG = "PNG";
|
private static readonly string FORMAT_PNG = "PNG";
|
||||||
private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art";
|
private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art";
|
||||||
|
@ -53,11 +53,10 @@ namespace GreenshotPlugin.Core {
|
||||||
private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap";
|
private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap";
|
||||||
//private static readonly string FORMAT_HTML = "HTML Format";
|
//private static readonly string FORMAT_HTML = "HTML Format";
|
||||||
|
|
||||||
private static IntPtr nextClipboardViewer = IntPtr.Zero;
|
|
||||||
// Template for the HTML Text on the clipboard
|
// Template for the HTML Text on the clipboard
|
||||||
// see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx
|
// see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx
|
||||||
// or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx
|
// or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx
|
||||||
private const string HTML_CLIPBOARD_STRING = @"Version:0.9
|
private const string HtmlClipboardString = @"Version:0.9
|
||||||
StartHTML:<<<<<<<1
|
StartHTML:<<<<<<<1
|
||||||
EndHTML:<<<<<<<2
|
EndHTML:<<<<<<<2
|
||||||
StartFragment:<<<<<<<3
|
StartFragment:<<<<<<<3
|
||||||
|
@ -75,7 +74,7 @@ EndSelection:<<<<<<<4
|
||||||
<!--EndFragment -->
|
<!--EndFragment -->
|
||||||
</BODY>
|
</BODY>
|
||||||
</HTML>";
|
</HTML>";
|
||||||
private const string HTML_CLIPBOARD_BASE64_STRING = @"Version:0.9
|
private const string HtmlClipboardBase64String = @"Version:0.9
|
||||||
StartHTML:<<<<<<<1
|
StartHTML:<<<<<<<1
|
||||||
EndHTML:<<<<<<<2
|
EndHTML:<<<<<<<2
|
||||||
StartFragment:<<<<<<<3
|
StartFragment:<<<<<<<3
|
||||||
|
@ -111,7 +110,7 @@ EndSelection:<<<<<<<4
|
||||||
using (Process ownerProcess = Process.GetProcessById(pid))
|
using (Process ownerProcess = Process.GetProcessById(pid))
|
||||||
{
|
{
|
||||||
// Exclude myself
|
// Exclude myself
|
||||||
if (ownerProcess != null && me.Id != ownerProcess.Id)
|
if (me.Id != ownerProcess.Id)
|
||||||
{
|
{
|
||||||
// Get Process Name
|
// Get Process Name
|
||||||
owner = ownerProcess.ProcessName;
|
owner = ownerProcess.ProcessName;
|
||||||
|
@ -122,20 +121,21 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
LOG.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e);
|
Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e);
|
||||||
StringBuilder title = new StringBuilder(260, 260);
|
var title = new StringBuilder(260, 260);
|
||||||
User32.GetWindowText(hWnd, title, title.Capacity);
|
User32.GetWindowText(hWnd, title, title.Capacity);
|
||||||
owner = title.ToString();
|
owner = title.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.Warn("Non critical error: Couldn't get clipboard owner.", e);
|
Log.Warn("Non critical error: Couldn't get clipboard owner.", e);
|
||||||
}
|
}
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ EndSelection:<<<<<<<4
|
||||||
/// <param name="ido"></param>
|
/// <param name="ido"></param>
|
||||||
/// <param name="copy"></param>
|
/// <param name="copy"></param>
|
||||||
private static void SetDataObject(IDataObject ido, bool copy) {
|
private static void SetDataObject(IDataObject ido, bool copy) {
|
||||||
lock (clipboardLockObject) {
|
lock (ClipboardLockObject) {
|
||||||
// Clear first, this seems to solve some issues
|
// Clear first, this seems to solve some issues
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -155,7 +155,7 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
catch (Exception clearException)
|
catch (Exception clearException)
|
||||||
{
|
{
|
||||||
LOG.Warn(clearException.Message);
|
Log.Warn(clearException.Message);
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -164,7 +164,7 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
catch (Exception clipboardSetException)
|
catch (Exception clipboardSetException)
|
||||||
{
|
{
|
||||||
string messageText = null;
|
string messageText;
|
||||||
string clipboardOwner = GetClipboardOwner();
|
string clipboardOwner = GetClipboardOwner();
|
||||||
if (clipboardOwner != null)
|
if (clipboardOwner != null)
|
||||||
{
|
{
|
||||||
|
@ -173,7 +173,7 @@ EndSelection:<<<<<<<4
|
||||||
else {
|
else {
|
||||||
messageText = Language.GetString("clipboard_error");
|
messageText = Language.GetString("clipboard_error");
|
||||||
}
|
}
|
||||||
LOG.Error(messageText, clipboardSetException);
|
Log.Error(messageText, clipboardSetException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,21 +182,21 @@ EndSelection:<<<<<<<4
|
||||||
/// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions.
|
/// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IDataObject GetDataObject() {
|
public static IDataObject GetDataObject() {
|
||||||
lock (clipboardLockObject) {
|
lock (ClipboardLockObject) {
|
||||||
int retryCount = 2;
|
int retryCount = 2;
|
||||||
while (retryCount >= 0) {
|
while (retryCount >= 0) {
|
||||||
try {
|
try {
|
||||||
return Clipboard.GetDataObject();
|
return Clipboard.GetDataObject();
|
||||||
} catch (Exception ee) {
|
} catch (Exception ee) {
|
||||||
if (retryCount == 0) {
|
if (retryCount == 0) {
|
||||||
string messageText = null;
|
string messageText;
|
||||||
string clipboardOwner = GetClipboardOwner();
|
string clipboardOwner = GetClipboardOwner();
|
||||||
if (clipboardOwner != null) {
|
if (clipboardOwner != null) {
|
||||||
messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner);
|
messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner);
|
||||||
} else {
|
} else {
|
||||||
messageText = Language.GetString("clipboard_error");
|
messageText = Language.GetString("clipboard_error");
|
||||||
}
|
}
|
||||||
LOG.Error(messageText, ee);
|
Log.Error(messageText, ee);
|
||||||
} else {
|
} else {
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
@ -264,13 +264,15 @@ EndSelection:<<<<<<<4
|
||||||
if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) {
|
if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) {
|
||||||
try {
|
try {
|
||||||
MemoryStream imageStream = dataObject.GetData(FORMAT_FILECONTENTS) as MemoryStream;
|
MemoryStream imageStream = dataObject.GetData(FORMAT_FILECONTENTS) as MemoryStream;
|
||||||
if (isValidStream(imageStream)) {
|
if (IsValidStream(imageStream)) {
|
||||||
using (Image tmpImage = Image.FromStream(imageStream)) {
|
using (ImageHelper.FromStream(imageStream))
|
||||||
|
{
|
||||||
// If we get here, there is an image
|
// If we get here, there is an image
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +284,7 @@ EndSelection:<<<<<<<4
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="memoryStream"></param>
|
/// <param name="memoryStream"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static bool isValidStream(MemoryStream memoryStream) {
|
private static bool IsValidStream(MemoryStream memoryStream) {
|
||||||
return memoryStream != null && memoryStream.Length > 0;
|
return memoryStream != null && memoryStream.Length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +311,7 @@ EndSelection:<<<<<<<4
|
||||||
// Get single image, this takes the "best" match
|
// Get single image, this takes the "best" match
|
||||||
Image singleImage = GetImage(dataObject);
|
Image singleImage = GetImage(dataObject);
|
||||||
if (singleImage != null) {
|
if (singleImage != null) {
|
||||||
LOG.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat);
|
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat);
|
||||||
yield return singleImage;
|
yield return singleImage;
|
||||||
} else {
|
} else {
|
||||||
// check if files are supplied
|
// check if files are supplied
|
||||||
|
@ -320,10 +322,10 @@ EndSelection:<<<<<<<4
|
||||||
try {
|
try {
|
||||||
returnImage = ImageHelper.LoadImage(imageFile);
|
returnImage = ImageHelper.LoadImage(imageFile);
|
||||||
} catch (Exception streamImageEx) {
|
} catch (Exception streamImageEx) {
|
||||||
LOG.Error("Problem retrieving Image from clipboard.", streamImageEx);
|
Log.Error("Problem retrieving Image from clipboard.", streamImageEx);
|
||||||
}
|
}
|
||||||
if (returnImage != null) {
|
if (returnImage != null) {
|
||||||
LOG.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat);
|
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat);
|
||||||
yield return returnImage;
|
yield return returnImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,20 +348,19 @@ EndSelection:<<<<<<<4
|
||||||
// So I build some special logik to get the best format:
|
// So I build some special logik to get the best format:
|
||||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
|
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) {
|
||||||
// Outlook ??
|
// Outlook ??
|
||||||
LOG.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||||
retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF };
|
retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF };
|
||||||
} else {
|
} else {
|
||||||
retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF };
|
retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF };
|
||||||
}
|
}
|
||||||
foreach (string currentFormat in retrieveFormats) {
|
foreach (string currentFormat in retrieveFormats) {
|
||||||
if (formats.Contains(currentFormat)) {
|
if (formats.Contains(currentFormat)) {
|
||||||
LOG.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||||
returnImage = GetImageForFormat(currentFormat, dataObject);
|
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||||
} else {
|
} else {
|
||||||
LOG.DebugFormat("Couldn't find format {0}.", currentFormat);
|
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||||
}
|
}
|
||||||
if (returnImage != null) {
|
if (returnImage != null) {
|
||||||
ImageHelper.Orientate(returnImage);
|
|
||||||
return returnImage;
|
return returnImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,54 +379,59 @@ EndSelection:<<<<<<<4
|
||||||
private static Image GetImageForFormat(string format, IDataObject dataObject) {
|
private static Image GetImageForFormat(string format, IDataObject dataObject) {
|
||||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||||
MemoryStream imageStream = clipboardObject as MemoryStream;
|
MemoryStream imageStream = clipboardObject as MemoryStream;
|
||||||
if (!isValidStream(imageStream)) {
|
if (!IsValidStream(imageStream)) {
|
||||||
// TODO: add "HTML Format" support here...
|
// TODO: add "HTML Format" support here...
|
||||||
return clipboardObject as Image;
|
return clipboardObject as Image;
|
||||||
} else {
|
}
|
||||||
if (config.EnableSpecialDIBClipboardReader) {
|
if (CoreConfig.EnableSpecialDIBClipboardReader) {
|
||||||
if (format == FORMAT_17 || format == DataFormats.Dib) {
|
if (format == FORMAT_17 || format == DataFormats.Dib) {
|
||||||
LOG.Info("Found DIB stream, trying to process it.");
|
Log.Info("Found DIB stream, trying to process it.");
|
||||||
try {
|
try {
|
||||||
byte[] dibBuffer = new byte[imageStream.Length];
|
byte[] dibBuffer = new byte[imageStream.Length];
|
||||||
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||||
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer);
|
||||||
if (!infoHeader.IsDibV5) {
|
if (!infoHeader.IsDibV5) {
|
||||||
LOG.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||||
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||||
uint infoHeaderSize = infoHeader.biSize;
|
uint infoHeaderSize = infoHeader.biSize;
|
||||||
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||||
|
|
||||||
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER();
|
BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER
|
||||||
fileHeader.bfType = BITMAPFILEHEADER.BM;
|
{
|
||||||
fileHeader.bfSize = fileSize;
|
bfType = BITMAPFILEHEADER.BM,
|
||||||
fileHeader.bfReserved1 = 0;
|
bfSize = fileSize,
|
||||||
fileHeader.bfReserved2 = 0;
|
bfReserved1 = 0,
|
||||||
fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4);
|
bfReserved2 = 0,
|
||||||
|
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed*4)
|
||||||
|
};
|
||||||
|
|
||||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray<BITMAPFILEHEADER>(fileHeader);
|
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
|
||||||
|
|
||||||
using (MemoryStream bitmapStream = new MemoryStream()) {
|
using (MemoryStream bitmapStream = new MemoryStream()) {
|
||||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||||
using (Image tmpImage = Image.FromStream(bitmapStream)) {
|
var image = ImageHelper.FromStream(bitmapStream);
|
||||||
if (tmpImage != null) {
|
if (image != null)
|
||||||
return ImageHelper.Clone(tmpImage);
|
{
|
||||||
}
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.Info("Using special DIBV5 / Format17 format reader");
|
Log.Info("Using special DIBV5 / Format17 format reader");
|
||||||
// CF_DIBV5
|
// CF_DIBV5
|
||||||
IntPtr gcHandle = IntPtr.Zero;
|
IntPtr gcHandle = IntPtr.Zero;
|
||||||
try {
|
try {
|
||||||
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
||||||
gcHandle = GCHandle.ToIntPtr(handle);
|
gcHandle = GCHandle.ToIntPtr(handle);
|
||||||
return new Bitmap(infoHeader.biWidth, infoHeader.biHeight, -(int)(infoHeader.biSizeImage / infoHeader.biHeight),
|
return
|
||||||
|
new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
|
||||||
|
-(int)(infoHeader.biSizeImage / infoHeader.biHeight),
|
||||||
infoHeader.biBitCount == 32?PixelFormat.Format32bppArgb: PixelFormat.Format24bppRgb,
|
infoHeader.biBitCount == 32?PixelFormat.Format32bppArgb: PixelFormat.Format24bppRgb,
|
||||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight)));
|
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.biHeight - 1) * (int)(infoHeader.biSizeImage / infoHeader.biHeight))
|
||||||
|
);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LOG.Error("Problem retrieving Format17 from clipboard.", ex);
|
Log.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (gcHandle == IntPtr.Zero) {
|
if (gcHandle == IntPtr.Zero) {
|
||||||
GCHandle.FromIntPtr(gcHandle).Free();
|
GCHandle.FromIntPtr(gcHandle).Free();
|
||||||
|
@ -433,23 +439,24 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception dibEx) {
|
} catch (Exception dibEx) {
|
||||||
LOG.Error("Problem retrieving DIB from clipboard.", dibEx);
|
Log.Error("Problem retrieving DIB from clipboard.", dibEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.Info("Skipping special DIB format reader as it's disabled in the configuration.");
|
Log.Info("Skipping special DIB format reader as it's disabled in the configuration.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
if (imageStream != null)
|
||||||
|
{
|
||||||
imageStream.Seek(0, SeekOrigin.Begin);
|
imageStream.Seek(0, SeekOrigin.Begin);
|
||||||
using (Image tmpImage = Image.FromStream(imageStream, true, true)) {
|
var tmpImage = ImageHelper.FromStream(imageStream);
|
||||||
if (tmpImage != null) {
|
if (tmpImage != null) {
|
||||||
LOG.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
|
Log.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
|
||||||
return ImageHelper.Clone(tmpImage);
|
return tmpImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception streamImageEx) {
|
} catch (Exception streamImageEx) {
|
||||||
LOG.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx);
|
Log.Error(string.Format("Problem retrieving {0} from clipboard.", format), streamImageEx);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -468,7 +475,7 @@ EndSelection:<<<<<<<4
|
||||||
/// <returns>string if there is text on the clipboard</returns>
|
/// <returns>string if there is text on the clipboard</returns>
|
||||||
public static string GetText(IDataObject dataObject) {
|
public static string GetText(IDataObject dataObject) {
|
||||||
if (ContainsText(dataObject)) {
|
if (ContainsText(dataObject)) {
|
||||||
return (String)dataObject.GetData(DataFormats.Text);
|
return (string)dataObject.GetData(DataFormats.Text);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -483,32 +490,32 @@ EndSelection:<<<<<<<4
|
||||||
SetDataObject(ido, true);
|
SetDataObject(ido, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getHTMLString(ISurface surface, string filename) {
|
private static string GetHtmlString(ISurface surface, string filename) {
|
||||||
string utf8EncodedHTMLString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HTML_CLIPBOARD_STRING));
|
string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString));
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${width}", surface.Image.Width.ToString());
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString());
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${height}", surface.Image.Height.ToString());
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString());
|
||||||
utf8EncodedHTMLString= utf8EncodedHTMLString.Replace("${file}", filename.Replace("\\","/"));
|
utf8EncodedHtmlString= utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\","/"));
|
||||||
StringBuilder sb=new StringBuilder();
|
StringBuilder sb=new StringBuilder();
|
||||||
sb.Append(utf8EncodedHTMLString);
|
sb.Append(utf8EncodedHtmlString);
|
||||||
sb.Replace("<<<<<<<1", (utf8EncodedHTMLString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<2", (utf8EncodedHTMLString.IndexOf("</HTML>")).ToString("D8"));
|
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>")).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<3", (utf8EncodedHTMLString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<4", (utf8EncodedHTMLString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getHTMLDataURLString(ISurface surface, MemoryStream pngStream) {
|
private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) {
|
||||||
string utf8EncodedHTMLString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HTML_CLIPBOARD_BASE64_STRING));
|
string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String));
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${width}", surface.Image.Width.ToString());
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString());
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${height}", surface.Image.Height.ToString());
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString());
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${format}", "png");
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png");
|
||||||
utf8EncodedHTMLString = utf8EncodedHTMLString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(),0, (int)pngStream.Length));
|
utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(),0, (int)pngStream.Length));
|
||||||
StringBuilder sb=new StringBuilder();
|
StringBuilder sb=new StringBuilder();
|
||||||
sb.Append(utf8EncodedHTMLString);
|
sb.Append(utf8EncodedHtmlString);
|
||||||
sb.Replace("<<<<<<<1", (utf8EncodedHTMLString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("<HTML>") + "<HTML>".Length).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<2", (utf8EncodedHTMLString.IndexOf("</HTML>")).ToString("D8"));
|
sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("</HTML>")).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<3", (utf8EncodedHTMLString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("<!--StartFragment -->")+"<!--StartFragment -->".Length).ToString("D8"));
|
||||||
sb.Replace("<<<<<<<4", (utf8EncodedHTMLString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("<!--EndFragment -->")).ToString("D8"));
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,7 +546,7 @@ EndSelection:<<<<<<<4
|
||||||
disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
||||||
try {
|
try {
|
||||||
// Create PNG stream
|
// Create PNG stream
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.PNG)) {
|
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) {
|
||||||
pngStream = new MemoryStream();
|
pngStream = new MemoryStream();
|
||||||
// PNG works for e.g. Powerpoint
|
// PNG works for e.g. Powerpoint
|
||||||
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||||
|
@ -549,11 +556,11 @@ EndSelection:<<<<<<<4
|
||||||
dataObject.SetData(FORMAT_PNG, false, pngStream);
|
dataObject.SetData(FORMAT_PNG, false, pngStream);
|
||||||
}
|
}
|
||||||
} catch (Exception pngEX) {
|
} catch (Exception pngEX) {
|
||||||
LOG.Error("Error creating PNG for the Clipboard.", pngEX);
|
Log.Error("Error creating PNG for the Clipboard.", pngEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.DIB)) {
|
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) {
|
||||||
using (MemoryStream tmpBmpStream = new MemoryStream()) {
|
using (MemoryStream tmpBmpStream = new MemoryStream()) {
|
||||||
// Save image as BMP
|
// Save image as BMP
|
||||||
SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false);
|
SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false);
|
||||||
|
@ -568,21 +575,23 @@ EndSelection:<<<<<<<4
|
||||||
dataObject.SetData(DataFormats.Dib, true, dibStream);
|
dataObject.SetData(DataFormats.Dib, true, dibStream);
|
||||||
}
|
}
|
||||||
} catch (Exception dibEx) {
|
} catch (Exception dibEx) {
|
||||||
LOG.Error("Error creating DIB for the Clipboard.", dibEx);
|
Log.Error("Error creating DIB for the Clipboard.", dibEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CF_DibV5
|
// CF_DibV5
|
||||||
try {
|
try {
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) {
|
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) {
|
||||||
// Create the stream for the clipboard
|
// Create the stream for the clipboard
|
||||||
dibV5Stream = new MemoryStream();
|
dibV5Stream = new MemoryStream();
|
||||||
|
|
||||||
// Create the BITMAPINFOHEADER
|
// Create the BITMAPINFOHEADER
|
||||||
BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32);
|
BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32)
|
||||||
|
{
|
||||||
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
||||||
header.biCompression = BI_COMPRESSION.BI_BITFIELDS;
|
biCompression = BI_COMPRESSION.BI_BITFIELDS
|
||||||
|
};
|
||||||
// Create a byte[] to write
|
// Create a byte[] to write
|
||||||
byte[] headerBytes = BinaryStructHelper.ToByteArray<BITMAPINFOHEADER>(header);
|
byte[] headerBytes = BinaryStructHelper.ToByteArray(header);
|
||||||
// Write the BITMAPINFOHEADER to the stream
|
// Write the BITMAPINFOHEADER to the stream
|
||||||
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
|
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
|
||||||
|
|
||||||
|
@ -591,7 +600,7 @@ EndSelection:<<<<<<<4
|
||||||
// Make sure the values are set
|
// Make sure the values are set
|
||||||
colorMask.InitValues();
|
colorMask.InitValues();
|
||||||
// Create the byte[] from the struct
|
// Create the byte[] from the struct
|
||||||
byte[] colorMaskBytes = BinaryStructHelper.ToByteArray<BitfieldColorMask>(colorMask);
|
byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask);
|
||||||
Array.Reverse(colorMaskBytes);
|
Array.Reverse(colorMaskBytes);
|
||||||
// Write to the stream
|
// Write to the stream
|
||||||
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
|
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
|
||||||
|
@ -605,35 +614,37 @@ EndSelection:<<<<<<<4
|
||||||
dataObject.SetData(FORMAT_17, true, dibV5Stream);
|
dataObject.SetData(FORMAT_17, true, dibV5Stream);
|
||||||
}
|
}
|
||||||
} catch (Exception dibEx) {
|
} catch (Exception dibEx) {
|
||||||
LOG.Error("Error creating DIB for the Clipboard.", dibEx);
|
Log.Error("Error creating DIB for the Clipboard.", dibEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the HTML
|
// Set the HTML
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
|
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) {
|
||||||
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||||
string html = getHTMLString(surface, tmpFile);
|
string html = GetHtmlString(surface, tmpFile);
|
||||||
dataObject.SetText(html, TextDataFormat.Html);
|
dataObject.SetText(html, TextDataFormat.Html);
|
||||||
} else if (config.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) {
|
} else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) {
|
||||||
string html;
|
string html;
|
||||||
using (MemoryStream tmpPNGStream = new MemoryStream()) {
|
using (MemoryStream tmpPngStream = new MemoryStream()) {
|
||||||
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false)
|
||||||
|
{
|
||||||
// Do not allow to reduce the colors, some applications dislike 256 color images
|
// Do not allow to reduce the colors, some applications dislike 256 color images
|
||||||
// reported with bug #3594681
|
// reported with bug #3594681
|
||||||
pngOutputSettings.DisableReduceColors = true;
|
DisableReduceColors = true
|
||||||
|
};
|
||||||
// Check if we can use the previously used image
|
// Check if we can use the previously used image
|
||||||
if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) {
|
if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) {
|
||||||
ImageOutput.SaveToStream(imageToSave, surface, tmpPNGStream, pngOutputSettings);
|
ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
|
||||||
} else {
|
} else {
|
||||||
ImageOutput.SaveToStream(surface, tmpPNGStream, pngOutputSettings);
|
ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings);
|
||||||
}
|
}
|
||||||
html = getHTMLDataURLString(surface, tmpPNGStream);
|
html = GetHtmlDataUrlString(surface, tmpPngStream);
|
||||||
}
|
}
|
||||||
dataObject.SetText(html, TextDataFormat.Html);
|
dataObject.SetText(html, TextDataFormat.Html);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone!
|
// we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone!
|
||||||
// Check if Bitmap is wanted
|
// Check if Bitmap is wanted
|
||||||
if (config.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) {
|
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) {
|
||||||
dataObject.SetImage(imageToSave);
|
dataObject.SetImage(imageToSave);
|
||||||
// Place the DataObject to the clipboard
|
// Place the DataObject to the clipboard
|
||||||
SetDataObject(dataObject, true);
|
SetDataObject(dataObject, true);
|
||||||
|
@ -656,8 +667,8 @@ EndSelection:<<<<<<<4
|
||||||
dibV5Stream = null;
|
dibV5Stream = null;
|
||||||
}
|
}
|
||||||
// cleanup if needed
|
// cleanup if needed
|
||||||
if (disposeImage && imageToSave != null) {
|
if (disposeImage) {
|
||||||
imageToSave.Dispose();
|
imageToSave?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -695,7 +706,7 @@ EndSelection:<<<<<<<4
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type</param>
|
/// <param name="type">Type</param>
|
||||||
/// <param name="obj">object</param>
|
/// <param name="obj">object</param>
|
||||||
public static void SetClipboardData(Type type, Object obj) {
|
public static void SetClipboardData(Type type, object obj) {
|
||||||
DataFormats.Format format = DataFormats.GetFormat(type.FullName);
|
DataFormats.Format format = DataFormats.GetFormat(type.FullName);
|
||||||
|
|
||||||
//now copy to clipboard
|
//now copy to clipboard
|
||||||
|
@ -724,7 +735,7 @@ EndSelection:<<<<<<<4
|
||||||
formats = dataObj.GetFormats();
|
formats = dataObj.GetFormats();
|
||||||
}
|
}
|
||||||
if (formats != null) {
|
if (formats != null) {
|
||||||
LOG.DebugFormat("Got clipboard formats: {0}", String.Join(",", formats));
|
Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats));
|
||||||
return new List<string>(formats);
|
return new List<string>(formats);
|
||||||
}
|
}
|
||||||
return new List<string>();
|
return new List<string>();
|
||||||
|
@ -784,7 +795,7 @@ EndSelection:<<<<<<<4
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type to get</param>
|
/// <param name="type">Type to get</param>
|
||||||
/// <returns>object from clipboard</returns>
|
/// <returns>object from clipboard</returns>
|
||||||
public static Object GetClipboardData(Type type) {
|
public static object GetClipboardData(Type type) {
|
||||||
string format = type.FullName;
|
string format = type.FullName;
|
||||||
return GetClipboardData(format);
|
return GetClipboardData(format);
|
||||||
}
|
}
|
||||||
|
@ -795,7 +806,7 @@ EndSelection:<<<<<<<4
|
||||||
/// <param name="dataObj">IDataObject</param>
|
/// <param name="dataObj">IDataObject</param>
|
||||||
/// <param name="type">Type to get</param>
|
/// <param name="type">Type to get</param>
|
||||||
/// <returns>object from IDataObject</returns>
|
/// <returns>object from IDataObject</returns>
|
||||||
public static Object GetFromDataObject(IDataObject dataObj, Type type) {
|
public static object GetFromDataObject(IDataObject dataObj, Type type) {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
return GetFromDataObject(dataObj, type.FullName);
|
return GetFromDataObject(dataObj, type.FullName);
|
||||||
}
|
}
|
||||||
|
@ -820,7 +831,7 @@ EndSelection:<<<<<<<4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
LOG.Warn("Ignoring an issue with getting the dropFilenames from the clipboard: ", ex);
|
Log.Warn("Ignoring an issue with getting the dropFilenames from the clipboard: ", ex);
|
||||||
}
|
}
|
||||||
return filenames;
|
return filenames;
|
||||||
}
|
}
|
||||||
|
@ -831,12 +842,12 @@ EndSelection:<<<<<<<4
|
||||||
/// <param name="dataObj">IDataObject</param>
|
/// <param name="dataObj">IDataObject</param>
|
||||||
/// <param name="format">format to get</param>
|
/// <param name="format">format to get</param>
|
||||||
/// <returns>object from IDataObject</returns>
|
/// <returns>object from IDataObject</returns>
|
||||||
public static Object GetFromDataObject(IDataObject dataObj, string format) {
|
public static object GetFromDataObject(IDataObject dataObj, string format) {
|
||||||
if (dataObj != null) {
|
if (dataObj != null) {
|
||||||
try {
|
try {
|
||||||
return dataObj.GetData(format);
|
return dataObj.GetData(format);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.Error("Error in GetClipboardData.", e);
|
Log.Error("Error in GetClipboardData.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -847,7 +858,7 @@ EndSelection:<<<<<<<4
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="format">format to get</param>
|
/// <param name="format">format to get</param>
|
||||||
/// <returns>object from clipboard</returns>
|
/// <returns>object from clipboard</returns>
|
||||||
public static Object GetClipboardData(string format) {
|
public static object GetClipboardData(string format) {
|
||||||
return GetFromDataObject(GetDataObject(), format);
|
return GetFromDataObject(GetDataObject(), format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
GreenshotPlugin/Core/Func.cs
Normal file
29
GreenshotPlugin/Core/Func.cs
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace GreenshotPlugin.Core
|
||||||
|
{
|
||||||
|
public delegate TResult Func<out TResult>();
|
||||||
|
public delegate TResult Func<in T, out TResult>(T arg);
|
||||||
|
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
|
||||||
|
public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
|
||||||
|
public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
|
||||||
|
}
|
68
GreenshotPlugin/Core/IImage.cs
Normal file
68
GreenshotPlugin/Core/IImage.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
|
namespace GreenshotPlugin.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The image interface, this abstracts an image
|
||||||
|
/// </summary>
|
||||||
|
public interface IImage : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Height of the image, can be set to change
|
||||||
|
/// </summary>
|
||||||
|
int Height { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Width of the image, can be set to change.
|
||||||
|
/// </summary>
|
||||||
|
int Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the image
|
||||||
|
/// </summary>
|
||||||
|
Size Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pixelformat of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
PixelFormat PixelFormat { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertical resolution of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
float VerticalResolution { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Horizontal resolution of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
float HorizontalResolution { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unterlying image, or an on demand rendered version with different attributes as the original
|
||||||
|
/// </summary>
|
||||||
|
Image Image { get; }
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -390,41 +390,13 @@ namespace GreenshotPlugin.Core {
|
||||||
if (string.IsNullOrEmpty(fullPath)) {
|
if (string.IsNullOrEmpty(fullPath)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Image fileImage;
|
|
||||||
LOG.InfoFormat("Loading image from file {0}", fullPath);
|
LOG.InfoFormat("Loading image from file {0}", fullPath);
|
||||||
// Fixed lock problem Bug #3431881
|
// Fixed lock problem Bug #3431881
|
||||||
using (Stream surfaceFileStream = File.OpenRead(fullPath)) {
|
using (Stream surfaceFileStream = File.OpenRead(fullPath)) {
|
||||||
// And fixed problem that the bitmap stream is disposed... by Cloning the image
|
returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface);
|
||||||
// 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 {0} with Size {1}x{2} and PixelFormat {3}", fullPath, tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
|
||||||
fileImage = ImageHelper.Clone(tmpImage);
|
|
||||||
}
|
}
|
||||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
if (returnSurface != null) {
|
||||||
const int markerSize = 14;
|
LOG.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution);
|
||||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
|
||||||
string greenshotMarker;
|
|
||||||
using (StreamReader streamReader = new StreamReader(surfaceFileStream)) {
|
|
||||||
greenshotMarker = streamReader.ReadToEnd();
|
|
||||||
if (!greenshotMarker.StartsWith("Greenshot")) {
|
|
||||||
throw new ArgumentException(string.Format("{0} is not a Greenshot file!", fullPath));
|
|
||||||
}
|
|
||||||
LOG.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
|
||||||
const int filesizeLocation = 8 + markerSize;
|
|
||||||
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
|
|
||||||
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 file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
|
||||||
}
|
}
|
||||||
return returnSurface;
|
return returnSurface;
|
||||||
}
|
}
|
||||||
|
|
86
GreenshotPlugin/Core/ImageWrapper.cs
Normal file
86
GreenshotPlugin/Core/ImageWrapper.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
|
namespace GreenshotPlugin.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wrap an image, make it resizeable
|
||||||
|
/// </summary>
|
||||||
|
public class ImageWrapper : IImage
|
||||||
|
{
|
||||||
|
// Underlying image, is used to generate a resized version of it when needed
|
||||||
|
private readonly Image _image;
|
||||||
|
private Image _imageClone;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">Image</param>
|
||||||
|
/// <returns>IImage</returns>
|
||||||
|
public static IImage FromImage(Image image)
|
||||||
|
{
|
||||||
|
return image == null ? null : new ImageWrapper(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageWrapper(Image image)
|
||||||
|
{
|
||||||
|
// Make sure the orientation is set correctly so Greenshot can process the image correctly
|
||||||
|
ImageHelper.Orientate(image);
|
||||||
|
_image = image;
|
||||||
|
Width = _image.Width;
|
||||||
|
Height = _image.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_image.Dispose();
|
||||||
|
_imageClone?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Height of the image, can be set to change
|
||||||
|
/// </summary>
|
||||||
|
public int Height { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Width of the image, can be set to change.
|
||||||
|
/// </summary>
|
||||||
|
public int Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the image
|
||||||
|
/// </summary>
|
||||||
|
public Size Size => new Size(Width, Height);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pixelformat of the underlying image
|
||||||
|
/// </summary>
|
||||||
|
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||||
|
|
||||||
|
public float HorizontalResolution => Image.HorizontalResolution;
|
||||||
|
public float VerticalResolution => Image.VerticalResolution;
|
||||||
|
|
||||||
|
public Image Image
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_imageClone == null)
|
||||||
|
{
|
||||||
|
if (_image.Height == Height && _image.Width == Width)
|
||||||
|
{
|
||||||
|
return _image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||||
|
{
|
||||||
|
return _imageClone;
|
||||||
|
}
|
||||||
|
// Calculate new image clone
|
||||||
|
_imageClone?.Dispose();
|
||||||
|
_imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null);
|
||||||
|
return _imageClone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,6 @@ using log4net;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
@ -91,9 +90,9 @@ namespace GreenshotPlugin.Core {
|
||||||
{
|
{
|
||||||
if (responseStream != null)
|
if (responseStream != null)
|
||||||
{
|
{
|
||||||
using (Image image = Image.FromStream(responseStream))
|
using (Image image = ImageHelper.FromStream(responseStream))
|
||||||
{
|
{
|
||||||
return (image.Height > 16 && image.Width > 16) ? new Bitmap(image, 16, 16) : new Bitmap(image);
|
return image.Height > 16 && image.Width > 16 ? new Bitmap(image, 16, 16) : new Bitmap(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,38 +129,55 @@ namespace GreenshotPlugin.Core {
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url">Of an image</param>
|
/// <param name="url">Of an image</param>
|
||||||
/// <returns>Bitmap</returns>
|
/// <returns>Bitmap</returns>
|
||||||
public static Image DownloadImage(string url) {
|
public static Image DownloadImage(string url)
|
||||||
try {
|
{
|
||||||
string content;
|
StringBuilder extensions = new StringBuilder();
|
||||||
using (MemoryStream memoryStream = GetAsMemoryStream(url)) {
|
foreach (var extension in ImageHelper.StreamConverters.Keys)
|
||||||
try {
|
{
|
||||||
using (Image image = Image.FromStream(memoryStream)) {
|
if (string.IsNullOrEmpty(extension))
|
||||||
return ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} catch (Exception) {
|
extensions.AppendFormat(@"\.{0}|", extension);
|
||||||
|
}
|
||||||
|
extensions.Length--;
|
||||||
|
|
||||||
|
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||||
|
var match = imageUrlRegex.Match(url);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var memoryStream = GetAsMemoryStream(url))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
// If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
|
// If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
|
||||||
using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) {
|
string content;
|
||||||
|
using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
|
||||||
|
{
|
||||||
content = streamReader.ReadLine();
|
content = streamReader.ReadLine();
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
Regex imageUrlRegex = new Regex(@"(http|https)://.*(\.png|\.gif|\.jpg|\.tiff|\.jpeg|\.bmp)");
|
|
||||||
Match match = imageUrlRegex.Match(content);
|
|
||||||
if (match.Success)
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream2 = GetAsMemoryStream(match.Value))
|
|
||||||
{
|
|
||||||
using (Image image = Image.FromStream(memoryStream2))
|
|
||||||
{
|
|
||||||
return ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
match = imageUrlRegex.Match(content);
|
||||||
|
if (!match.Success)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
using (var memoryStream2 = GetAsMemoryStream(match.Value))
|
||||||
|
{
|
||||||
|
return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
LOG.Error("Problem downloading the image from: " + url, e);
|
LOG.Error("Problem downloading the image from: " + url, e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -347,7 +363,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="webRequest">HttpWebRequest to write the multipart form data to</param>
|
/// <param name="webRequest">HttpWebRequest to write the multipart form data to</param>
|
||||||
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
||||||
public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary<string, object> postParameters) {
|
public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary<string, object> postParameters) {
|
||||||
string boundary = String.Format("----------{0:N}", Guid.NewGuid());
|
string boundary = string.Format("----------{0:N}", Guid.NewGuid());
|
||||||
webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
|
webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
|
||||||
using (Stream formDataStream = webRequest.GetRequestStream()) {
|
using (Stream formDataStream = webRequest.GetRequestStream()) {
|
||||||
WriteMultipartFormData(formDataStream, boundary, postParameters);
|
WriteMultipartFormData(formDataStream, boundary, postParameters);
|
||||||
|
@ -360,7 +376,7 @@ namespace GreenshotPlugin.Core {
|
||||||
/// <param name="response">HttpListenerResponse</param>
|
/// <param name="response">HttpListenerResponse</param>
|
||||||
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
/// <param name="postParameters">Parameters to include in the multipart form data</param>
|
||||||
public static void WriteMultipartFormData(HttpListenerResponse response, IDictionary<string, object> postParameters) {
|
public static void WriteMultipartFormData(HttpListenerResponse response, IDictionary<string, object> postParameters) {
|
||||||
string boundary = String.Format("----------{0:N}", Guid.NewGuid());
|
string boundary = string.Format("----------{0:N}", Guid.NewGuid());
|
||||||
response.ContentType = "multipart/form-data; boundary=" + boundary;
|
response.ContentType = "multipart/form-data; boundary=" + boundary;
|
||||||
WriteMultipartFormData(response.OutputStream, boundary, postParameters);
|
WriteMultipartFormData(response.OutputStream, boundary, postParameters);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@
|
||||||
<Compile Include="Core\CaptureHandler.cs" />
|
<Compile Include="Core\CaptureHandler.cs" />
|
||||||
<Compile Include="Core\EventDelay.cs" />
|
<Compile Include="Core\EventDelay.cs" />
|
||||||
<Compile Include="Core\FastBitmap.cs" />
|
<Compile Include="Core\FastBitmap.cs" />
|
||||||
|
<Compile Include="Core\Func.cs" />
|
||||||
|
<Compile Include="Core\IImage.cs" />
|
||||||
|
<Compile Include="Core\ImageWrapper.cs" />
|
||||||
<Compile Include="Core\OperatingSystemExtensions.cs" />
|
<Compile Include="Core\OperatingSystemExtensions.cs" />
|
||||||
<Compile Include="Core\WmInputLangChangeRequestFilter.cs" />
|
<Compile Include="Core\WmInputLangChangeRequestFilter.cs" />
|
||||||
<Compile Include="GlobalSuppressions.cs" />
|
<Compile Include="GlobalSuppressions.cs" />
|
||||||
|
|
|
@ -226,7 +226,7 @@ namespace Greenshot.Plugin
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
string UploadURL
|
string UploadUrl
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue