Code Quality changes and dependency updates.

This commit is contained in:
Robin 2019-12-18 08:47:28 +01:00
commit 6b6bcb99bb
123 changed files with 3092 additions and 3781 deletions

View file

@ -58,11 +58,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))"> <ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))">
<PackageReference Include="Nerdbank.GitVersioning" Version="3.0.26"> <PackageReference Include="Nerdbank.GitVersioning" Version="3.0.28">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19351-01" PrivateAssets="All"/> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" BeforeTargets="PostBuildEvent" Condition="'$(BuildingInsideVisualStudio)' == 'true' And $(MSBuildProjectName.Contains('Addon.')) And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo'))"> <Target Name="PostBuild" BeforeTargets="PostBuildEvent" Condition="'$(BuildingInsideVisualStudio)' == 'true' And $(MSBuildProjectName.Contains('Addon.')) And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo'))">

View file

@ -117,13 +117,11 @@ namespace Greenshot.Addon.Box
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this // TODO: Optimize this
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "box.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "box.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream); }
}
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -163,12 +161,10 @@ namespace Greenshot.Addon.Box
} }
if (url != null && _boxConfiguration.AfterUploadLinkToClipBoard) if (url != null && _boxConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(url);
clipboardAccessToken.SetAsUrl(url);
}
} }
return url; return url;
@ -206,58 +202,56 @@ namespace Greenshot.Addon.Box
oauthHttpBehaviour.OnHttpMessageHandlerCreated = httpMessageHandler => new OAuth2HttpMessageHandler(_oauth2Settings, oauthHttpBehaviour, httpMessageHandler); oauthHttpBehaviour.OnHttpMessageHandlerCreated = httpMessageHandler => new OAuth2HttpMessageHandler(_oauth2Settings, oauthHttpBehaviour, httpMessageHandler);
// TODO: See if the PostAsync<Bitmap> can be used? Or at least the HttpContentFactory? // TODO: See if the PostAsync<Bitmap> can be used? Or at least the HttpContentFactory?
using (var imageStream = new MemoryStream()) using var imageStream = new MemoryStream();
var multiPartContent = new MultipartFormDataContent();
var parentIdContent = new StringContent(_boxConfiguration.FolderId);
parentIdContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{ {
var multiPartContent = new MultipartFormDataContent(); Name = "\"parent_id\""
var parentIdContent = new StringContent(_boxConfiguration.FolderId); };
parentIdContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") multiPartContent.Add(parentIdContent);
surface.WriteToStream(imageStream, CoreConfiguration, _boxConfiguration);
imageStream.Position = 0;
BoxFile response;
using (var streamContent = new StreamContent(imageStream))
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); //"image/" + outputSettings.Format);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{ {
Name = "\"parent_id\"" Name = "\"file\"",
}; FileName = "\"" + filename + "\""
multiPartContent.Add(parentIdContent); }; // the extra quotes are important here
surface.WriteToStream(imageStream, CoreConfiguration, _boxConfiguration); multiPartContent.Add(streamContent);
imageStream.Position = 0;
BoxFile response; oauthHttpBehaviour.MakeCurrent();
using (var streamContent = new StreamContent(imageStream)) response = await UploadFileUri.PostAsync<BoxFile>(multiPartContent, cancellationToken).ConfigureAwait(false);
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); //"image/" + outputSettings.Format);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"file\"",
FileName = "\"" + filename + "\""
}; // the extra quotes are important here
multiPartContent.Add(streamContent);
oauthHttpBehaviour.MakeCurrent();
response = await UploadFileUri.PostAsync<BoxFile>(multiPartContent, cancellationToken).ConfigureAwait(false);
}
if (response == null)
{
return null;
}
if (_boxConfiguration.UseSharedLink)
{
if (response.SharedLink?.Url == null)
{
var uriForSharedLink = FilesUri.AppendSegments(response.Id);
var updateAccess = new
{
shared_link = new
{
access = "open"
}
};
oauthHttpBehaviour.MakeCurrent();
response = await uriForSharedLink.PostAsync<BoxFile>(updateAccess, cancellationToken).ConfigureAwait(false);
}
return response.SharedLink.Url;
}
return $"http://www.box.com/files/0/f/0/1/f_{response.Id}";
} }
if (response == null)
{
return null;
}
if (_boxConfiguration.UseSharedLink)
{
if (response.SharedLink?.Url == null)
{
var uriForSharedLink = FilesUri.AppendSegments(response.Id);
var updateAccess = new
{
shared_link = new
{
access = "open"
}
};
oauthHttpBehaviour.MakeCurrent();
response = await uriForSharedLink.PostAsync<BoxFile>(updateAccess, cancellationToken).ConfigureAwait(false);
}
return response.SharedLink.Url;
}
return $"http://www.box.com/files/0/f/0/1/f_{response.Id}";
} }
} }

View file

@ -123,12 +123,10 @@ namespace Greenshot.Addon.Dropbox
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this by caching // TODO: Optimize this by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Dropbox.gif")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Dropbox.gif");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -145,12 +143,10 @@ namespace Greenshot.Addon.Dropbox
exportInformation.Uri = uploadUrl; exportInformation.Uri = uploadUrl;
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
if (_dropboxPluginConfiguration.AfterUploadLinkToClipBoard) if (_dropboxPluginConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(uploadUrl);
clipboardAccessToken.SetAsUrl(uploadUrl);
}
} }
} }
_exportNotification.NotifyOfExport(this, exportInformation, surface); _exportNotification.NotifyOfExport(this, exportInformation, surface);
@ -166,30 +162,24 @@ namespace Greenshot.Addon.Dropbox
try try
{ {
var cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
using (var ownedPleaseWaitForm = _pleaseWaitFormFactory(cancellationTokenSource)) using var ownedPleaseWaitForm = _pleaseWaitFormFactory(cancellationTokenSource);
{ ownedPleaseWaitForm.Value.SetDetails("Dropbox", _dropboxLanguage.CommunicationWait);
ownedPleaseWaitForm.Value.SetDetails("Dropbox", _dropboxLanguage.CommunicationWait); ownedPleaseWaitForm.Value.Show();
ownedPleaseWaitForm.Value.Show(); try
try {
{ var filename = surfaceToUpload.GenerateFilename(CoreConfiguration, _dropboxPluginConfiguration);
var filename = surfaceToUpload.GenerateFilename(CoreConfiguration, _dropboxPluginConfiguration); using var imageStream = new MemoryStream();
using (var imageStream = new MemoryStream()) surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _dropboxPluginConfiguration);
{ imageStream.Position = 0;
surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _dropboxPluginConfiguration); using var streamContent = new StreamContent(imageStream);
imageStream.Position = 0; streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _dropboxPluginConfiguration));
using (var streamContent = new StreamContent(imageStream)) dropboxUrl = await UploadAsync(filename, streamContent, null, cancellationToken).ConfigureAwait(false);
{ }
streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _dropboxPluginConfiguration)); finally
dropboxUrl = await UploadAsync(filename, streamContent, null, cancellationToken).ConfigureAwait(false); {
} ownedPleaseWaitForm.Value.Close();
} }
} }
finally
{
ownedPleaseWaitForm.Value.Close();
}
}
}
catch (Exception e) catch (Exception e)
{ {
Log.Error().WriteLine(e); Log.Error().WriteLine(e);

View file

@ -89,12 +89,10 @@ namespace Greenshot.Addon.ExternalCommand
{ {
exportInformation.Uri = uriMatches[0].Groups[1].Value; exportInformation.Uri = uriMatches[0].Groups[1].Value;
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(exportInformation.Uri);
clipboardAccessToken.SetAsUrl(exportInformation.Uri); }
}
}
} }
if (_externalCommandDefinition.CommandBehavior.HasFlag(CommandBehaviors.DeleteOnExit)) if (_externalCommandDefinition.CommandBehavior.HasFlag(CommandBehaviors.DeleteOnExit))

View file

@ -19,6 +19,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CliWrap" Version="2.4.0" /> <PackageReference Include="CliWrap" Version="2.5.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -123,12 +123,10 @@ namespace Greenshot.Addon.Flickr
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this by caching // TODO: Optimize this by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "flickr.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "flickr.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -174,12 +172,10 @@ namespace Greenshot.Addon.Flickr
return null; return null;
} }
if (_flickrConfiguration.AfterUploadLinkToClipBoard) if (_flickrConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(uploadUrl);
clipboardAccessToken.SetAsUrl(uploadUrl);
}
} }
} }
@ -222,23 +218,21 @@ namespace Greenshot.Addon.Flickr
{ {
surfaceToUpload.WriteToStream(stream, CoreConfiguration, _flickrConfiguration); surfaceToUpload.WriteToStream(stream, CoreConfiguration, _flickrConfiguration);
stream.Position = 0; stream.Position = 0;
using (var streamContent = new StreamContent(stream)) using var streamContent = new StreamContent(stream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _flickrConfiguration));
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{ {
streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _flickrConfiguration)); Name = "\"photo\"",
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") FileName = "\"" + filename + "\""
{ };
Name = "\"photo\"", HttpBehaviour.Current.SetConfig(new HttpRequestMessageConfiguration
FileName = "\"" + filename + "\"" {
}; Properties = signedParameters
HttpBehaviour.Current.SetConfig(new HttpRequestMessageConfiguration });
{ var response = await FlickrUploadUri.PostAsync<XDocument>(streamContent, token).ConfigureAwait(false);
Properties = signedParameters photoId = (from element in response?.Root?.Elements() ?? Enumerable.Empty<XElement>()
}); where element.Name == "photoid"
var response = await FlickrUploadUri.PostAsync<XDocument>(streamContent, token).ConfigureAwait(false); select element.Value).FirstOrDefault();
photoId = (from element in response?.Root?.Elements() ?? Enumerable.Empty<XElement>()
where element.Name == "photoid"
select element.Value).FirstOrDefault();
}
} }
// Get Photo Info // Get Photo Info

View file

@ -101,13 +101,11 @@ namespace Greenshot.Addon.GooglePhotos
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this by caching // TODO: Optimize this by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "GooglePhotos.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "GooglePhotos.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream); }
}
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -144,12 +142,10 @@ namespace Greenshot.Addon.GooglePhotos
} }
if (url != null && _googlePhotosConfiguration.AfterUploadLinkToClipBoard) if (url != null && _googlePhotosConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(url);
clipboardAccessToken.SetAsUrl(url);
}
} }
return url; return url;
} }
@ -191,13 +187,11 @@ namespace Greenshot.Addon.GooglePhotos
{ {
surface.WriteToStream(imageStream, CoreConfiguration, _googlePhotosConfiguration); surface.WriteToStream(imageStream, CoreConfiguration, _googlePhotosConfiguration);
imageStream.Position = 0; imageStream.Position = 0;
using (var content = new StreamContent(imageStream)) using var content = new StreamContent(imageStream);
{ content.Headers.Add("Content-Type", surface.GenerateMimeType(CoreConfiguration, _googlePhotosConfiguration));
content.Headers.Add("Content-Type", surface.GenerateMimeType(CoreConfiguration, _googlePhotosConfiguration));
oAuthHttpBehaviour.MakeCurrent(); oAuthHttpBehaviour.MakeCurrent();
response = await uploadUri.PostAsync<string>(content, token).ConfigureAwait(true); response = await uploadUri.PostAsync<string>(content, token).ConfigureAwait(true);
}
} }
return ParseResponse(response); return ParseResponse(response);

View file

@ -104,17 +104,13 @@ namespace Greenshot.Addon.Imgur
localBehaviour.UploadProgress = percent => Execute.OnUIThread(() => progress.Report((int)(percent * 100))); localBehaviour.UploadProgress = percent => Execute.OnUIThread(() => progress.Report((int)(percent * 100)));
} }
using (var imageStream = new MemoryStream()) using var imageStream = new MemoryStream();
{ surfaceToUpload.WriteToStream(imageStream, _coreConfiguration, _imgurConfiguration);
surfaceToUpload.WriteToStream(imageStream, _coreConfiguration, _imgurConfiguration); imageStream.Position = 0;
imageStream.Position = 0; using var content = new StreamContent(imageStream);
using (var content = new StreamContent(imageStream)) content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(_coreConfiguration, _imgurConfiguration));
{ localBehaviour.MakeCurrent();
content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(_coreConfiguration, _imgurConfiguration)); return await uploadUri.PostAsync<ImgurImage>(content, token).ConfigureAwait(false);
localBehaviour.MakeCurrent();
return await uploadUri.PostAsync<ImgurImage>(content, token).ConfigureAwait(false);
}
}
} }
/// <summary> /// <summary>
@ -135,17 +131,13 @@ namespace Greenshot.Addon.Imgur
localBehaviour.UploadProgress = percent => Execute.OnUIThread(() => progress.Report((int) (percent * 100))); localBehaviour.UploadProgress = percent => Execute.OnUIThread(() => progress.Report((int) (percent * 100)));
} }
var oauthHttpBehaviour = OAuth2HttpBehaviourFactory.Create(oAuth2Settings, localBehaviour); var oauthHttpBehaviour = OAuth2HttpBehaviourFactory.Create(oAuth2Settings, localBehaviour);
using (var imageStream = new MemoryStream()) using var imageStream = new MemoryStream();
{ surfaceToUpload.WriteToStream(imageStream, _coreConfiguration, _imgurConfiguration);
surfaceToUpload.WriteToStream(imageStream, _coreConfiguration, _imgurConfiguration); imageStream.Position = 0;
imageStream.Position = 0; using var content = new StreamContent(imageStream);
using (var content = new StreamContent(imageStream)) content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(_coreConfiguration, _imgurConfiguration));
{ oauthHttpBehaviour.MakeCurrent();
content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(_coreConfiguration, _imgurConfiguration)); return await uploadUri.PostAsync<ImgurImage>(content, token).ConfigureAwait(false);
oauthHttpBehaviour.MakeCurrent();
return await uploadUri.PostAsync<ImgurImage>(content, token).ConfigureAwait(false);
}
}
} }
@ -187,27 +179,25 @@ namespace Greenshot.Addon.Imgur
{ {
var creditsUri = new Uri($"{_imgurConfiguration.ApiUrl}/credits.json"); var creditsUri = new Uri($"{_imgurConfiguration.ApiUrl}/credits.json");
Behaviour.MakeCurrent(); Behaviour.MakeCurrent();
using (var client = HttpClientFactory.Create(creditsUri)) using var client = HttpClientFactory.Create(creditsUri);
var response = await client.GetAsync(creditsUri, token).ConfigureAwait(false);
await response.HandleErrorAsync().ConfigureAwait(false);
var creditsJson = await response.GetAsAsync<dynamic>(token).ConfigureAwait(false);
if ((creditsJson != null) && creditsJson.ContainsKey("data"))
{ {
var response = await client.GetAsync(creditsUri, token).ConfigureAwait(false); dynamic data = creditsJson.data;
await response.HandleErrorAsync().ConfigureAwait(false); int credits = 0;
var creditsJson = await response.GetAsAsync<dynamic>(token).ConfigureAwait(false); if (data.ContainsKey("ClientRemaining"))
if ((creditsJson != null) && creditsJson.ContainsKey("data"))
{ {
dynamic data = creditsJson.data; credits = (int)data.ClientRemaining;
int credits = 0; Log.Debug().WriteLine("{0}={1}", "ClientRemaining", (int)data.ClientRemaining);
if (data.ContainsKey("ClientRemaining"))
{
credits = (int)data.ClientRemaining;
Log.Debug().WriteLine("{0}={1}", "ClientRemaining", (int)data.ClientRemaining);
}
if (data.ContainsKey("UserRemaining"))
{
credits = Math.Min(credits, (int)data.UserRemaining);
Log.Debug().WriteLine("{0}={1}", "UserRemaining", (int)data.UserRemaining);
}
_imgurConfiguration.Credits = credits;
} }
if (data.ContainsKey("UserRemaining"))
{
credits = Math.Min(credits, (int)data.UserRemaining);
Log.Debug().WriteLine("{0}={1}", "UserRemaining", (int)data.UserRemaining);
}
_imgurConfiguration.Credits = credits;
} }
} }
@ -224,17 +214,15 @@ namespace Greenshot.Addon.Imgur
Log.Debug().WriteLine("Retrieving Imgur info for {0} with url {1}", id, imageUri); Log.Debug().WriteLine("Retrieving Imgur info for {0} with url {1}", id, imageUri);
Behaviour.MakeCurrent(); Behaviour.MakeCurrent();
using (var client = HttpClientFactory.Create(imageUri)) using var client = HttpClientFactory.Create(imageUri);
var response = await client.GetAsync(imageUri, token).ConfigureAwait(false);
// retrieving image data seems to throw a 403 (Unauthorized) if it has been deleted
if ((response.StatusCode == HttpStatusCode.NotFound) || (response.StatusCode == HttpStatusCode.Redirect) || (response.StatusCode == HttpStatusCode.Unauthorized))
{ {
var response = await client.GetAsync(imageUri, token).ConfigureAwait(false); return null;
// retrieving image data seems to throw a 403 (Unauthorized) if it has been deleted
if ((response.StatusCode == HttpStatusCode.NotFound) || (response.StatusCode == HttpStatusCode.Redirect) || (response.StatusCode == HttpStatusCode.Unauthorized))
{
return null;
}
await response.HandleErrorAsync().ConfigureAwait(false);
return await response.GetAsAsync<ImgurImage>(token).ConfigureAwait(false);
} }
await response.HandleErrorAsync().ConfigureAwait(false);
return await response.GetAsAsync<ImgurImage>(token).ConfigureAwait(false);
} }
/// <summary> /// <summary>

View file

@ -81,12 +81,10 @@ namespace Greenshot.Addon.Imgur
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this, by caching // TODO: Optimize this, by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Imgur.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Imgur.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -128,10 +126,11 @@ namespace Greenshot.Addon.Imgur
{ {
// Create thumbnail // Create thumbnail
using (var tmpImage = surfaceToUpload.GetBitmapForExport()) using (var tmpImage = surfaceToUpload.GetBitmapForExport())
using (var thumbnail = tmpImage.CreateThumbnail(90, 90))
{ {
using var thumbnail = tmpImage.CreateThumbnail(90, 90);
imgurImage.Image = thumbnail; imgurImage.Image = thumbnail;
} }
if (_imgurConfiguration.AnonymousAccess && _imgurConfiguration.TrackHistory) if (_imgurConfiguration.AnonymousAccess && _imgurConfiguration.TrackHistory)
{ {
Log.Debug().WriteLine("Storing imgur upload for hash {0} and delete hash {1}", imgurImage.Data.Id, imgurImage.Data.Deletehash); Log.Debug().WriteLine("Storing imgur upload for hash {0} and delete hash {1}", imgurImage.Data.Id, imgurImage.Data.Deletehash);
@ -159,11 +158,9 @@ namespace Greenshot.Addon.Imgur
try try
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(uploadUrl.AbsoluteUri);
clipboardAccessToken.SetAsUrl(uploadUrl.AbsoluteUri);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -120,10 +120,8 @@ namespace Greenshot.Addon.Imgur.ViewModels
/// </summary> /// </summary>
public void ShowHistory() public void ShowHistory()
{ {
using (var imgurHistoryViewModel = ImgurHistoryViewModelFactory()) using var imgurHistoryViewModel = ImgurHistoryViewModelFactory();
{ WindowManager.ShowDialog(imgurHistoryViewModel.Value);
WindowManager.ShowDialog(imgurHistoryViewModel.Value);
}
} }
/// <summary> /// <summary>

View file

@ -177,11 +177,9 @@ namespace Greenshot.Addon.Imgur.ViewModels
/// </summary> /// </summary>
public void CopyToClipboard() public void CopyToClipboard()
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(SelectedImgur.Data.Link?.AbsoluteUri);
clipboardAccessToken.SetAsUrl(SelectedImgur.Data.Link?.AbsoluteUri);
}
} }
/// <summary> /// <summary>

View file

@ -392,7 +392,7 @@ namespace Greenshot.Addon.InternetExplorer
windowToCapture = InteropWindowQuery.GetForegroundWindow(); windowToCapture = InteropWindowQuery.GetForegroundWindow();
} }
// Show backgroundform after retrieving the active window.. // Show backgroundform after retrieving the active window..
var backgroundForm = new BackgroundForm("Internet Explorer", "Please wait while the page in Internet Explorer is captured..."); using var backgroundForm = new BackgroundForm("Internet Explorer", "Please wait while the page in Internet Explorer is captured...");
backgroundForm.Show(); backgroundForm.Show();
//BackgroundForm backgroundForm = BackgroundForm.ShowAndWait(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture)); //BackgroundForm backgroundForm = BackgroundForm.ShowAndWait(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture));
try try
@ -658,12 +658,10 @@ namespace Greenshot.Addon.InternetExplorer
// Loop over the frames and clear their source area so we don't see any artifacts // Loop over the frames and clear their source area so we don't see any artifacts
foreach (var frameDocument in documentContainer.Frames) foreach (var frameDocument in documentContainer.Frames)
{ {
using (var brush = new SolidBrush(clearColor)) using var brush = new SolidBrush(clearColor);
{ graphicsTarget.FillRectangle(brush, frameDocument.SourceRectangle);
graphicsTarget.FillRectangle(brush, frameDocument.SourceRectangle); }
}
}
// Loop over the frames and capture their content // Loop over the frames and capture their content
foreach (var frameDocument in documentContainer.Frames) foreach (var frameDocument in documentContainer.Frames)
{ {

View file

@ -22,7 +22,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dapplo.Log;
using Dapplo.Windows.Desktop; using Dapplo.Windows.Desktop;
using Microsoft.Win32; using Microsoft.Win32;
@ -31,8 +30,6 @@ namespace Greenshot.Addon.InternetExplorer {
/// Util code for Internet Explorer /// Util code for Internet Explorer
/// </summary> /// </summary>
public class InternetExplorerHelper { public class InternetExplorerHelper {
private static readonly LogSource Log = new LogSource();
// Internet explorer Registry key // Internet explorer Registry key
private const string IeKey = @"Software\Microsoft\Internet Explorer"; private const string IeKey = @"Software\Microsoft\Internet Explorer";

View file

@ -21,6 +21,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapplo.Jira" Version="0.9.2" /> <PackageReference Include="Dapplo.Jira" Version="0.9.2" />
<PackageReference Include="DynamicData" Version="6.13.13" /> <PackageReference Include="DynamicData" Version="6.14.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -91,7 +91,11 @@ namespace Greenshot.Addon.Jira
{ {
if (_jiraClient != null) if (_jiraClient != null)
{ {
Task.Run(async () => await LogoutAsync()).Wait(); Task.Run(async () =>
{
await LogoutAsync();
_issueTypeBitmapCache.Dispose();
}).Wait();
} }
FavIcon?.Dispose(); FavIcon?.Dispose();
} }
@ -251,14 +255,12 @@ namespace Greenshot.Addon.Jira
public async Task AttachAsync(string issueKey, ISurface surface, string filename = null, CancellationToken cancellationToken = default) public async Task AttachAsync(string issueKey, ISurface surface, string filename = null, CancellationToken cancellationToken = default)
{ {
await CheckCredentialsAsync(cancellationToken).ConfigureAwait(true); await CheckCredentialsAsync(cancellationToken).ConfigureAwait(true);
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ surface.WriteToStream(memoryStream, _coreConfiguration, _jiraConfiguration);
surface.WriteToStream(memoryStream, _coreConfiguration, _jiraConfiguration); memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.Seek(0, SeekOrigin.Begin); var contentType = surface.GenerateMimeType(_coreConfiguration, _jiraConfiguration);
var contentType = surface.GenerateMimeType(_coreConfiguration, _jiraConfiguration); await _jiraClient.Attachment.AttachAsync(issueKey, memoryStream, filename ?? surface.GenerateFilename(_coreConfiguration, _jiraConfiguration), contentType, cancellationToken).ConfigureAwait(false);
await _jiraClient.Attachment.AttachAsync(issueKey, memoryStream, filename ?? surface.GenerateFilename(_coreConfiguration, _jiraConfiguration), contentType, cancellationToken).ConfigureAwait(false); }
}
}
/// <summary> /// <summary>
/// Add a comment to the supplied issue /// Add a comment to the supplied issue

View file

@ -136,16 +136,12 @@ namespace Greenshot.Addon.Jira
} }
} }
if (displayIcon == null) if (displayIcon == null)
{ {
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "jira.svgz")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "jira.svgz");
{ using var gzStream = new GZipStream(bitmapStream, CompressionMode.Decompress);
using (var gzStream = new GZipStream(bitmapStream, CompressionMode.Decompress)) displayIcon = SvgBitmap.FromStream(gzStream);
{ //displayIcon = BitmapHelper.FromStream(bitmapStream);
displayIcon = SvgBitmap.FromStream(gzStream); }
}
//displayIcon = BitmapHelper.FromStream(bitmapStream);
}
}
return displayIcon; return displayIcon;
} }
} }
@ -192,43 +188,41 @@ namespace Greenshot.Addon.Jira
} }
} }
else else
{ {
// TODO: set filename // TODO: set filename
// _jiraViewModel.SetFilename(filename); // _jiraViewModel.SetFilename(filename);
using (var jiraViewModel = _jiraViewModelFactory()) using var jiraViewModel = _jiraViewModelFactory();
{ if (_windowManager.ShowDialog(jiraViewModel.Value) == true)
if (_windowManager.ShowDialog(jiraViewModel.Value) == true) {
{ try
try {
{ surface.UploadUrl = _jiraConnector.JiraBaseUri.AppendSegments("browse", jiraViewModel.Value.JiraIssue.Key).AbsoluteUri;
surface.UploadUrl = _jiraConnector.JiraBaseUri.AppendSegments("browse", jiraViewModel.Value.JiraIssue.Key).AbsoluteUri; // Run upload in the background
// Run upload in the background using (var ownedPleaseWaitForm = _pleaseWaitFormFactory())
using (var ownedPleaseWaitForm = _pleaseWaitFormFactory()) {
{ ownedPleaseWaitForm.Value.ShowAndWait(Description, _jiraLanguage.CommunicationWait,
ownedPleaseWaitForm.Value.ShowAndWait(Description, _jiraLanguage.CommunicationWait, async () =>
async () => {
{ await _jiraConnector.AttachAsync(jiraViewModel.Value.JiraIssue.Key, surface,
await _jiraConnector.AttachAsync(jiraViewModel.Value.JiraIssue.Key, surface, jiraViewModel.Value.Filename).ConfigureAwait(true);
jiraViewModel.Value.Filename).ConfigureAwait(true);
if (!string.IsNullOrEmpty(jiraViewModel.Value.Comment)) if (!string.IsNullOrEmpty(jiraViewModel.Value.Comment))
{ {
await _jiraConnector.AddCommentAsync(jiraViewModel.Value.JiraIssue.Key, await _jiraConnector.AddCommentAsync(jiraViewModel.Value.JiraIssue.Key,
jiraViewModel.Value.Comment).ConfigureAwait(true); jiraViewModel.Value.Comment).ConfigureAwait(true);
} }
} }
); );
} }
Log.Debug().WriteLine("Uploaded to Jira {0}", jiraViewModel.Value.JiraIssue.Key); Log.Debug().WriteLine("Uploaded to Jira {0}", jiraViewModel.Value.JiraIssue.Key);
exportInformation.ExportMade = true; exportInformation.ExportMade = true;
exportInformation.Uri = surface.UploadUrl; exportInformation.Uri = surface.UploadUrl;
} }
catch (Exception e) catch (Exception e)
{ {
MessageBox.Show(_jiraLanguage.UploadFailure + " " + e.Message); MessageBox.Show(_jiraLanguage.UploadFailure + " " + e.Message);
} }
}
} }
} }
_exportNotification.NotifyOfExport(this, exportInformation, surface); _exportNotification.NotifyOfExport(this, exportInformation, surface);

View file

@ -52,19 +52,15 @@ namespace Greenshot.Addon.LegacyEditor.Controls
_selectedColor = value; _selectedColor = value;
if (Image != null) if (Image != null)
{ {
using (var brush = value != Color.Transparent ? new SolidBrush(value) : (Brush) new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray)) using var brush = value != Color.Transparent ? new SolidBrush(value) : (Brush) new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray);
{ using var graphics = Graphics.FromImage(Image);
using (var graphics = Graphics.FromImage(Image)) int verticalOffset = Image.Height / 3;
{ int horizontalOffset = (Image.Width / 3) / 2;
int verticalOffset = Image.Height / 3; int width = Image.Width - (Image.Width / 3);
int horizontalOffset = (Image.Width / 3) / 2; int height = (Image.Height / 3) / 2;
int width = Image.Width - (Image.Width / 3); graphics.FillRectangle(brush, new Rectangle(horizontalOffset, verticalOffset, width, height));
int height = (Image.Height / 3) / 2; }
graphics.FillRectangle(brush, new Rectangle(horizontalOffset, verticalOffset, width, height));
}
}
}
Invalidate(); Invalidate();
} }
} }
@ -77,24 +73,22 @@ namespace Greenshot.Addon.LegacyEditor.Controls
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
private void ColorButtonClick(object sender, EventArgs e) private void ColorButtonClick(object sender, EventArgs e)
{ {
using (var ownedColorDialog = _colorDialogFactory()) using var ownedColorDialog = _colorDialogFactory();
var colorDialog = ownedColorDialog.Value;
colorDialog.Color = SelectedColor;
// Using the parent to make sure the dialog doesn't show on another window
colorDialog.ShowDialog(Parent.Parent);
if (colorDialog.DialogResult == DialogResult.Cancel)
{ {
var colorDialog = ownedColorDialog.Value; return;
colorDialog.Color = SelectedColor;
// Using the parent to make sure the dialog doesn't show on another window
colorDialog.ShowDialog(Parent.Parent);
if (colorDialog.DialogResult == DialogResult.Cancel)
{
return;
}
if (colorDialog.Color.Equals(SelectedColor))
{
return;
}
SelectedColor = colorDialog.Color;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
} }
} if (colorDialog.Color.Equals(SelectedColor))
{
return;
}
SelectedColor = colorDialog.Color;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor"));
}
} }
} }

View file

@ -39,7 +39,8 @@ namespace Greenshot.Addon.LegacyEditor.Controls {
if (components != null) { if (components != null) {
components.Dispose(); components.Dispose();
} }
} _toolTip.Dispose();
}
base.Dispose(disposing); base.Dispose(disposing);
} }

View file

@ -51,52 +51,42 @@ namespace Greenshot.Addon.LegacyEditor.Controls
} }
var graphics = e.Graphics; var graphics = e.Graphics;
var dropDownRect = e.ArrowRectangle; var dropDownRect = e.ArrowRectangle;
using (var brush = new SolidBrush(e.ArrowColor)) using var brush = new SolidBrush(e.ArrowColor);
int halfHeight = e.ArrowRectangle.Height / 2;
int halfWidth = e.ArrowRectangle.Width / 2;
var middle = new Point(dropDownRect.Left + halfWidth, dropDownRect.Top + halfHeight);
Point[] arrow;
int verticalArrowStart = middle.Y - halfHeight / 3;
int verticalArrowEnd = middle.Y + halfHeight / 3;
int horizontalArrowStart = middle.X - halfWidth;
int horizontalArrowEnd = middle.X + halfWidth;
arrow = e.Direction switch
{ {
int halfHeight = e.ArrowRectangle.Height / 2; ArrowDirection.Up => new[]
int halfWidth = e.ArrowRectangle.Width / 2;
var middle = new Point(dropDownRect.Left + halfWidth, dropDownRect.Top + halfHeight);
Point[] arrow;
int verticalArrowStart = middle.Y - halfHeight / 3;
int verticalArrowEnd = middle.Y + halfHeight / 3;
int horizontalArrowStart = middle.X - halfWidth;
int horizontalArrowEnd = middle.X + halfWidth;
switch (e.Direction)
{ {
case ArrowDirection.Up: new Point(horizontalArrowStart, verticalArrowEnd),
new Point(horizontalArrowEnd, verticalArrowEnd), new Point(middle.X, verticalArrowStart)
arrow = new[] { },
new Point(horizontalArrowStart, verticalArrowEnd), ArrowDirection.Left => new[]
new Point(horizontalArrowEnd, verticalArrowEnd), {
new Point(middle.X, verticalArrowStart)}; new Point(horizontalArrowEnd, verticalArrowStart),
new Point(horizontalArrowEnd, verticalArrowEnd), new Point(horizontalArrowStart, middle.Y)
break; },
case ArrowDirection.Left: ArrowDirection.Right => new[]
arrow = new[] { {
new Point(horizontalArrowEnd, verticalArrowStart), new Point(horizontalArrowStart, verticalArrowStart),
new Point(horizontalArrowEnd, verticalArrowEnd), new Point(horizontalArrowStart, verticalArrowEnd), new Point(horizontalArrowEnd, middle.Y)
new Point(horizontalArrowStart, middle.Y)}; },
_ => new[]
break; {
case ArrowDirection.Right: new Point(horizontalArrowStart, verticalArrowStart),
arrow = new[] { new Point(horizontalArrowEnd, verticalArrowStart), new Point(middle.X, verticalArrowEnd)
new Point(horizontalArrowStart, verticalArrowStart),
new Point(horizontalArrowStart, verticalArrowEnd),
new Point(horizontalArrowEnd, middle.Y)};
break;
default:
arrow = new[] {
new Point(horizontalArrowStart, verticalArrowStart),
new Point(horizontalArrowEnd, verticalArrowStart),
new Point(middle.X, verticalArrowEnd) };
break;
} }
graphics.FillPolygon(brush, arrow); };
} graphics.FillPolygon(brush, arrow);
} }
} }
} }

View file

@ -116,17 +116,12 @@ namespace Greenshot.Addon.LegacyEditor.Controls
/// <param name="bounds"></param> /// <param name="bounds"></param>
/// <param name="text"></param> /// <param name="text"></param>
private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text)
{ {
using (var font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel)) using var font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel);
{ // Make sure the text is visible by centering it in the line
// Make sure the text is visible by centering it in the line using var stringFormat = new StringFormat {LineAlignment = StringAlignment.Center};
using (var stringFormat = new StringFormat()) graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat);
{ }
stringFormat.LineAlignment = StringAlignment.Center;
graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat);
}
}
}
private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
{ {

View file

@ -39,7 +39,7 @@ namespace Greenshot.Addon.LegacyEditor.Controls
{ {
private const int VkEsc = 27; private const int VkEsc = 27;
private readonly IBitmapWithNativeSupport _image; private readonly IBitmapWithNativeSupport _image;
private Cursor _cursor; private readonly Cursor _cursor;
private bool _dragging; private bool _dragging;
private MovableShowColorForm _movableShowColorForm; private MovableShowColorForm _movableShowColorForm;
@ -87,16 +87,14 @@ namespace Greenshot.Addon.LegacyEditor.Controls
/// <param name="hotspotY">Hotspot Y coordinate</param> /// <param name="hotspotY">Hotspot Y coordinate</param>
/// <returns>Cursor</returns> /// <returns>Cursor</returns>
private static Cursor CreateCursor(IBitmapWithNativeSupport bitmap, int hotspotX, int hotspotY) private static Cursor CreateCursor(IBitmapWithNativeSupport bitmap, int hotspotX, int hotspotY)
{ {
using (var iconHandle = new SafeIconHandle(bitmap.NativeBitmap.GetHicon())) using var iconHandle = new SafeIconHandle(bitmap.NativeBitmap.GetHicon());
{ NativeIconMethods.GetIconInfo(iconHandle, out var iconInfo);
NativeIconMethods.GetIconInfo(iconHandle, out var iconInfo); iconInfo.Hotspot = new NativePoint(hotspotX, hotspotY);
iconInfo.Hotspot = new NativePoint(hotspotX, hotspotY); iconInfo.IsIcon = false;
iconInfo.IsIcon = false; var icon = NativeIconMethods.CreateIconIndirect(ref iconInfo);
var icon = NativeIconMethods.CreateIconIndirect(ref iconInfo); return new Cursor(icon);
return new Cursor(icon); }
}
}
/// <summary> /// <summary>
/// This Dispose is called from the Dispose and the Destructor. /// This Dispose is called from the Dispose and the Destructor.
@ -106,15 +104,12 @@ namespace Greenshot.Addon.LegacyEditor.Controls
{ {
if (disposing) if (disposing)
{ {
if (_cursor != null) _cursor.Dispose();
{
_cursor.Dispose();
}
_movableShowColorForm?.Dispose(); _movableShowColorForm?.Dispose();
_image.Dispose();
} }
_movableShowColorForm = null; _movableShowColorForm = null;
_cursor = null; base.Dispose(disposing);
base.Dispose(disposing);
} }
/// <summary> /// <summary>

View file

@ -60,14 +60,12 @@ namespace Greenshot.Addon.LegacyEditor.Controls
} }
if (Image != null) if (Image != null)
{ {
using (var graphics = Graphics.FromImage(Image)) using var graphics = Graphics.FromImage(Image);
{ int quarterSize = Image.Height / 4;
int quarterSize = Image.Height / 4; var colorArea = new Rectangle(0, Image.Height - quarterSize, Image.Width, quarterSize);
var colorArea = new Rectangle(0, Image.Height - quarterSize, Image.Width, quarterSize); graphics.FillRectangle(brush, colorArea);
graphics.FillRectangle(brush, colorArea); }
}
}
// cleanup GDI Object // cleanup GDI Object
brush.Dispose(); brush.Dispose();
@ -84,7 +82,7 @@ namespace Greenshot.Addon.LegacyEditor.Controls
private void ColorButtonClick(object sender, EventArgs e) private void ColorButtonClick(object sender, EventArgs e)
{ {
var colorDialog = new ColorDialog(_editorConfiguration, _greenshotLanguage) using var colorDialog = new ColorDialog(_editorConfiguration, _greenshotLanguage)
{ {
Color = SelectedColor Color = SelectedColor
}; };

View file

@ -99,11 +99,8 @@ namespace Greenshot.Addon.LegacyEditor.Drawing.Adorners
var targetGraphics = paintEventArgs.Graphics; var targetGraphics = paintEventArgs.Graphics;
var bounds = Bounds; var bounds = Bounds;
using (var brush = new SolidBrush(_color)) using var brush = new SolidBrush(_color);
{ targetGraphics.FillRectangle(brush, bounds.X, bounds.Y, bounds.Width, bounds.Height);
targetGraphics.FillRectangle(brush, bounds.X, bounds.Y, bounds.Width, bounds.Height);
}
} }
/// <summary> /// <summary>

View file

@ -57,21 +57,14 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
return NativeRect.Empty; return NativeRect.Empty;
} }
using (var pen = new Pen(Color.White)) using var pen = new Pen(Color.White) {Width = lineThickness};
{ SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldTypes.ARROWHEADS), pen);
pen.Width = lineThickness; using var path = new GraphicsPath();
SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldTypes.ARROWHEADS), pen); path.AddLine(Left, Top, Left + Width, Top + Height);
using (var path = new GraphicsPath()) using var matrix = new Matrix();
{ NativeRectFloat drawingBounds = path.GetBounds(matrix, pen);
path.AddLine(Left, Top, Left + Width, Top + Height); return drawingBounds.Inflate(2, 2).Round();
using (var matrix = new Matrix()) }
{
NativeRectFloat drawingBounds = path.GetBounds(matrix, pen);
return drawingBounds.Inflate(2, 2).Round();
}
}
}
}
} }
/// <summary> /// <summary>
@ -109,28 +102,25 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var steps = 5; var steps = 5;
var currentStep = 1; var currentStep = 1;
while (currentStep <= steps) while (currentStep <= steps)
{ {
using (var shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness)) using var shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
{ SetArrowHeads(heads, shadowCapPen);
SetArrowHeads(heads, shadowCapPen);
graphics.DrawLine(shadowCapPen, graphics.DrawLine(shadowCapPen,
Left + currentStep, Left + currentStep,
Top + currentStep, Top + currentStep,
Left + currentStep + Width, Left + currentStep + Width,
Top + currentStep + Height); Top + currentStep + Height);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
} }
}
} }
using (var pen = new Pen(lineColor, lineThickness))
{ using var pen = new Pen(lineColor, lineThickness);
SetArrowHeads(heads, pen); SetArrowHeads(heads, pen);
graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
} }
}
} }
} }
@ -150,18 +140,13 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS) + 10; var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS) + 10;
if (lineThickness > 0) if (lineThickness > 0)
{ {
using (var pen = new Pen(Color.White)) using var pen = new Pen(Color.White) {Width = lineThickness};
{ SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldTypes.ARROWHEADS), pen);
pen.Width = lineThickness; using var path = new GraphicsPath();
SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldTypes.ARROWHEADS), pen); path.AddLine(Left, Top, Left + Width, Top + Height);
using (var path = new GraphicsPath()) return path.IsOutlineVisible(x, y, pen);
{ }
path.AddLine(Left, Top, Left + Width, Top + Height);
return path.IsOutlineVisible(x, y, pen);
}
}
}
return false; return false;
} }
} }

View file

@ -109,14 +109,12 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
Log.Debug().WriteLine("Rotating element with {0} degrees.", rotateAngle); Log.Debug().WriteLine("Rotating element with {0} degrees.", rotateAngle);
DisposeShadow(); DisposeShadow();
using (var tmpMatrix = new Matrix()) using var tmpMatrix = new Matrix();
{ using (_bitmap)
using (_bitmap) {
{ _bitmap = _bitmap.ApplyEffect(new RotateEffect(rotateAngle), tmpMatrix);
_bitmap = _bitmap.ApplyEffect(new RotateEffect(rotateAngle), tmpMatrix); }
} }
}
}
base.Transform(matrix); base.Transform(matrix);
} }
@ -225,12 +223,10 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
private void CheckShadow(bool shadow) private void CheckShadow(bool shadow)
{ {
if (shadow && _shadowBitmap == null) if (shadow && _shadowBitmap == null)
{ {
using (var matrix = new Matrix()) using var matrix = new Matrix();
{ _shadowBitmap = _bitmap.ApplyEffect(new DropShadowEffect(), matrix);
_shadowBitmap = _bitmap.ApplyEffect(new DropShadowEffect(), matrix); }
}
}
} }
/// <summary> /// <summary>

View file

@ -79,23 +79,22 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
return; return;
} }
using (Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)))
{
var cropRectangle = new NativeRect(Left, Top, Width, Height).Normalize();
var selectionRect = new NativeRect(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1);
DrawSelectionBorder(g, selectionRect); using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100));
var cropRectangle = new NativeRect(Left, Top, Width, Height).Normalize();
var selectionRect = new NativeRect(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1);
// top DrawSelectionBorder(g, selectionRect);
g.FillRectangle(cropBrush, new NativeRect(0, 0, _parent.Width, cropRectangle.Top));
// left // top
g.FillRectangle(cropBrush, new NativeRect(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); g.FillRectangle(cropBrush, new NativeRect(0, 0, _parent.Width, cropRectangle.Top));
// right // left
g.FillRectangle(cropBrush, g.FillRectangle(cropBrush, new NativeRect(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height));
new NativeRect(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); // right
// bottom g.FillRectangle(cropBrush,
g.FillRectangle(cropBrush, new NativeRect(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height))); new NativeRect(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height));
} // bottom
} g.FillRectangle(cropBrush, new NativeRect(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height)));
}
} }
} }

View file

@ -75,12 +75,11 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
return; return;
} }
using (var fileCursor = new Cursor(filename))
{ using var fileCursor = new Cursor(filename);
Cursor = fileCursor; Cursor = fileCursor;
Log.Debug().WriteLine("Loaded file: " + filename + " with resolution: " + Height + "," + Width); Log.Debug().WriteLine("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
} }
}
protected override void OnDeserialized(StreamingContext streamingContext) protected override void OnDeserialized(StreamingContext streamingContext)
{ {

View file

@ -602,14 +602,14 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
} }
protected void DrawSelectionBorder(Graphics g, NativeRect rect) protected void DrawSelectionBorder(Graphics g, NativeRect rect)
{ {
using (var pen = new Pen(Color.MediumSeaGreen)) using var pen = new Pen(Color.MediumSeaGreen)
{ {
pen.DashPattern = new float[] {1, 2}; DashPattern = new float[] {1, 2},
pen.Width = 1; Width = 1
g.DrawRectangle(pen, rect); };
} g.DrawRectangle(pen, rect);
} }
public void ResizeTo(int width, int height) public void ResizeTo(int width, int height)

View file

@ -82,32 +82,28 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var steps = 5; var steps = 5;
var currentStep = lineVisible ? 1 : 0; var currentStep = lineVisible ? 1 : 0;
while (currentStep <= steps) while (currentStep <= steps)
{ {
using (var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) using var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))
{ {
shadowPen.Width = lineVisible ? lineThickness : 1; Width = lineVisible ? lineThickness : 1
var shadowRect = new NativeRect(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height).Normalize(); };
graphics.DrawEllipse(shadowPen, shadowRect); var shadowRect = new NativeRect(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height).Normalize();
currentStep++; graphics.DrawEllipse(shadowPen, shadowRect);
alpha = alpha - basealpha / steps; currentStep++;
} alpha = alpha - basealpha / steps;
} }
} }
//draw the original shape //draw the original shape
if (Colors.IsVisible(fillColor)) if (Colors.IsVisible(fillColor))
{ {
using (Brush brush = new SolidBrush(fillColor)) using Brush brush = new SolidBrush(fillColor);
{ graphics.FillEllipse(brush, rect);
graphics.FillEllipse(brush, rect); }
}
}
if (lineVisible) if (lineVisible)
{ {
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ graphics.DrawEllipse(pen, rect);
graphics.DrawEllipse(pen, rect); }
}
}
} }
public override bool Contains(int x, int y) public override bool Contains(int x, int y)
@ -151,16 +147,12 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
// check the rest of the lines // check the rest of the lines
if (lineThickness > 0) if (lineThickness > 0)
{ {
using (var pen = new Pen(Color.White, lineThickness)) using var pen = new Pen(Color.White, lineThickness);
{ using var path = new GraphicsPath();
using (var path = new GraphicsPath()) path.AddEllipse(rect);
{ return path.IsOutlineVisible(x, y, pen);
path.AddEllipse(rect); }
return path.IsOutlineVisible(x, y, pen);
}
}
}
return false; return false;
} }
} }

View file

@ -85,24 +85,20 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var steps = 5; var steps = 5;
var currentStep = lineVisible ? 1 : 0; var currentStep = lineVisible ? 1 : 0;
while (currentStep <= steps) while (currentStep <= steps)
{ {
using (var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness)) using var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
{ var shadowRect = new NativeRect(Left + currentStep, Top + currentStep, Width, Height).Normalize();
var shadowRect = new NativeRect(Left + currentStep, Top + currentStep, Width, Height).Normalize(); graphics.DrawRectangle(shadowPen, shadowRect);
graphics.DrawRectangle(shadowPen, shadowRect); currentStep++;
currentStep++; alpha = alpha - baseAlpha / steps;
alpha = alpha - baseAlpha / steps; }
}
}
} }
var rect = new NativeRect(Left, Top, Width, Height).Normalize(); var rect = new NativeRect(Left, Top, Width, Height).Normalize();
if (lineThickness > 0) if (lineThickness > 0)
{ {
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ graphics.DrawRectangle(pen, rect);
graphics.DrawRectangle(pen, rect); }
}
}
} }
} }
} }

View file

@ -57,59 +57,58 @@ namespace Greenshot.Addon.LegacyEditor.Drawing.Filters
{ {
pixelSize = rect.Height; pixelSize = rect.Height;
} }
using (var dest = FastBitmapFactory.CreateCloneOf(applyBitmap, area: rect))
using var dest = FastBitmapFactory.CreateCloneOf(applyBitmap, area: rect);
using (var src = FastBitmapFactory.Create(applyBitmap, rect))
{ {
using (var src = FastBitmapFactory.Create(applyBitmap, rect)) var halbPixelSize = pixelSize / 2;
// Create a list of x values
var xValues = new List<int>();
for (var x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize)
{ {
var halbPixelSize = pixelSize / 2; xValues.Add(x);
// Create a list of x values }
var xValues = new List<int>(); for (var y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize)
for (var x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize) {
{ Parallel.ForEach(xValues, x =>
xValues.Add(x); {
} // TODO: Use stackalloc, or byte[]?
for (var y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize) var colors = new List<Color>();
{ for (var yy = y; yy < y + pixelSize; yy++)
Parallel.ForEach(xValues, x => {
{ if (yy < src.Top || yy >= src.Bottom)
// TODO: Use stackalloc, or byte[]? {
var colors = new List<Color>(); continue;
for (var yy = y; yy < y + pixelSize; yy++) }
{ for (var xx = x; xx < x + pixelSize; xx++)
if (yy < src.Top || yy >= src.Bottom) {
{ if (xx < src.Left || xx >= src.Right)
continue; {
} continue;
for (var xx = x; xx < x + pixelSize; xx++) }
{ colors.Add(src.GetColorAt(xx, yy));
if (xx < src.Left || xx >= src.Right) }
{ }
continue; var currentAvgColor = Colors.Mix(colors);
} for (var yy = y; yy <= y + pixelSize; yy++)
colors.Add(src.GetColorAt(xx, yy)); {
} if (yy < src.Top || yy >= src.Bottom)
} {
var currentAvgColor = Colors.Mix(colors); continue;
for (var yy = y; yy <= y + pixelSize; yy++) }
{ for (var xx = x; xx <= x + pixelSize; xx++)
if (yy < src.Top || yy >= src.Bottom) {
{ if (xx < src.Left || xx >= src.Right)
continue; {
} continue;
for (var xx = x; xx <= x + pixelSize; xx++) }
{ dest.SetColorAt(xx, yy, ref currentAvgColor);
if (xx < src.Left || xx >= src.Right) }
{ }
continue; });
}
dest.SetColorAt(xx, yy, ref currentAvgColor);
}
}
});
}
} }
dest.DrawTo(graphics, rect.Location);
} }
dest.DrawTo(graphics, rect.Location);
} }
} }
} }

View file

@ -186,31 +186,29 @@ namespace Greenshot.Addon.LegacyEditor.Drawing {
int lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS);
var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR); var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR);
using (var pen = new Pen(lineColor)) { using var pen = new Pen(lineColor) {Width = lineThickness};
pen.Width = lineThickness; if (!(pen.Width > 0))
if (!(pen.Width > 0)) {
{ return;
return; }
} // Make sure the lines are nicely rounded
// Make sure the lines are nicely rounded pen.EndCap = LineCap.Round;
pen.EndCap = LineCap.Round; pen.StartCap = LineCap.Round;
pen.StartCap = LineCap.Round; pen.LineJoin = LineJoin.Round;
pen.LineJoin = LineJoin.Round; // Move to where we need to draw
// Move to where we need to draw graphics.TranslateTransform(Left, Top);
graphics.TranslateTransform(Left, Top); lock (_freehandPathLock)
lock (_freehandPathLock) {
{ if (_isRecalculated && Selected && renderMode == RenderMode.Edit)
if (_isRecalculated && Selected && renderMode == RenderMode.Edit) {
{ DrawSelectionBorder(graphics, pen, _freehandPath);
DrawSelectionBorder(graphics, pen, _freehandPath); }
} graphics.DrawPath(pen, _freehandPath);
graphics.DrawPath(pen, _freehandPath); }
}
// Move back, otherwise everything is shifted // Move back, otherwise everything is shifted
graphics.TranslateTransform(-Left,-Top); graphics.TranslateTransform(-Left,-Top);
} }
}
/// <summary> /// <summary>
/// Draw a selectionborder around the freehand path /// Draw a selectionborder around the freehand path
@ -218,20 +216,19 @@ namespace Greenshot.Addon.LegacyEditor.Drawing {
/// <param name="graphics">Graphics</param> /// <param name="graphics">Graphics</param>
/// <param name="linePen">Pen</param> /// <param name="linePen">Pen</param>
/// <param name="path">GraphicsPath</param> /// <param name="path">GraphicsPath</param>
protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) { protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path)
using (var selectionPen = (Pen) linePen.Clone()) { {
using (var selectionPath = (GraphicsPath)path.Clone()) { using var selectionPen = (Pen) linePen.Clone();
selectionPen.Width += 5; using var selectionPath = (GraphicsPath)path.Clone();
selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); selectionPen.Width += 5;
graphics.DrawPath(selectionPen, selectionPath); selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen);
selectionPath.Widen(selectionPen); graphics.DrawPath(selectionPen, selectionPath);
selectionPen.DashPattern = new float[]{2,2}; selectionPath.Widen(selectionPen);
selectionPen.Color = Color.LightSeaGreen; selectionPen.DashPattern = new float[]{2,2};
selectionPen.Width = 1; selectionPen.Color = Color.LightSeaGreen;
graphics.DrawPath(selectionPen, selectionPath); selectionPen.Width = 1;
} graphics.DrawPath(selectionPen, selectionPath);
} }
}
/// <summary> /// <summary>
/// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds...
@ -276,14 +273,12 @@ namespace Greenshot.Addon.LegacyEditor.Drawing {
bool returnValue = base.ClickableAt(x, y); bool returnValue = base.ClickableAt(x, y);
if (returnValue) { if (returnValue) {
int lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS); int lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS);
using (var pen = new Pen(Color.White)) { using var pen = new Pen(Color.White) {Width = lineThickness + 10};
pen.Width = lineThickness + 10; lock (_freehandPathLock)
lock (_freehandPathLock) {
{ returnValue = _freehandPath.IsOutlineVisible(x - Left, y - Top, pen);
returnValue = _freehandPath.IsOutlineVisible(x - Left, y - Top, pen);
}
} }
} }
return returnValue; return returnValue;
} }
} }

View file

@ -69,12 +69,11 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
return; return;
} }
using (var fileIcon = new Icon(filename))
{ using var fileIcon = new Icon(filename);
Icon = fileIcon; Icon = fileIcon;
Log.Debug().WriteLine("Loaded file: " + filename + " with resolution: " + Height + "," + Width); Log.Debug().WriteLine("Loaded file: " + filename + " with resolution: " + Height + "," + Width);
} }
}
protected override void OnDeserialized(StreamingContext streamingContext) protected override void OnDeserialized(StreamingContext streamingContext)
{ {

View file

@ -91,28 +91,24 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var steps = 5; var steps = 5;
var currentStep = 1; var currentStep = 1;
while (currentStep <= steps) while (currentStep <= steps)
{ {
using (var shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness)) using var shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness);
{ graphics.DrawLine(shadowCapPen,
graphics.DrawLine(shadowCapPen, Left + currentStep,
Left + currentStep, Top + currentStep,
Top + currentStep, Left + currentStep + Width,
Left + currentStep + Width, Top + currentStep + Height);
Top + currentStep + Height);
currentStep++; currentStep++;
#pragma warning disable IDE0054 // Use compound assignment #pragma warning disable IDE0054 // Use compound assignment
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
#pragma warning restore IDE0054 // Use compound assignment #pragma warning restore IDE0054 // Use compound assignment
} }
}
} }
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height);
graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); }
}
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -120,17 +116,12 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS) + 5; var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS) + 5;
if (lineThickness > 0) if (lineThickness > 0)
{ {
using (var pen = new Pen(Color.White)) using var pen = new Pen(Color.White) {Width = lineThickness};
{ using var path = new GraphicsPath();
pen.Width = lineThickness; path.AddLine(Left, Top, Left + Width, Top + Height);
using (var path = new GraphicsPath()) return path.IsOutlineVisible(x, y, pen);
{ }
path.AddLine(Left, Top, Left + Width, Top + Height);
return path.IsOutlineVisible(x, y, pen);
}
}
}
return false; return false;
} }

View file

@ -94,34 +94,33 @@ namespace Greenshot.Addon.LegacyEditor.Drawing {
int alpha = basealpha; int alpha = basealpha;
int steps = 5; int steps = 5;
int currentStep = lineVisible ? 1 : 0; int currentStep = lineVisible ? 1 : 0;
while (currentStep <= steps) { while (currentStep <= steps)
using (var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { {
shadowPen.Width = lineVisible ? lineThickness : 1; using var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) {Width = lineVisible ? lineThickness : 1};
var shadowRect = new NativeRect( var shadowRect = new NativeRect(
rect.Left + currentStep, rect.Left + currentStep,
rect.Top + currentStep, rect.Top + currentStep,
rect.Width, rect.Width,
rect.Height).Normalize(); rect.Height).Normalize();
graphics.DrawRectangle(shadowPen, shadowRect); graphics.DrawRectangle(shadowPen, shadowRect);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
} }
}
} }
if (Colors.IsVisible(fillColor)) { if (Colors.IsVisible(fillColor))
using (Brush brush = new SolidBrush(fillColor)) { {
graphics.FillRectangle(brush, rect); using Brush brush = new SolidBrush(fillColor);
} graphics.FillRectangle(brush, rect);
} }
graphics.SmoothingMode = SmoothingMode.HighSpeed; graphics.SmoothingMode = SmoothingMode.HighSpeed;
if (lineVisible) { if (lineVisible)
using (var pen = new Pen(lineColor, lineThickness)) { {
graphics.DrawRectangle(pen, rect); using var pen = new Pen(lineColor, lineThickness);
} graphics.DrawRectangle(pen, rect);
} }
} }
public override bool ClickableAt(int x, int y) { public override bool ClickableAt(int x, int y) {
@ -143,14 +142,13 @@ namespace Greenshot.Addon.LegacyEditor.Drawing {
} }
// check the rest of the lines // check the rest of the lines
if (lineThickness > 0) { if (lineThickness > 0)
using (var pen = new Pen(Color.White, lineThickness)) { {
using (var path = new GraphicsPath()) { using var pen = new Pen(Color.White, lineThickness);
path.AddRectangle(rect); using var path = new GraphicsPath();
return path.IsOutlineVisible(x, y, pen); path.AddRectangle(rect);
} return path.IsOutlineVisible(x, y, pen);
} }
}
return false; return false;
} }
} }

View file

@ -55,18 +55,14 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS); var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS);
var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR); var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR);
var shadow = GetFieldValueAsBool(FieldTypes.SHADOW); var shadow = GetFieldValueAsBool(FieldTypes.SHADOW);
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ var inflateValue = lineThickness + 2 + (shadow ? 6 : 0);
var inflateValue = lineThickness + 2 + (shadow ? 6 : 0); using var tailPath = CreateTail();
using (var tailPath = CreateTail()) NativeRectFloat tailBounds = tailPath.GetBounds(new Matrix(), pen);
{ var bounds = new NativeRect(Left, Top, Width, Height).Normalize();
NativeRectFloat tailBounds = tailPath.GetBounds(new Matrix(), pen);
var bounds = new NativeRect(Left, Top, Width, Height).Normalize();
return tailBounds.Round().Union(bounds).Inflate(inflateValue, inflateValue); return tailBounds.Round().Union(bounds).Inflate(inflateValue, inflateValue);
} }
}
}
return NativeRect.Empty; return NativeRect.Empty;
} }
} }
@ -237,37 +233,33 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var alpha = basealpha; var alpha = basealpha;
const int steps = 5; const int steps = 5;
var currentStep = lineVisible ? 1 : 0; var currentStep = lineVisible ? 1 : 0;
using (var shadowMatrix = new Matrix()) using var shadowMatrix = new Matrix();
using (var bubbleClone = (GraphicsPath) bubble.Clone()) using var bubbleClone = (GraphicsPath) bubble.Clone();
using (var tailClone = (GraphicsPath) tail.Clone()) using var tailClone = (GraphicsPath) tail.Clone();
{ shadowMatrix.Translate(1, 1);
shadowMatrix.Translate(1, 1); while (currentStep <= steps)
while (currentStep <= steps) {
{ using (var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)))
using (var shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) {
{ shadowPen.Width = lineVisible ? lineThickness : 1;
shadowPen.Width = lineVisible ? lineThickness : 1; tailClone.Transform(shadowMatrix);
tailClone.Transform(shadowMatrix); graphics.DrawPath(shadowPen, tailClone);
graphics.DrawPath(shadowPen, tailClone); bubbleClone.Transform(shadowMatrix);
bubbleClone.Transform(shadowMatrix); graphics.DrawPath(shadowPen, bubbleClone);
graphics.DrawPath(shadowPen, bubbleClone); }
} currentStep++;
currentStep++; alpha = alpha - basealpha / steps;
alpha = alpha - basealpha / steps; }
} }
}
}
var state = graphics.Save(); var state = graphics.Save();
// draw the tail border where the bubble is not visible // draw the tail border where the bubble is not visible
using (var clipRegion = new Region(bubble)) using (var clipRegion = new Region(bubble))
{ {
graphics.SetClip(clipRegion, CombineMode.Exclude); graphics.SetClip(clipRegion, CombineMode.Exclude);
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ graphics.DrawPath(pen, tail);
graphics.DrawPath(pen, tail); }
}
}
graphics.Restore(state); graphics.Restore(state);
if (Colors.IsVisible(fillColor)) if (Colors.IsVisible(fillColor))
@ -289,12 +281,10 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
using (var clipRegion = new Region(tail)) using (var clipRegion = new Region(tail))
{ {
graphics.SetClip(clipRegion, CombineMode.Exclude); graphics.SetClip(clipRegion, CombineMode.Exclude);
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ //pen.EndCap = pen.StartCap = LineCap.Round;
//pen.EndCap = pen.StartCap = LineCap.Round; graphics.DrawPath(pen, bubble);
graphics.DrawPath(pen, bubble); }
}
}
graphics.Restore(state); graphics.Restore(state);
} }
@ -328,26 +318,23 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS); var lineThickness = GetFieldValueAsInt(FieldTypes.LINE_THICKNESS);
var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR); var lineColor = GetFieldValueAsColor(FieldTypes.LINE_COLOR);
using (var pen = new Pen(lineColor, lineThickness)) using var pen = new Pen(lineColor, lineThickness);
{ using (var bubblePath = CreateBubble(lineThickness))
using (var bubblePath = CreateBubble(lineThickness)) {
{ bubblePath.Widen(pen);
bubblePath.Widen(pen); if (bubblePath.IsVisible(clickedPoint))
if (bubblePath.IsVisible(clickedPoint)) {
{ return true;
return true; }
} }
}
using (var tailPath = CreateTail()) using var tailPath = CreateTail();
{ tailPath.Widen(pen);
tailPath.Widen(pen); if (tailPath.IsVisible(clickedPoint))
if (tailPath.IsVisible(clickedPoint)) {
{ return true;
return true; }
} }
}
}
}
return false; return false;
} }

View file

@ -195,14 +195,11 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false);
} }
using (var fam = new FontFamily(FontFamily.GenericSansSerif.Name))
{ using var fam = new FontFamily(FontFamily.GenericSansSerif.Name);
using (var font = new Font(fam, _fontSize, FontStyle.Bold, GraphicsUnit.Pixel)) using var font = new Font(fam, _fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
{ TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font);
TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); }
}
}
}
public override bool ClickableAt(int x, int y) public override bool ClickableAt(int x, int y)
{ {

View file

@ -257,6 +257,7 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
/// </summary> /// </summary>
/// <param name="coreConfiguration">ICoreConfiguration</param> /// <param name="coreConfiguration">ICoreConfiguration</param>
/// <param name="editorConfiguration">IEditorConfiguration</param> /// <param name="editorConfiguration">IEditorConfiguration</param>
/// <param name="editorLanguage">IEditorLanguage</param>
/// <param name="newBitmap">IBitmapWithNativeSupport</param> /// <param name="newBitmap">IBitmapWithNativeSupport</param>
public Surface(ICoreConfiguration coreConfiguration, IEditorConfiguration editorConfiguration, IEditorLanguage editorLanguage, IBitmapWithNativeSupport newBitmap) : this(coreConfiguration, editorConfiguration, editorLanguage) public Surface(ICoreConfiguration coreConfiguration, IEditorConfiguration editorConfiguration, IEditorLanguage editorLanguage, IBitmapWithNativeSupport newBitmap) : this(coreConfiguration, editorConfiguration, editorLanguage)
{ {
@ -563,7 +564,7 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
/// <param name="effect"></param> /// <param name="effect"></param>
public void ApplyBitmapEffect(IEffect effect) public void ApplyBitmapEffect(IEffect effect)
{ {
var backgroundForm = new BackgroundForm("Effect", "Please wait"); using var backgroundForm = new BackgroundForm("Effect", "Please wait");
backgroundForm.Show(); backgroundForm.Show();
Application.DoEvents(); Application.DoEvents();
try try
@ -1079,7 +1080,8 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing) // TODO: Check if we need to dispose _cursorContainer
if (disposing)
{ {
Count--; Count--;
Log.Debug().WriteLine("Disposing surface!"); Log.Debug().WriteLine("Disposing surface!");
@ -2035,14 +2037,12 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
var uri = new Uri(possibleUrl); var uri = new Uri(possibleUrl);
using (var image = uri.GetAsAsync<Bitmap>().Result) using var image = uri.GetAsAsync<Bitmap>().Result;
{ if (image != null)
if (image != null) {
{ AddImageContainer(BitmapWrapper.FromBitmap(image), mouse.X, mouse.Y);
AddImageContainer(BitmapWrapper.FromBitmap(image), mouse.X, mouse.Y); return;
return; }
}
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -2054,15 +2054,13 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
var uri = new Uri(possibleUrl); var uri = new Uri(possibleUrl);
using (var image = uri.GetAsAsync<Bitmap>().Result) using var image = uri.GetAsAsync<Bitmap>().Result;
{ if (image != null)
if (image != null) {
{ AddImageContainer(BitmapWrapper.FromBitmap(image), mouse.X, mouse.Y);
AddImageContainer(BitmapWrapper.FromBitmap(image), mouse.X, mouse.Y); return;
return; }
} }
}
}
} }
foreach (var image in ClipboardHelper.GetBitmaps(e.Data)) foreach (var image in ClipboardHelper.GetBitmaps(e.Data))

View file

@ -262,8 +262,8 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
}; };
_textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged); _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged);
_textBox.LostFocus += textBox_LostFocus; _textBox.LostFocus += TextBox_LostFocus;
_textBox.KeyDown += textBox_KeyDown; _textBox.KeyDown += TextBox_KeyDown;
} }
private void ShowTextBox() private void ShowTextBox()
@ -306,7 +306,10 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
_parent.Focus(); _parent.Focus();
_textBox?.Hide(); _textBox?.Hide();
_parent.KeysLocked = false; _parent.KeysLocked = false;
_parent.Controls.Remove(_textBox); if (_textBox != null)
{
_parent.Controls.Remove(_textBox);
}
} }
/// <summary> /// <summary>
@ -336,43 +339,41 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
var fontStyle = FontStyle.Regular; var fontStyle = FontStyle.Regular;
bool hasStyle = false; bool hasStyle = false;
using (var fontFamily = new FontFamily(fontFamilyName)) using var fontFamily = new FontFamily(fontFamilyName);
bool boldAvailable = fontFamily.IsStyleAvailable(FontStyle.Bold);
if (fontBold && boldAvailable)
{ {
bool boldAvailable = fontFamily.IsStyleAvailable(FontStyle.Bold); fontStyle |= FontStyle.Bold;
if (fontBold && boldAvailable) hasStyle = true;
{
fontStyle |= FontStyle.Bold;
hasStyle = true;
}
bool italicAvailable = fontFamily.IsStyleAvailable(FontStyle.Italic);
if (fontItalic && italicAvailable)
{
fontStyle |= FontStyle.Italic;
hasStyle = true;
}
if (!hasStyle)
{
bool regularAvailable = fontFamily.IsStyleAvailable(FontStyle.Regular);
if (regularAvailable)
{
fontStyle = FontStyle.Regular;
}
else
{
if (boldAvailable)
{
fontStyle = FontStyle.Bold;
}
else if (italicAvailable)
{
fontStyle = FontStyle.Italic;
}
}
}
return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel);
} }
bool italicAvailable = fontFamily.IsStyleAvailable(FontStyle.Italic);
if (fontItalic && italicAvailable)
{
fontStyle |= FontStyle.Italic;
hasStyle = true;
}
if (!hasStyle)
{
bool regularAvailable = fontFamily.IsStyleAvailable(FontStyle.Regular);
if (regularAvailable)
{
fontStyle = FontStyle.Regular;
}
else
{
if (boldAvailable)
{
fontStyle = FontStyle.Bold;
}
else if (italicAvailable)
{
fontStyle = FontStyle.Italic;
}
}
}
return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel);
} }
/// <summary> /// <summary>
@ -487,7 +488,7 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
_textBox.ForeColor = lineColor; _textBox.ForeColor = lineColor;
} }
private void textBox_KeyDown(object sender, KeyEventArgs e) private void TextBox_KeyDown(object sender, KeyEventArgs e)
{ {
// ESC and Enter/Return (w/o Shift) hide text editor // ESC and Enter/Return (w/o Shift) hide text editor
if (e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None)) if (e.KeyCode == Keys.Escape || ((e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter) && e.Modifiers == Keys.None))
@ -518,7 +519,7 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
} }
} }
private void textBox_LostFocus(object sender, EventArgs e) private void TextBox_LostFocus(object sender, EventArgs e)
{ {
// next change will be made undoable // next change will be made undoable
makeUndoable = true; makeUndoable = true;
@ -593,12 +594,11 @@ namespace Greenshot.Addon.LegacyEditor.Drawing
{ {
shadowRect = shadowRect.Inflate(-textOffset, -textOffset); shadowRect = shadowRect.Inflate(-textOffset, -textOffset);
} }
using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100)))
{ using Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100));
graphics.DrawString(text, font, fontBrush, (Rectangle)shadowRect, stringFormat); graphics.DrawString(text, font, fontBrush, (Rectangle)shadowRect, stringFormat);
currentStep++; currentStep++;
alpha = alpha - basealpha / steps; alpha = alpha - basealpha / steps;
}
} }
} }

View file

@ -66,13 +66,13 @@ namespace Greenshot.Addon.LegacyEditor
{ {
switch (fieldType.ValueType) switch (fieldType.ValueType)
{ {
case var intType when fieldType.ValueType == typeof(int): case var _ when fieldType.ValueType == typeof(int):
fieldValue = Convert.ToInt32(preferredValue); fieldValue = Convert.ToInt32(preferredValue);
break; break;
case var boolType when fieldType.ValueType == typeof(bool): case var _ when fieldType.ValueType == typeof(bool):
fieldValue = Convert.ToBoolean(preferredValue); fieldValue = Convert.ToBoolean(preferredValue);
break; break;
case var colorType when fieldType.ValueType == typeof(Color): case var _ when fieldType.ValueType == typeof(Color):
var color = Color.FromName(preferredStringValue); var color = Color.FromName(preferredStringValue);
fieldValue = color; fieldValue = color;
if (Color.Empty == color) if (Color.Empty == color)
@ -80,22 +80,22 @@ namespace Greenshot.Addon.LegacyEditor
fieldValue = Color.FromArgb(Convert.ToInt32(preferredValue)); fieldValue = Color.FromArgb(Convert.ToInt32(preferredValue));
} }
break; break;
case var alignType when fieldType.ValueType == typeof(StringAlignment): case var _ when fieldType.ValueType == typeof(StringAlignment):
fieldValue = Enum.Parse(typeof(StringAlignment), preferredStringValue, true); fieldValue = Enum.Parse(typeof(StringAlignment), preferredStringValue, true);
break; break;
case var fieldFlagType when fieldType.ValueType == typeof(FieldFlag): case var _ when fieldType.ValueType == typeof(FieldFlag):
fieldValue = Enum.Parse(typeof(FieldFlag), preferredStringValue, true); fieldValue = Enum.Parse(typeof(FieldFlag), preferredStringValue, true);
break; break;
case var preparedFilterType when fieldType.ValueType == typeof(PreparedFilter): case var _ when fieldType.ValueType == typeof(PreparedFilter):
fieldValue = Enum.Parse(typeof(PreparedFilter), preferredStringValue, true); fieldValue = Enum.Parse(typeof(PreparedFilter), preferredStringValue, true);
break; break;
case var arrowHeadCombinationType when fieldType.ValueType == typeof(ArrowContainer.ArrowHeadCombination): case var _ when fieldType.ValueType == typeof(ArrowContainer.ArrowHeadCombination):
fieldValue = Enum.Parse(typeof(ArrowContainer.ArrowHeadCombination), preferredStringValue, true); fieldValue = Enum.Parse(typeof(ArrowContainer.ArrowHeadCombination), preferredStringValue, true);
break; break;
case var floatType when fieldType.ValueType == typeof(float): case var _ when fieldType.ValueType == typeof(float):
fieldValue = Convert.ToSingle(preferredValue, CultureInfo.InvariantCulture); fieldValue = Convert.ToSingle(preferredValue, CultureInfo.InvariantCulture);
break; break;
case var doubleType when fieldType.ValueType == typeof(double): case var _ when fieldType.ValueType == typeof(double):
fieldValue = Convert.ToDouble(preferredValue, CultureInfo.InvariantCulture); fieldValue = Convert.ToDouble(preferredValue, CultureInfo.InvariantCulture);
break; break;
default: default:

View file

@ -41,8 +41,9 @@ namespace Greenshot.Addon.LegacyEditor.Forms {
components.Dispose(); components.Dispose();
} }
} }
// Make sure that clipboard changes are not longer processed. _destinationScaleHandler.Dispose();
_clipboardSubscription?.Dispose(); // Make sure that clipboard changes are not longer processed.
_clipboardSubscription?.Dispose();
// Remove all other stuff // Remove all other stuff
_disposables.Dispose(); _disposables.Dispose();
base.Dispose(disposing); base.Dispose(disposing);

View file

@ -350,24 +350,22 @@ namespace Greenshot.Addon.LegacyEditor.Forms
/// <param name="e"></param> /// <param name="e"></param>
private void PropertiesToolStrip_Paint(object sender, PaintEventArgs e) private void PropertiesToolStrip_Paint(object sender, PaintEventArgs e)
{ {
using (var cbBorderPen = new Pen(SystemColors.ActiveBorder)) using var cbBorderPen = new Pen(SystemColors.ActiveBorder);
// Loop over all items in the propertiesToolStrip
foreach (ToolStripItem item in propertiesToolStrip.Items)
{ {
// Loop over all items in the propertiesToolStrip // Only ToolStripComboBox that are visible
foreach (ToolStripItem item in propertiesToolStrip.Items) if (!(item is ToolStripComboBox cb) || !cb.Visible)
{ {
// Only ToolStripComboBox that are visible continue;
if (!(item is ToolStripComboBox cb) || !cb.Visible) }
{ // Calculate the rectangle
continue; if (cb.ComboBox != null)
} {
// Calculate the rectangle var r = new Rectangle(cb.ComboBox.Location.X - 1, cb.ComboBox.Location.Y - 1, cb.ComboBox.Size.Width + 1, cb.ComboBox.Size.Height + 1);
if (cb.ComboBox != null)
{
var r = new Rectangle(cb.ComboBox.Location.X - 1, cb.ComboBox.Location.Y - 1, cb.ComboBox.Size.Width + 1, cb.ComboBox.Size.Height + 1);
// Draw the rectangle // Draw the rectangle
e.Graphics.DrawRectangle(cbBorderPen, r); e.Graphics.DrawRectangle(cbBorderPen, r);
}
} }
} }
} }
@ -901,15 +899,14 @@ namespace Greenshot.Addon.LegacyEditor.Forms
{ {
return; return;
} }
using (Stream streamWrite = File.OpenWrite(saveFileDialog.FileName))
{ using Stream streamWrite = File.OpenWrite(saveFileDialog.FileName);
_surface.SaveElementsToStream(streamWrite); _surface.SaveElementsToStream(streamWrite);
}
} }
private void LoadElementsToolStripMenuItemClick(object sender, EventArgs e) private void LoadElementsToolStripMenuItemClick(object sender, EventArgs e)
{ {
var openFileDialog = new OpenFileDialog using var openFileDialog = new OpenFileDialog
{ {
Filter = "Greenshot templates (*.gst)|*.gst" Filter = "Greenshot templates (*.gst)|*.gst"
}; };
@ -1105,14 +1102,12 @@ namespace Greenshot.Addon.LegacyEditor.Forms
private void BtnResizeClick(object sender, EventArgs e) private void BtnResizeClick(object sender, EventArgs e)
{ {
var resizeEffect = new ResizeEffect(_surface.Screenshot.Width, _surface.Screenshot.Height, true); var resizeEffect = new ResizeEffect(_surface.Screenshot.Width, _surface.Screenshot.Height, true);
using (var resizeSettingsForm = _resizeSettingsFormFactory(resizeEffect)) using var resizeSettingsForm = _resizeSettingsFormFactory(resizeEffect);
var result = resizeSettingsForm.Value.ShowDialog(this);
if (result == DialogResult.OK)
{ {
var result = resizeSettingsForm.Value.ShowDialog(this); _surface.ApplyBitmapEffect(resizeEffect);
if (result == DialogResult.OK) UpdateUndoRedoSurfaceDependencies();
{
_surface.ApplyBitmapEffect(resizeEffect);
UpdateUndoRedoSurfaceDependencies();
}
} }
} }

View file

@ -17,7 +17,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.ComponentModel;
using Dapplo.Config.Language; using Dapplo.Config.Language;
namespace Greenshot.Addon.Lutim.Configuration namespace Greenshot.Addon.Lutim.Configuration

View file

@ -48,10 +48,8 @@ namespace Greenshot.Addon.Lutim.Entities
{ {
get get
{ {
using (var memoryStream = new MemoryStream(Convert.FromBase64String(ThumbBase64))) using var memoryStream = new MemoryStream(Convert.FromBase64String(ThumbBase64));
{ return Image.FromStream(memoryStream);
return Image.FromStream(memoryStream);
}
} }
} }

View file

@ -29,7 +29,6 @@ using Dapplo.HttpExtensions;
using Dapplo.Log; using Dapplo.Log;
using Greenshot.Addon.Lutim.Configuration; using Greenshot.Addon.Lutim.Configuration;
using Greenshot.Addon.Lutim.Entities; using Greenshot.Addon.Lutim.Entities;
using Greenshot.Addons.Core;
using Greenshot.Addons.Interfaces; using Greenshot.Addons.Interfaces;
namespace Greenshot.Addon.Lutim namespace Greenshot.Addon.Lutim
@ -41,12 +40,10 @@ namespace Greenshot.Addon.Lutim
{ {
private static readonly LogSource Log = new LogSource(); private static readonly LogSource Log = new LogSource();
private readonly ILutimConfiguration _lutimConfiguration; private readonly ILutimConfiguration _lutimConfiguration;
private readonly ICoreConfiguration _coreConfiguration;
public LutimApi(ILutimConfiguration lutimConfiguration, ICoreConfiguration coreConfiguration) public LutimApi(ILutimConfiguration lutimConfiguration)
{ {
_lutimConfiguration = lutimConfiguration; _lutimConfiguration = lutimConfiguration;
_coreConfiguration = coreConfiguration;
} }
/// <summary> /// <summary>
@ -87,13 +84,13 @@ namespace Greenshot.Addon.Lutim
} }
catch (ArgumentException) catch (ArgumentException)
{ {
Log.Info().WriteLine("Bad format of lutim history item for short {0}", key); Log.Info().WriteLine("Bad format of Lutim history item for short {0}", key);
_lutimConfiguration.LutimUploadHistory.Remove(key); _lutimConfiguration.LutimUploadHistory.Remove(key);
_lutimConfiguration.RuntimeLutimHistory.Remove(key); _lutimConfiguration.RuntimeLutimHistory.Remove(key);
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error().WriteLine(e, "Problem loading lutim history for short " + key); Log.Error().WriteLine(e, "Problem loading Lutim history for short " + key);
} }
} }
} }

View file

@ -84,12 +84,11 @@ namespace Greenshot.Addon.Lutim {
/// <inheritdoc /> /// <inheritdoc />
public override IBitmapWithNativeSupport DisplayIcon { public override IBitmapWithNativeSupport DisplayIcon {
get { get
{
// TODO: Optimize this by caching // TODO: Optimize this by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Lutim.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "Lutim.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -155,11 +154,9 @@ namespace Greenshot.Addon.Lutim {
} }
try try
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(uploadUrl);
clipboardAccessToken.SetAsUrl(uploadUrl);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -181,11 +181,9 @@ namespace Greenshot.Addon.Lutim.ViewModels
public void CopyToClipboard() public void CopyToClipboard()
{ {
// TODO: Build url // TODO: Build url
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(SelectedLutim.LutimInfo.Short);
clipboardAccessToken.SetAsUrl(SelectedLutim.LutimInfo.Short);
}
} }
/// <summary> /// <summary>

View file

@ -49,17 +49,18 @@ namespace Greenshot.Addon.Office.Destinations
/// <summary> /// <summary>
/// Constructor used for dependency wiring /// Constructor used for dependency wiring
/// </summary> /// </summary>
/// <param name="oneNoteExporter">OneNoteExporter</param>
/// <param name="coreConfiguration">ICoreConfiguration</param> /// <param name="coreConfiguration">ICoreConfiguration</param>
/// <param name="greenshotLanguage">IGreenshotLanguage</param> /// <param name="greenshotLanguage">IGreenshotLanguage</param>
/// <param name="exportNotification">ExportNotification</param> /// <param name="exportNotification">ExportNotification</param>
public OneNoteDestination( public OneNoteDestination(
OneNoteExporter oneNoteExporter, OneNoteExporter oneNoteExporter,
ICoreConfiguration coreConfiguration, ICoreConfiguration coreConfiguration,
IGreenshotLanguage greenshotLanguage, IGreenshotLanguage greenshotLanguage,
ExportNotification exportNotification ExportNotification exportNotification
) : base(coreConfiguration, greenshotLanguage) ) : base(coreConfiguration, greenshotLanguage)
{ {
this._oneNoteExporter = oneNoteExporter; _oneNoteExporter = oneNoteExporter;
_exportNotification = exportNotification; _exportNotification = exportNotification;
_exePath = PluginUtils.GetExePath("ONENOTE.EXE"); _exePath = PluginUtils.GetExePath("ONENOTE.EXE");
if (_exePath != null && !File.Exists(_exePath)) if (_exePath != null && !File.Exists(_exePath))
@ -71,6 +72,7 @@ namespace Greenshot.Addon.Office.Destinations
/// <summary> /// <summary>
/// Constructor used for dependency wiring, and being able to specify a page /// Constructor used for dependency wiring, and being able to specify a page
/// </summary> /// </summary>
/// <param name="oneNoteExporter">OneNoteExporter</param>
/// <param name="page">OneNotePage</param> /// <param name="page">OneNotePage</param>
/// <param name="coreConfiguration">ICoreConfiguration</param> /// <param name="coreConfiguration">ICoreConfiguration</param>
/// <param name="greenshotLanguage">IGreenshotLanguage</param> /// <param name="greenshotLanguage">IGreenshotLanguage</param>

View file

@ -49,10 +49,8 @@ namespace Greenshot.Addon.Office
private bool HasApplication(string applicationName) private bool HasApplication(string applicationName)
{ {
string registryPath = $@"{applicationName}\CLSID"; string registryPath = $@"{applicationName}\CLSID";
using (var registryKey = Registry.ClassesRoot.OpenSubKey(registryPath, false)) using var registryKey = Registry.ClassesRoot.OpenSubKey(registryPath, false);
{ return registryKey != null && Guid.TryParse(registryKey.GetValue(null) as string, out _);
return registryKey != null && Guid.TryParse(registryKey.GetValue(null) as string, out _);
}
} }
/// <summary> /// <summary>

View file

@ -82,24 +82,19 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns>IEnumerable with names of the workbooks</returns> /// <returns>IEnumerable with names of the workbooks</returns>
public static IEnumerable<string> GetWorkbooks() public static IEnumerable<string> GetWorkbooks()
{ {
using (var excelApplication = GetExcelApplication()) using var excelApplication = GetExcelApplication();
if ((excelApplication == null) || (excelApplication.ComObject == null))
{ {
if ((excelApplication == null) || (excelApplication.ComObject == null)) yield break;
}
using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks);
for (int i = 1; i <= workbooks.ComObject.Count; i++)
{
using var workbook = DisposableCom.Create(workbooks.ComObject[i]);
if (workbook != null)
{ {
yield break; yield return workbook.ComObject.Name;
}
using (var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks))
{
for (int i = 1; i <= workbooks.ComObject.Count; i++)
{
using (var workbook = DisposableCom.Create(workbooks.ComObject[i]))
{
if (workbook != null)
{
yield return workbook.ComObject.Name;
}
}
}
} }
} }
} }
@ -129,24 +124,19 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <param name="imageSize"></param> /// <param name="imageSize"></param>
public static void InsertIntoExistingWorkbook(string workbookName, string tmpFile, Size imageSize) public static void InsertIntoExistingWorkbook(string workbookName, string tmpFile, Size imageSize)
{ {
using (var excelApplication = GetExcelApplication()) using var excelApplication = GetExcelApplication();
if ((excelApplication == null) || (excelApplication.ComObject == null))
{ {
if ((excelApplication == null) || (excelApplication.ComObject == null)) return;
}
using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks);
for (int i = 1; i <= workbooks.ComObject.Count; i++)
{
using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject[i]);
if ((workbook != null) && workbook.ComObject.Name.StartsWith(workbookName))
{ {
return; InsertIntoExistingWorkbook(workbook, tmpFile, imageSize);
}
using (var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks))
{
for (int i = 1; i <= workbooks.ComObject.Count; i++)
{
using (var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject[i]))
{
if ((workbook != null) && workbook.ComObject.Name.StartsWith(workbookName))
{
InsertIntoExistingWorkbook(workbook, tmpFile, imageSize);
}
}
}
} }
} }
} }
@ -159,40 +149,33 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <param name="imageSize"></param> /// <param name="imageSize"></param>
private static void InsertIntoExistingWorkbook(IDisposableCom<_Workbook> workbook, string tmpFile, Size imageSize) private static void InsertIntoExistingWorkbook(IDisposableCom<_Workbook> workbook, string tmpFile, Size imageSize)
{ {
using (var workSheet = DisposableCom.Create(workbook.ComObject.ActiveSheet as Worksheet)) using var workSheet = DisposableCom.Create(workbook.ComObject.ActiveSheet as Worksheet);
if (workSheet == null)
{ {
if (workSheet == null) return;
{
return;
}
using (var shapes = DisposableCom.Create(workSheet.ComObject.Shapes))
{
if (shapes == null)
{
return;
}
using (var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, imageSize.Width, imageSize.Height)))
{
if (shape == null)
{
return;
}
shape.ComObject.Top = 40;
shape.ComObject.Left = 40;
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromTopLeft);
shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromTopLeft);
workbook.ComObject.Activate();
using (var application = DisposableCom.Create(workbook.ComObject.Application))
{
var excelWindow = InteropWindowFactory.CreateFor((IntPtr) application.ComObject.Hwnd);
excelWindow.ToForegroundAsync();
}
}
}
} }
using var shapes = DisposableCom.Create(workSheet.ComObject.Shapes);
if (shapes == null)
{
return;
}
using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, imageSize.Width, imageSize.Height));
if (shape == null)
{
return;
}
shape.ComObject.Top = 40;
shape.ComObject.Left = 40;
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromTopLeft);
shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromTopLeft);
workbook.ComObject.Activate();
using var application = DisposableCom.Create(workbook.ComObject.Application);
var excelWindow = InteropWindowFactory.CreateFor((IntPtr) application.ComObject.Hwnd);
excelWindow.ToForegroundAsync();
} }
/// <summary> /// <summary>
@ -202,22 +185,16 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <param name="imageSize"></param> /// <param name="imageSize"></param>
public static void InsertIntoNewWorkbook(string tmpFile, Size imageSize) public static void InsertIntoNewWorkbook(string tmpFile, Size imageSize)
{ {
using (var excelApplication = GetOrCreateExcelApplication()) using var excelApplication = GetOrCreateExcelApplication();
if (excelApplication == null)
{ {
if (excelApplication == null) return;
{
return;
}
excelApplication.ComObject.Visible = true;
using (var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks))
{
using (var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject.Add()))
{
InsertIntoExistingWorkbook(workbook, tmpFile, imageSize);
}
}
} }
excelApplication.ComObject.Visible = true;
using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks);
using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject.Add());
InsertIntoExistingWorkbook(workbook, tmpFile, imageSize);
} }
} }

View file

@ -57,22 +57,20 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns>bool true if export worked</returns> /// <returns>bool true if export worked</returns>
public bool ExportToNewPage(ISurface surfaceToUpload) public bool ExportToNewPage(ISurface surfaceToUpload)
{ {
using (var oneNoteApplication = GetOrCreateOneNoteApplication()) using var oneNoteApplication = GetOrCreateOneNoteApplication();
var newPage = new OneNotePage();
string unfiledNotesSectionId = GetSectionId(oneNoteApplication, SpecialLocation.slUnfiledNotesSection);
if (unfiledNotesSectionId == null)
{ {
var newPage = new OneNotePage(); return false;
string unfiledNotesSectionId = GetSectionId(oneNoteApplication, SpecialLocation.slUnfiledNotesSection);
if (unfiledNotesSectionId == null)
{
return false;
}
string pageId;
oneNoteApplication.ComObject.CreateNewPage(unfiledNotesSectionId, out pageId, NewPageStyle.npsDefault);
newPage.Id = pageId;
// Set the new name, this is automatically done in the export to page
newPage.Name = surfaceToUpload.CaptureDetails.Title;
return ExportToPage(oneNoteApplication, surfaceToUpload, newPage);
} }
string pageId;
oneNoteApplication.ComObject.CreateNewPage(unfiledNotesSectionId, out pageId, NewPageStyle.npsDefault);
newPage.Id = pageId;
// Set the new name, this is automatically done in the export to page
newPage.Name = surfaceToUpload.CaptureDetails.Title;
return ExportToPage(oneNoteApplication, surfaceToUpload, newPage);
} }
/// <summary> /// <summary>
@ -83,10 +81,8 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns>bool true if everything worked</returns> /// <returns>bool true if everything worked</returns>
public bool ExportToPage(ISurface surfaceToUpload, OneNotePage page) public bool ExportToPage(ISurface surfaceToUpload, OneNotePage page)
{ {
using (var oneNoteApplication = GetOrCreateOneNoteApplication()) using var oneNoteApplication = GetOrCreateOneNoteApplication();
{ return ExportToPage(oneNoteApplication, surfaceToUpload, page);
return ExportToPage(oneNoteApplication, surfaceToUpload, page);
}
} }
/// <summary> /// <summary>
@ -103,25 +99,23 @@ namespace Greenshot.Addon.Office.OfficeExport
return false; return false;
} }
using (var pngStream = new MemoryStream()) using var pngStream = new MemoryStream();
var pngOutputSettings = new SurfaceOutputSettings(_coreConfiguration, OutputFormats.png, 100, false);
ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
var base64String = Convert.ToBase64String(pngStream.GetBuffer());
var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Screenshot.Width, surfaceToUpload.Screenshot.Height);
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);
Log.Info().WriteLine("Sending XML: {0}", pageChangesXml);
oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false);
try
{ {
var pngOutputSettings = new SurfaceOutputSettings(_coreConfiguration, OutputFormats.png, 100, false); oneNoteApplication.ComObject.NavigateTo(page.Id, null, false);
ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings);
var base64String = Convert.ToBase64String(pngStream.GetBuffer());
var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Screenshot.Width, surfaceToUpload.Screenshot.Height);
var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name);
Log.Info().WriteLine("Sending XML: {0}", pageChangesXml);
oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false);
try
{
oneNoteApplication.ComObject.NavigateTo(page.Id, null, false);
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex, "Unable to navigate to the target page");
}
return true;
} }
catch (Exception ex)
{
Log.Warn().WriteLine(ex, "Unable to navigate to the target page");
}
return true;
} }
/// <summary> /// <summary>
@ -166,80 +160,78 @@ namespace Greenshot.Addon.Office.OfficeExport
var pages = new List<OneNotePage>(); var pages = new List<OneNotePage>();
try try
{ {
using (var oneNoteApplication = GetOrCreateOneNoteApplication()) using var oneNoteApplication = GetOrCreateOneNoteApplication();
if (oneNoteApplication != null)
{ {
if (oneNoteApplication != null) // ReSharper disable once RedundantAssignment
string notebookXml = "";
oneNoteApplication.ComObject.GetHierarchy("", HierarchyScope.hsPages, out notebookXml, XMLSchema.xs2010);
if (!string.IsNullOrEmpty(notebookXml))
{ {
// ReSharper disable once RedundantAssignment Log.Debug().WriteLine(notebookXml);
string notebookXml = ""; StringReader reader = null;
oneNoteApplication.ComObject.GetHierarchy("", HierarchyScope.hsPages, out notebookXml, XMLSchema.xs2010); try
if (!string.IsNullOrEmpty(notebookXml))
{ {
Log.Debug().WriteLine(notebookXml); reader = new StringReader(notebookXml);
StringReader reader = null; using var xmlReader = new XmlTextReader(reader);
try reader = null;
OneNoteSection currentSection = null;
OneNoteNotebook currentNotebook = null;
while (xmlReader.Read())
{ {
reader = new StringReader(notebookXml); if ("one:Notebook".Equals(xmlReader.Name))
using (var xmlReader = new XmlTextReader(reader))
{ {
reader = null; string id = xmlReader.GetAttribute("ID");
OneNoteSection currentSection = null; if ((id != null) && ((currentNotebook == null) || !id.Equals(currentNotebook.Id)))
OneNoteNotebook currentNotebook = null;
while (xmlReader.Read())
{ {
if ("one:Notebook".Equals(xmlReader.Name)) currentNotebook = new OneNoteNotebook
{ {
string id = xmlReader.GetAttribute("ID"); Id = xmlReader.GetAttribute("ID"),
if ((id != null) && ((currentNotebook == null) || !id.Equals(currentNotebook.Id))) Name = xmlReader.GetAttribute("name")
{ };
currentNotebook = new OneNoteNotebook();
currentNotebook.Id = xmlReader.GetAttribute("ID");
currentNotebook.Name = xmlReader.GetAttribute("name");
}
}
if ("one:Section".Equals(xmlReader.Name))
{
string id = xmlReader.GetAttribute("ID");
if ((id != null) && ((currentSection == null) || !id.Equals(currentSection.Id)))
{
currentSection = new OneNoteSection
{
Id = xmlReader.GetAttribute("ID"),
Name = xmlReader.GetAttribute("name"),
Parent = currentNotebook
};
}
}
if ("one:Page".Equals(xmlReader.Name))
{
// Skip deleted items
if ("true".Equals(xmlReader.GetAttribute("isInRecycleBin")))
{
continue;
}
var page = new OneNotePage
{
Parent = currentSection,
Name = xmlReader.GetAttribute("name"),
Id = xmlReader.GetAttribute("ID")
};
if ((page.Id == null) || (page.Name == null))
{
continue;
}
page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed"));
pages.Add(page);
}
} }
} }
} if ("one:Section".Equals(xmlReader.Name))
finally
{
if (reader != null)
{ {
reader.Dispose(); string id = xmlReader.GetAttribute("ID");
if (id != null && (currentSection == null || !id.Equals(currentSection.Id)))
{
currentSection = new OneNoteSection
{
Id = xmlReader.GetAttribute("ID"),
Name = xmlReader.GetAttribute("name"),
Parent = currentNotebook
};
}
} }
if ("one:Page".Equals(xmlReader.Name))
{
// Skip deleted items
if ("true".Equals(xmlReader.GetAttribute("isInRecycleBin")))
{
continue;
}
var page = new OneNotePage
{
Parent = currentSection,
Name = xmlReader.GetAttribute("name"),
Id = xmlReader.GetAttribute("ID")
};
if ((page.Id == null) || (page.Name == null))
{
continue;
}
page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed"));
pages.Add(page);
}
}
}
finally
{
if (reader != null)
{
reader.Dispose();
} }
} }
} }
@ -294,20 +286,18 @@ namespace Greenshot.Addon.Office.OfficeExport
try try
{ {
reader = new StringReader(notebookXml); reader = new StringReader(notebookXml);
using (var xmlReader = new XmlTextReader(reader)) using var xmlReader = new XmlTextReader(reader);
while (xmlReader.Read())
{ {
while (xmlReader.Read()) if (!"one:Section".Equals(xmlReader.Name))
{ {
if (!"one:Section".Equals(xmlReader.Name)) continue;
{ }
continue; string id = xmlReader.GetAttribute("ID");
} string path = xmlReader.GetAttribute("path");
string id = xmlReader.GetAttribute("ID"); if (unfiledNotesPath.Equals(path))
string path = xmlReader.GetAttribute("path"); {
if (unfiledNotesPath.Equals(path)) return id;
{
return id;
}
} }
} }
} }

View file

@ -86,100 +86,94 @@ namespace Greenshot.Addon.Office.OfficeExport
if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) if (_outlookVersion.Major >= (int)OfficeVersions.Office2013)
{ {
// Check inline "panel" for Outlook 2013 // Check inline "panel" for Outlook 2013
using (var activeExplorer = DisposableCom.Create((_Explorer)outlookApplication.ComObject.ActiveExplorer())) using var activeExplorer = DisposableCom.Create((_Explorer)outlookApplication.ComObject.ActiveExplorer());
// Only if we have one and if the capture is the one we selected
if ((activeExplorer != null) && activeExplorer.ComObject.Caption.StartsWith(inspectorCaption))
{ {
// Only if we have one and if the capture is the one we selected var untypedInlineResponse = activeExplorer.ComObject.ActiveInlineResponse;
if ((activeExplorer != null) && activeExplorer.ComObject.Caption.StartsWith(inspectorCaption)) using (DisposableCom.Create(untypedInlineResponse))
{ {
var untypedInlineResponse = activeExplorer.ComObject.ActiveInlineResponse; switch (untypedInlineResponse)
using (DisposableCom.Create(untypedInlineResponse))
{ {
switch (untypedInlineResponse) case MailItem mailItem:
{ if (!mailItem.Sent)
case MailItem mailItem: {
if (!mailItem.Sent) return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser))
{ {
return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName); return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName);
} }
break; }
case AppointmentItem appointmentItem: break;
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser))
{
return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName);
}
}
break;
}
} }
} }
} }
} }
using (var inspectors = DisposableCom.Create(outlookApplication.ComObject.Inspectors)) using var inspectors = DisposableCom.Create(outlookApplication.ComObject.Inspectors);
if ((inspectors == null) || (inspectors.ComObject.Count == 0))
{ {
if ((inspectors == null) || (inspectors.ComObject.Count == 0)) return false;
}
Log.Debug().WriteLine("Got {0} inspectors to check", inspectors.ComObject.Count);
for (int i = 1; i <= inspectors.ComObject.Count; i++)
{
using var inspector = DisposableCom.Create((_Inspector)inspectors.ComObject[i]);
string currentCaption = inspector.ComObject.Caption;
if (!currentCaption.StartsWith(inspectorCaption))
{ {
return false; continue;
} }
Log.Debug().WriteLine("Got {0} inspectors to check", inspectors.ComObject.Count);
for (int i = 1; i <= inspectors.ComObject.Count; i++)
{
using (var inspector = DisposableCom.Create((_Inspector)inspectors.ComObject[i]))
{
string currentCaption = inspector.ComObject.Caption;
if (!currentCaption.StartsWith(inspectorCaption))
{
continue;
}
var currentItemUntyped = inspector.ComObject.CurrentItem; var currentItemUntyped = inspector.ComObject.CurrentItem;
using (DisposableCom.Create(currentItemUntyped)) using (DisposableCom.Create(currentItemUntyped))
{ {
switch (currentItemUntyped) switch (currentItemUntyped)
{
case MailItem mailItem:
if (mailItem.Sent)
{ {
case MailItem mailItem: continue;
if (mailItem.Sent)
{
continue;
}
try
{
return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName);
}
catch (Exception exExport)
{
Log.Error().WriteLine(exExport, "Export to {0} failed.", currentCaption);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser))
{
Log.Debug().WriteLine("Not exporting, as organizer is set to {0} and currentuser {1} is not him.", appointmentItem.Organizer, _currentUser);
continue;
}
}
else
{
// skip, can't export to olAppointment
continue;
}
try
{
return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName);
}
catch (Exception exExport)
{
Log.Error().WriteLine(exExport, "Export to {0} failed.", currentCaption);
}
break;
default:
continue;
} }
} try
{
return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName);
}
catch (Exception exExport)
{
Log.Error().WriteLine(exExport, "Export to {0} failed.", currentCaption);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser))
{
Log.Debug().WriteLine("Not exporting, as organizer is set to {0} and currentuser {1} is not him.", appointmentItem.Organizer, _currentUser);
continue;
}
}
else
{
// skip, can't export to olAppointment
continue;
}
try
{
return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName);
}
catch (Exception exExport)
{
Log.Error().WriteLine(exExport, "Export to {0} failed.", currentCaption);
}
break;
default:
continue;
} }
} }
} }
@ -239,21 +233,19 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
using (wordDocument) using (wordDocument)
{ {
using (var application = DisposableCom.Create(wordDocument.ComObject.Application)) using var application = DisposableCom.Create(wordDocument.ComObject.Application);
try
{ {
try if (_wordExporter.InsertIntoExistingDocument(application, wordDocument, tmpFile, null, null))
{ {
if (_wordExporter.InsertIntoExistingDocument(application, wordDocument, tmpFile, null, null)) Log.Info().WriteLine("Inserted into Wordmail");
{ return true;
Log.Info().WriteLine("Inserted into Wordmail");
return true;
}
}
catch (Exception exportException)
{
Log.Error().WriteLine(exportException, "Error exporting to the word editor, trying to do it via another method");
} }
} }
catch (Exception exportException)
{
Log.Error().WriteLine(exportException, "Error exporting to the word editor, trying to do it via another method");
}
} }
} }
else if (isAppointment) else if (isAppointment)
@ -296,8 +288,7 @@ namespace Greenshot.Addon.Office.OfficeExport
// The following might cause a security popup... can't ignore it. // The following might cause a security popup... can't ignore it.
try try
{ {
var document2 = inspector.ComObject.HTMLEditor as IHTMLDocument2; if (inspector.ComObject.HTMLEditor is IHTMLDocument2 document2)
if (document2 != null)
{ {
var selection = document2.selection; var selection = document2.selection;
if (selection != null) if (selection != null)
@ -332,24 +323,20 @@ namespace Greenshot.Addon.Office.OfficeExport
} }
// Create the attachment (if inlined the attachment isn't visible as attachment!) // Create the attachment (if inlined the attachment isn't visible as attachment!)
using (var attachments = DisposableCom.Create(mailItem.Attachments)) using var attachments = DisposableCom.Create(mailItem.Attachments);
using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible ? 0 : 1, attachmentName));
if (_outlookVersion.Major >= (int)OfficeVersions.Office2007)
{ {
using (var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible ? 0 : 1, attachmentName))) // Add the content id to the attachment, this only works for Outlook >= 2007
try
{ {
if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) var propertyAccessor = attachment.ComObject.PropertyAccessor;
{ propertyAccessor.SetProperty(AttachmentContentId, contentId);
// Add the content id to the attachment, this only works for Outlook >= 2007 }
try // ReSharper disable once EmptyGeneralCatchClause
{ catch
var propertyAccessor = attachment.ComObject.PropertyAccessor; {
propertyAccessor.SetProperty(AttachmentContentId, contentId); // Ignore
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Ignore
}
}
} }
} }
} }
@ -401,135 +388,127 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <param name="url"></param> /// <param name="url"></param>
private void ExportToNewEmail(IDisposableCom<Application> outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string cc, string bcc, string url) private void ExportToNewEmail(IDisposableCom<Application> outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string cc, string bcc, string url)
{ {
using (var newItem = DisposableCom.Create((MailItem)outlookApplication.ComObject.CreateItem(OlItemType.olMailItem))) using var newItem = DisposableCom.Create((MailItem)outlookApplication.ComObject.CreateItem(OlItemType.olMailItem));
if (newItem == null)
{ {
if (newItem == null) return;
{ }
return; var newMail = newItem.ComObject;
} newMail.Subject = subject;
var newMail = newItem.ComObject; if (!string.IsNullOrEmpty(to))
newMail.Subject = subject; {
if (!string.IsNullOrEmpty(to)) newMail.To = to;
{ }
newMail.To = to; if (!string.IsNullOrEmpty(cc))
} {
if (!string.IsNullOrEmpty(cc)) newMail.CC = cc;
{ }
newMail.CC = cc; if (!string.IsNullOrEmpty(bcc))
} {
if (!string.IsNullOrEmpty(bcc)) newMail.BCC = bcc;
{ }
newMail.BCC = bcc; newMail.BodyFormat = OlBodyFormat.olFormatHTML;
} string bodyString = null;
newMail.BodyFormat = OlBodyFormat.olFormatHTML; // Read the default signature, if nothing found use empty email
string bodyString = null; try
// Read the default signature, if nothing found use empty email {
try bodyString = GetOutlookSignature(format);
{ }
bodyString = GetOutlookSignature(format); catch (Exception e)
} {
catch (Exception e) Log.Error().WriteLine("Problem reading signature!", e);
{ }
Log.Error().WriteLine("Problem reading signature!", e); switch (format)
} {
switch (format) case EmailFormat.Text:
{ // Create the attachment (and dispose the COM object after using)
case EmailFormat.Text: using (var attachments = DisposableCom.Create(newMail.Attachments))
// Create the attachment (and dispose the COM object after using) {
using (var attachments = DisposableCom.Create(newMail.Attachments)) using (DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 1, attachmentName)))
{ {
using (DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 1, attachmentName))) newMail.BodyFormat = OlBodyFormat.olFormatPlain;
if (bodyString == null)
{ {
newMail.BodyFormat = OlBodyFormat.olFormatPlain; bodyString = "";
if (bodyString == null) }
{ newMail.Body = bodyString;
bodyString = ""; }
} }
newMail.Body = bodyString; break;
} default:
} string contentId = Path.GetFileName(tmpFile);
break; // Create the attachment (and dispose the COM object after using)
default: using (var attachments = DisposableCom.Create(newMail.Attachments))
string contentId = Path.GetFileName(tmpFile); {
// Create the attachment (and dispose the COM object after using) using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName));
using (var attachments = DisposableCom.Create(newMail.Attachments)) // add content ID to the attachment
{ if (_outlookVersion.Major >= (int)OfficeVersions.Office2007)
using (var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName))) {
{ try
// add content ID to the attachment {
if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) contentId = Guid.NewGuid().ToString();
{ using var propertyAccessor = DisposableCom.Create(attachment.ComObject.PropertyAccessor);
try propertyAccessor.ComObject.SetProperty(AttachmentContentId, contentId);
{ }
contentId = Guid.NewGuid().ToString(); catch
using (var propertyAccessor = DisposableCom.Create(attachment.ComObject.PropertyAccessor)) {
{ Log.Info().WriteLine("Error working with the PropertyAccessor, using filename as contentid");
propertyAccessor.ComObject.SetProperty(AttachmentContentId, contentId); contentId = Path.GetFileName(tmpFile);
}
}
catch
{
Log.Info().WriteLine("Error working with the PropertyAccessor, using filename as contentid");
contentId = Path.GetFileName(tmpFile);
}
}
} }
} }
}
newMail.BodyFormat = OlBodyFormat.olFormatHTML; newMail.BodyFormat = OlBodyFormat.olFormatHTML;
string href = ""; string href = "";
string hrefEnd = ""; string hrefEnd = "";
if (!string.IsNullOrEmpty(url)) if (!string.IsNullOrEmpty(url))
{
href = string.Format("<A HREF=\"{0}\">", url);
hrefEnd = "</A>";
}
string htmlImgEmbedded = string.Format("<BR/>{0}<IMG border=0 hspace=0 alt=\"{1}\" align=baseline src=\"cid:{2}\">{3}<BR/>", href, attachmentName, contentId, hrefEnd);
string fallbackBody = string.Format("<HTML><BODY>{0}</BODY></HTML>", htmlImgEmbedded);
if (bodyString == null)
{
bodyString = fallbackBody;
}
else
{
int bodyIndex = bodyString.IndexOf("<body", StringComparison.CurrentCultureIgnoreCase);
if (bodyIndex >= 0)
{ {
href = string.Format("<A HREF=\"{0}\">", url); bodyIndex = bodyString.IndexOf(">", bodyIndex, StringComparison.Ordinal) + 1;
hrefEnd = "</A>";
}
string htmlImgEmbedded = string.Format("<BR/>{0}<IMG border=0 hspace=0 alt=\"{1}\" align=baseline src=\"cid:{2}\">{3}<BR/>", href, attachmentName, contentId, hrefEnd);
string fallbackBody = string.Format("<HTML><BODY>{0}</BODY></HTML>", htmlImgEmbedded);
if (bodyString == null)
{
bodyString = fallbackBody;
}
else
{
int bodyIndex = bodyString.IndexOf("<body", StringComparison.CurrentCultureIgnoreCase);
if (bodyIndex >= 0) if (bodyIndex >= 0)
{ {
bodyIndex = bodyString.IndexOf(">", bodyIndex, StringComparison.Ordinal) + 1; bodyString = bodyString.Insert(bodyIndex, htmlImgEmbedded);
if (bodyIndex >= 0)
{
bodyString = bodyString.Insert(bodyIndex, htmlImgEmbedded);
}
else
{
bodyString = fallbackBody;
}
} }
else else
{ {
bodyString = fallbackBody; bodyString = fallbackBody;
} }
} }
newMail.HTMLBody = bodyString; else
break;
}
// So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();)
newMail.Display(false);
using (var inspector = DisposableCom.Create((_Inspector)newMail.GetInspector))
{
if (inspector != null)
{
try
{ {
inspector.ComObject.Activate(); bodyString = fallbackBody;
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Ignore
} }
} }
newMail.HTMLBody = bodyString;
break;
}
// So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();)
newMail.Display(false);
using var inspector = DisposableCom.Create((_Inspector)newMail.GetInspector);
if (inspector != null)
{
try
{
inspector.ComObject.Activate();
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Ignore
} }
} }
} }
@ -620,50 +599,41 @@ namespace Greenshot.Addon.Office.OfficeExport
} }
string defaultProfile = (string)profilesKey.GetValue(DefaultProfileValue); string defaultProfile = (string)profilesKey.GetValue(DefaultProfileValue);
Log.Debug().WriteLine("defaultProfile={0}", defaultProfile); Log.Debug().WriteLine("defaultProfile={0}", defaultProfile);
using (var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false)) using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false);
if (profileKey != null)
{ {
if (profileKey != null) string[] numbers = profileKey.GetSubKeyNames();
foreach (string number in numbers)
{ {
string[] numbers = profileKey.GetSubKeyNames(); Log.Debug().WriteLine("Found subkey {0}", number);
foreach (string number in numbers) using var numberKey = profileKey.OpenSubKey(number, false);
if (numberKey != null)
{ {
Log.Debug().WriteLine("Found subkey {0}", number); byte[] val = (byte[])numberKey.GetValue(NewSignatureValue);
using (var numberKey = profileKey.OpenSubKey(number, false)) if (val == null)
{ {
if (numberKey != null) continue;
}
string signatureName = "";
foreach (byte b in val)
{
if (b != 0)
{ {
byte[] val = (byte[])numberKey.GetValue(NewSignatureValue); signatureName += (char)b;
if (val == null)
{
continue;
}
string signatureName = "";
foreach (byte b in val)
{
if (b != 0)
{
signatureName += (char)b;
}
}
Log.Debug().WriteLine("Found email signature: {0}", signatureName);
string extension;
switch (format)
{
case EmailFormat.Text:
extension = ".txt";
break;
default:
extension = ".htm";
break;
}
string signatureFile = Path.Combine(SignaturePath, signatureName + extension);
if (File.Exists(signatureFile))
{
Log.Debug().WriteLine("Found email signature file: {0}", signatureFile);
return File.ReadAllText(signatureFile, Encoding.Default);
}
} }
} }
Log.Debug().WriteLine("Found email signature: {0}", signatureName);
var extension = format switch
{
EmailFormat.Text => ".txt",
_ => ".htm"
};
string signatureFile = Path.Combine(SignaturePath, signatureName + extension);
if (File.Exists(signatureFile))
{
Log.Debug().WriteLine("Found email signature file: {0}", signatureFile);
return File.ReadAllText(signatureFile, Encoding.Default);
}
} }
} }
} }
@ -694,10 +664,8 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
using (var mapiNamespace = DisposableCom.Create(outlookApplication.ComObject.GetNamespace("MAPI"))) using (var mapiNamespace = DisposableCom.Create(outlookApplication.ComObject.GetNamespace("MAPI")))
{ {
using (var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser)) using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser);
{ _currentUser = currentUser.ComObject.Name;
_currentUser = currentUser.ComObject.Name;
}
} }
Log.Info().WriteLine("Current user: {0}", _currentUser); Log.Info().WriteLine("Current user: {0}", _currentUser);
} }
@ -717,99 +685,91 @@ namespace Greenshot.Addon.Office.OfficeExport
IDictionary<string, OlObjectClass> inspectorCaptions = new SortedDictionary<string, OlObjectClass>(); IDictionary<string, OlObjectClass> inspectorCaptions = new SortedDictionary<string, OlObjectClass>();
try try
{ {
using (var outlookApplication = GetOutlookApplication()) using var outlookApplication = GetOutlookApplication();
if (outlookApplication == null)
{ {
if (outlookApplication == null) return inspectorCaptions;
{ }
return inspectorCaptions;
}
// The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library // The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library
if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) if (_outlookVersion.Major >= (int)OfficeVersions.Office2013)
{
// Check inline "panel" for Outlook 2013
using var activeExplorer = DisposableCom.Create(outlookApplication.ComObject.ActiveExplorer());
if (activeExplorer != null)
{ {
// Check inline "panel" for Outlook 2013 var untypedInlineResponse = activeExplorer.ComObject.ActiveInlineResponse;
using (var activeExplorer = DisposableCom.Create(outlookApplication.ComObject.ActiveExplorer())) if (untypedInlineResponse != null)
{ {
if (activeExplorer != null) string caption = activeExplorer.ComObject.Caption;
using (DisposableCom.Create(untypedInlineResponse))
{ {
var untypedInlineResponse = activeExplorer.ComObject.ActiveInlineResponse; switch (untypedInlineResponse)
if (untypedInlineResponse != null)
{ {
string caption = activeExplorer.ComObject.Caption; case MailItem mailItem:
using (DisposableCom.Create(untypedInlineResponse)) if (!mailItem.Sent)
{
switch (untypedInlineResponse)
{ {
case MailItem mailItem: inspectorCaptions.Add(caption, mailItem.Class);
if (!mailItem.Sent)
{
inspectorCaptions.Add(caption, mailItem.Class);
}
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser))
{
inspectorCaptions.Add(caption, appointmentItem.Class);
}
}
break;
} }
} break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser))
{
inspectorCaptions.Add(caption, appointmentItem.Class);
}
}
break;
} }
} }
} }
} }
}
using (var inspectors = DisposableCom.Create(outlookApplication.ComObject.Inspectors)) using var inspectors = DisposableCom.Create(outlookApplication.ComObject.Inspectors);
if ((inspectors != null) && (inspectors.ComObject.Count > 0))
{
for (int i = 1; i <= inspectors.ComObject.Count; i++)
{ {
if ((inspectors != null) && (inspectors.ComObject.Count > 0)) using var inspector = DisposableCom.Create(inspectors.ComObject[i]);
string caption = inspector.ComObject.Caption;
// Fix double entries in the directory, TODO: store on something uniq
if (inspectorCaptions.ContainsKey(caption))
{ {
for (int i = 1; i <= inspectors.ComObject.Count; i++) continue;
}
var currentItemUntyped = inspector.ComObject.CurrentItem;
using (DisposableCom.Create(currentItemUntyped))
{
switch (currentItemUntyped)
{ {
using (var inspector = DisposableCom.Create(inspectors.ComObject[i])) case MailItem mailItem:
{ if (mailItem.Sent)
string caption = inspector.ComObject.Caption;
// Fix double entries in the directory, TODO: store on something uniq
if (inspectorCaptions.ContainsKey(caption))
{ {
continue; continue;
} }
inspectorCaptions.Add(caption, mailItem.Class);
var currentItemUntyped = inspector.ComObject.CurrentItem; break;
using (DisposableCom.Create(currentItemUntyped)) case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{ {
switch (currentItemUntyped) if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser))
{ {
case MailItem mailItem: Log.Debug().WriteLine("Not exporting, as organizer is set to {0} and currentuser {1} is not him.", appointmentItem.Organizer, _currentUser);
if (mailItem.Sent) continue;
{
continue;
}
inspectorCaptions.Add(caption, mailItem.Class);
break;
case AppointmentItem appointmentItem:
if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings)
{
if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser))
{
Log.Debug().WriteLine("Not exporting, as organizer is set to {0} and currentuser {1} is not him.", appointmentItem.Organizer, _currentUser);
continue;
}
}
else
{
// skip, can't export to olAppointment
continue;
}
inspectorCaptions.Add(caption, appointmentItem.Class);
break;
default:
continue;
} }
} }
} else
{
// skip, can't export to olAppointment
continue;
}
inspectorCaptions.Add(caption, appointmentItem.Class);
break;
default:
continue;
} }
} }
} }

View file

@ -81,72 +81,64 @@ namespace Greenshot.Addon.Office.OfficeExport
slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, _officeConfiguration.PowerpointSlideLayout)); slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, _officeConfiguration.PowerpointSlideLayout));
} }
using (var shapes = DisposableCom.Create(slide.ComObject.Shapes)) using var shapes = DisposableCom.Create(slide.ComObject.Shapes);
using var shapeForLocation = DisposableCom.Create(shapes.ComObject[2]);
// Shapes[2] is the image shape on this layout.
shapeForCaption = DisposableCom.Create(shapes.ComObject[1]);
if (width > shapeForLocation.ComObject.Width)
{ {
using (var shapeForLocation = DisposableCom.Create(shapes.ComObject[2])) width = shapeForLocation.ComObject.Width;
{ left = shapeForLocation.ComObject.Left;
// Shapes[2] is the image shape on this layout. hasScaledWidth = true;
shapeForCaption = DisposableCom.Create(shapes.ComObject[1]);
if (width > shapeForLocation.ComObject.Width)
{
width = shapeForLocation.ComObject.Width;
left = shapeForLocation.ComObject.Left;
hasScaledWidth = true;
}
else
{
shapeForLocation.ComObject.Left = left;
}
shapeForLocation.ComObject.Width = imageSize.Width;
if (height > shapeForLocation.ComObject.Height)
{
height = shapeForLocation.ComObject.Height;
top = shapeForLocation.ComObject.Top;
hasScaledHeight = true;
}
else
{
top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f;
}
shapeForLocation.ComObject.Height = imageSize.Height;
}
} }
else
{
shapeForLocation.ComObject.Left = left;
}
shapeForLocation.ComObject.Width = imageSize.Width;
if (height > shapeForLocation.ComObject.Height)
{
height = shapeForLocation.ComObject.Height;
top = shapeForLocation.ComObject.Top;
hasScaledHeight = true;
}
else
{
top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f;
}
shapeForLocation.ComObject.Height = imageSize.Height;
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error().WriteLine(e, "Powerpoint shape creating failed"); Log.Error().WriteLine(e, "Powerpoint shape creating failed");
using (var slides = DisposableCom.Create(presentation.ComObject.Slides)) using var slides = DisposableCom.Create(presentation.ComObject.Slides);
{ slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank));
slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank));
}
} }
using (var shapes = DisposableCom.Create(slide.ComObject.Shapes)) using (var shapes = DisposableCom.Create(slide.ComObject.Shapes))
{ {
using (var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height))) using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height));
if (_officeConfiguration.PowerpointLockAspectRatio)
{ {
if (_officeConfiguration.PowerpointLockAspectRatio) shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
{
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
}
else
{
shape.ComObject.LockAspectRatio = MsoTriState.msoFalse;
}
shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
if (hasScaledWidth)
{
shape.ComObject.Width = width;
}
if (hasScaledHeight)
{
shape.ComObject.Height = height;
}
shape.ComObject.Left = left;
shape.ComObject.Top = top;
shape.ComObject.AlternativeText = title;
} }
else
{
shape.ComObject.LockAspectRatio = MsoTriState.msoFalse;
}
shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle);
if (hasScaledWidth)
{
shape.ComObject.Width = width;
}
if (hasScaledHeight)
{
shape.ComObject.Height = height;
}
shape.ComObject.Left = left;
shape.ComObject.Top = top;
shape.ComObject.AlternativeText = title;
} }
if (shapeForCaption != null) if (shapeForCaption != null)
{ {
@ -155,13 +147,9 @@ namespace Greenshot.Addon.Office.OfficeExport
using (shapeForCaption) using (shapeForCaption)
{ {
// Using try/catch to make sure problems with the text range don't give an exception. // Using try/catch to make sure problems with the text range don't give an exception.
using (var textFrame = DisposableCom.Create(shapeForCaption.ComObject.TextFrame)) using var textFrame = DisposableCom.Create(shapeForCaption.ComObject.TextFrame);
{ using var textRange = DisposableCom.Create(textFrame.ComObject.TextRange);
using (var textRange = DisposableCom.Create(textFrame.ComObject.TextRange)) textRange.ComObject.Text = title;
{
textRange.ComObject.Text = title;
}
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -172,16 +160,10 @@ namespace Greenshot.Addon.Office.OfficeExport
// Activate/Goto the slide // Activate/Goto the slide
try try
{ {
using (var application = DisposableCom.Create(presentation.ComObject.Application)) using var application = DisposableCom.Create(presentation.ComObject.Application);
{ using var activeWindow = DisposableCom.Create(application.ComObject.ActiveWindow);
using (var activeWindow = DisposableCom.Create(application.ComObject.ActiveWindow)) using var view = DisposableCom.Create(activeWindow.ComObject.View);
{ view.ComObject.GotoSlide(slide.ComObject.SlideNumber);
using (var view = DisposableCom.Create(activeWindow.ComObject.View))
{
view.ComObject.GotoSlide(slide.ComObject.SlideNumber);
}
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -211,31 +193,28 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
return false; return false;
} }
using (var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations))
using var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations);
Log.Debug().WriteLine("Open Presentations: {0}", presentations.ComObject.Count);
for (int i = 1; i <= presentations.ComObject.Count; i++)
{ {
Log.Debug().WriteLine("Open Presentations: {0}", presentations.ComObject.Count); using var presentation = DisposableCom.Create(presentations.ComObject[i]);
for (int i = 1; i <= presentations.ComObject.Count; i++) if (presentation == null)
{ {
using (var presentation = DisposableCom.Create(presentations.ComObject[i])) continue;
{ }
if (presentation == null) if (!presentation.ComObject.Name.StartsWith(presentationName))
{ {
continue; continue;
} }
if (!presentation.ComObject.Name.StartsWith(presentationName)) try
{ {
continue; AddPictureToPresentation(presentation, tmpFile, imageSize, title);
} return true;
try }
{ catch (Exception e)
AddPictureToPresentation(presentation, tmpFile, imageSize, title); {
return true; Log.Error().WriteLine(e, "Adding picture to powerpoint failed");
}
catch (Exception e)
{
Log.Error().WriteLine(e, "Adding picture to powerpoint failed");
}
}
} }
} }
} }
@ -286,39 +265,33 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns></returns> /// <returns></returns>
public IEnumerable<string> GetPowerpointPresentations() public IEnumerable<string> GetPowerpointPresentations()
{ {
using (var powerpointApplication = GetPowerPointApplication()) using var powerpointApplication = GetPowerPointApplication();
if (powerpointApplication == null)
{ {
if (powerpointApplication == null) yield break;
{ }
yield break;
}
using (var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations)) using var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations);
Log.Debug().WriteLine("Open Presentations: {0}", presentations.ComObject.Count);
for (int i = 1; i <= presentations.ComObject.Count; i++)
{
using var presentation = DisposableCom.Create(presentations.ComObject[i]);
if (presentation == null)
{ {
Log.Debug().WriteLine("Open Presentations: {0}", presentations.ComObject.Count); continue;
for (int i = 1; i <= presentations.ComObject.Count; i++) }
if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue)
{
continue;
}
if (IsAfter2003())
{
if (presentation.ComObject.Final)
{ {
using (var presentation = DisposableCom.Create(presentations.ComObject[i])) continue;
{
if (presentation == null)
{
continue;
}
if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue)
{
continue;
}
if (IsAfter2003())
{
if (presentation.ComObject.Final)
{
continue;
}
}
yield return presentation.ComObject.Name;
}
} }
} }
yield return presentation.ComObject.Name;
} }
} }
@ -355,20 +328,16 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
powerpointApplication.ComObject.Activate(); powerpointApplication.ComObject.Activate();
powerpointApplication.ComObject.Visible = MsoTriState.msoTrue; powerpointApplication.ComObject.Visible = MsoTriState.msoTrue;
using (var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations)) using var presentations = DisposableCom.Create(powerpointApplication.ComObject.Presentations);
using var presentation = DisposableCom.Create(presentations.ComObject.Add());
try
{ {
using (var presentation = DisposableCom.Create(presentations.ComObject.Add())) AddPictureToPresentation(presentation, tmpFile, imageSize, title);
{ isPictureAdded = true;
try }
{ catch (Exception e)
AddPictureToPresentation(presentation, tmpFile, imageSize, title); {
isPictureAdded = true; Log.Error().WriteLine(e, "Powerpoint add picture to presentation failed");
}
catch (Exception e)
{
Log.Error().WriteLine(e, "Powerpoint add picture to presentation failed");
}
}
} }
} }
} }

View file

@ -55,18 +55,16 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns></returns> /// <returns></returns>
private IDisposableCom<InlineShape> AddPictureToSelection(IDisposableCom<Selection> selection, string tmpFile) private IDisposableCom<InlineShape> AddPictureToSelection(IDisposableCom<Selection> selection, string tmpFile)
{ {
using (var shapes = DisposableCom.Create(selection.ComObject.InlineShapes)) using var shapes = DisposableCom.Create(selection.ComObject.InlineShapes);
var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, false, true, Type.Missing));
// Lock aspect ratio
if (_officeConfiguration.WordLockAspectRatio)
{ {
var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, false, true, Type.Missing)); shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
// Lock aspect ratio
if (_officeConfiguration.WordLockAspectRatio)
{
shape.ComObject.LockAspectRatio = MsoTriState.msoTrue;
}
selection.ComObject.InsertAfter("\r\n");
selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing);
return shape;
} }
selection.ComObject.InsertAfter("\r\n");
selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing);
return shape;
} }
/// <summary> /// <summary>
@ -113,36 +111,30 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <returns></returns> /// <returns></returns>
public IEnumerable<string> GetWordDocuments() public IEnumerable<string> GetWordDocuments()
{ {
using (var wordApplication = GetWordApplication()) using var wordApplication = GetWordApplication();
if (wordApplication == null)
{ {
if (wordApplication == null) yield break;
}
using var documents = DisposableCom.Create(wordApplication.ComObject.Documents);
for (int i = 1; i <= documents.ComObject.Count; i++)
{
using var document = DisposableCom.Create(documents.ComObject[i]);
if (document.ComObject.ReadOnly)
{ {
yield break; continue;
} }
using (var documents = DisposableCom.Create(wordApplication.ComObject.Documents)) if (IsAfter2003())
{ {
for (int i = 1; i <= documents.ComObject.Count; i++) if (document.ComObject.Final)
{ {
using (var document = DisposableCom.Create(documents.ComObject[i])) continue;
{
if (document.ComObject.ReadOnly)
{
continue;
}
if (IsAfter2003())
{
if (document.ComObject.Final)
{
continue;
}
}
using (var activeWindow = DisposableCom.Create(document.ComObject.ActiveWindow))
{
yield return activeWindow.ComObject.Caption;
}
}
} }
} }
using var activeWindow = DisposableCom.Create(document.ComObject.ActiveWindow);
yield return activeWindow.ComObject.Caption;
} }
} }
@ -177,20 +169,15 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
return false; return false;
} }
using (var documents = DisposableCom.Create(wordApplication.ComObject.Documents))
using var documents = DisposableCom.Create(wordApplication.ComObject.Documents);
for (int i = 1; i <= documents.ComObject.Count; i++)
{ {
for (int i = 1; i <= documents.ComObject.Count; i++) using var wordDocument = DisposableCom.Create((_Document)documents.ComObject[i]);
using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow);
if (activeWindow.ComObject.Caption.StartsWith(wordCaption))
{ {
using (var wordDocument = DisposableCom.Create((_Document)documents.ComObject[i])) return InsertIntoExistingDocument(wordApplication, wordDocument, tmpFile, null, null);
{
using (var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow))
{
if (activeWindow.ComObject.Caption.StartsWith(wordCaption))
{
return InsertIntoExistingDocument(wordApplication, wordDocument, tmpFile, null, null);
}
}
}
} }
} }
} }
@ -219,81 +206,72 @@ namespace Greenshot.Addon.Office.OfficeExport
{ {
Log.Warn().WriteLine(ex); Log.Warn().WriteLine(ex);
} }
using (var selection = DisposableCom.Create(wordApplication.ComObject.Selection))
using var selection = DisposableCom.Create(wordApplication.ComObject.Selection);
if (selection == null)
{ {
if (selection == null) Log.Info().WriteLine("No selection to insert {0} into found.", tmpFile);
{ return false;
Log.Info().WriteLine("No selection to insert {0} into found.", tmpFile);
return false;
}
// Add Picture
using (var shape = AddPictureToSelection(selection, tmpFile))
{
if (!string.IsNullOrEmpty(address))
{
object screentip = Type.Missing;
if (!string.IsNullOrEmpty(tooltip))
{
screentip = tooltip;
}
try
{
using (var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks))
{
hyperlinks.ComObject.Add(shape, screentip, Type.Missing, screentip, Type.Missing, Type.Missing);
}
}
catch (Exception e)
{
Log.Warn().WriteLine("Couldn't add hyperlink for image: {0}", e.Message);
}
}
}
try
{
using (var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow))
{
activeWindow.ComObject.Activate();
using (var activePane = DisposableCom.Create(activeWindow.ComObject.ActivePane))
{
using (var view = DisposableCom.Create(activePane.ComObject.View))
{
view.ComObject.Zoom.Percentage = 100;
}
}
}
}
catch (Exception e)
{
if (e.InnerException != null)
{
Log.Warn().WriteLine("Couldn't set zoom to 100, error: {0}", e.InnerException.Message);
}
else
{
Log.Warn().WriteLine("Couldn't set zoom to 100, error: {0}", e.Message);
}
}
try
{
wordApplication.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
try
{
wordDocument.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
return true;
} }
// Add Picture
using (var shape = AddPictureToSelection(selection, tmpFile))
{
if (!string.IsNullOrEmpty(address))
{
object screentip = Type.Missing;
if (!string.IsNullOrEmpty(tooltip))
{
screentip = tooltip;
}
try
{
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
hyperlinks.ComObject.Add(shape, screentip, Type.Missing, screentip, Type.Missing, Type.Missing);
}
catch (Exception e)
{
Log.Warn().WriteLine("Couldn't add hyperlink for image: {0}", e.Message);
}
}
}
try
{
using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow);
activeWindow.ComObject.Activate();
using var activePane = DisposableCom.Create(activeWindow.ComObject.ActivePane);
using var view = DisposableCom.Create(activePane.ComObject.View);
view.ComObject.Zoom.Percentage = 100;
}
catch (Exception e)
{
if (e.InnerException != null)
{
Log.Warn().WriteLine("Couldn't set zoom to 100, error: {0}", e.InnerException.Message);
}
else
{
Log.Warn().WriteLine("Couldn't set zoom to 100, error: {0}", e.Message);
}
}
try
{
wordApplication.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
try
{
wordDocument.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
return true;
} }
/// <summary> /// <summary>
@ -304,76 +282,64 @@ namespace Greenshot.Addon.Office.OfficeExport
/// <param name="tooltip">string</param> /// <param name="tooltip">string</param>
public void InsertIntoNewDocument(string tmpFile, string address, string tooltip) public void InsertIntoNewDocument(string tmpFile, string address, string tooltip)
{ {
using (var wordApplication = GetOrCreateWordApplication()) using var wordApplication = GetOrCreateWordApplication();
if (wordApplication == null)
{ {
if (wordApplication == null) return;
}
wordApplication.ComObject.Visible = true;
wordApplication.ComObject.Activate();
// Create new Document
object template = string.Empty;
object newTemplate = false;
object documentType = 0;
object documentVisible = true;
using var documents = DisposableCom.Create(wordApplication.ComObject.Documents);
using var wordDocument = DisposableCom.Create(documents.ComObject.Add(template, newTemplate, documentType, documentVisible));
using (var selection = DisposableCom.Create(wordApplication.ComObject.Selection))
{
// Add Picture
using var shape = AddPictureToSelection(selection, tmpFile);
if (!string.IsNullOrEmpty(address))
{ {
return; object screentip = Type.Missing;
} if (!string.IsNullOrEmpty(tooltip))
wordApplication.ComObject.Visible = true;
wordApplication.ComObject.Activate();
// Create new Document
object template = string.Empty;
object newTemplate = false;
object documentType = 0;
object documentVisible = true;
using (var documents = DisposableCom.Create(wordApplication.ComObject.Documents))
{
using (var wordDocument = DisposableCom.Create(documents.ComObject.Add(template, newTemplate, documentType, documentVisible)))
{ {
using (var selection = DisposableCom.Create(wordApplication.ComObject.Selection)) screentip = tooltip;
}
try
{
using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks);
using (DisposableCom.Create(hyperlinks.ComObject.Add(shape, screentip, Type.Missing, screentip, Type.Missing, Type.Missing)))
{ {
// Add Picture // Do nothing
using (var shape = AddPictureToSelection(selection, tmpFile))
{
if (!string.IsNullOrEmpty(address))
{
object screentip = Type.Missing;
if (!string.IsNullOrEmpty(tooltip))
{
screentip = tooltip;
}
try
{
using (var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks))
{
using (DisposableCom.Create(hyperlinks.ComObject.Add(shape, screentip, Type.Missing, screentip, Type.Missing, Type.Missing)))
{
// Do nothing
}
}
}
catch (Exception e)
{
Log.Warn().WriteLine("Couldn't add hyperlink for image: {0}", e.Message);
}
}
}
}
try
{
wordDocument.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
try
{
using (var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow))
{
activeWindow.ComObject.Activate();
}
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
} }
} }
catch (Exception e)
{
Log.Warn().WriteLine("Couldn't add hyperlink for image: {0}", e.Message);
}
} }
} }
try
{
wordDocument.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
try
{
using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow);
activeWindow.ComObject.Activate();
// ReSharper disable once EmptyGeneralCatchClause
}
catch (Exception ex)
{
Log.Warn().WriteLine(ex);
}
} }
/// <summary> /// <summary>

View file

@ -126,10 +126,8 @@ namespace Greenshot.Addon.OneDrive
get get
{ {
// TODO: Optimize this by caching // TODO: Optimize this by caching
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "onedrive.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "onedrive.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -188,11 +186,9 @@ namespace Greenshot.Addon.OneDrive
if (_oneDriveConfiguration.AfterUploadLinkToClipBoard) if (_oneDriveConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(response.AbsoluteUri);
clipboardAccessToken.SetAsUrl(response.AbsoluteUri);
}
} }
return response; return response;
@ -227,17 +223,13 @@ namespace Greenshot.Addon.OneDrive
localBehaviour.UploadProgress = percent => { Execute.OnUIThread(() => progress.Report((int)(percent * 100))); }; localBehaviour.UploadProgress = percent => { Execute.OnUIThread(() => progress.Report((int)(percent * 100))); };
} }
var oauthHttpBehaviour = OAuth2HttpBehaviourFactory.Create(oAuth2Settings, localBehaviour); var oauthHttpBehaviour = OAuth2HttpBehaviourFactory.Create(oAuth2Settings, localBehaviour);
using (var imageStream = new MemoryStream()) using var imageStream = new MemoryStream();
{ surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _oneDriveConfiguration);
surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _oneDriveConfiguration); imageStream.Position = 0;
imageStream.Position = 0; using var content = new StreamContent(imageStream);
using (var content = new StreamContent(imageStream)) content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(CoreConfiguration, _oneDriveConfiguration));
{ oauthHttpBehaviour.MakeCurrent();
content.Headers.Add("Content-Type", surfaceToUpload.GenerateMimeType(CoreConfiguration, _oneDriveConfiguration)); return await uploadUri.PutAsync<OneDriveUploadResponse>(content, token);
oauthHttpBehaviour.MakeCurrent();
return await uploadUri.PutAsync<OneDriveUploadResponse>(content, token);
}
}
} }
private async Task<OneDriveGetLinkResponse> CreateSharableLinkAync(OAuth2Settings oAuth2Settings, private async Task<OneDriveGetLinkResponse> CreateSharableLinkAync(OAuth2Settings oAuth2Settings,

View file

@ -185,12 +185,10 @@ namespace Greenshot.Addon.Photobucket
public override IBitmapWithNativeSupport DisplayIcon public override IBitmapWithNativeSupport DisplayIcon
{ {
get get
{ {
// TODO: Optimize this // TODO: Optimize this
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "photobucket-logo.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "photobucket-logo.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -295,28 +293,26 @@ namespace Greenshot.Addon.Photobucket
{ {
surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _photobucketConfiguration); surfaceToUpload.WriteToStream(imageStream, CoreConfiguration, _photobucketConfiguration);
imageStream.Position = 0; imageStream.Position = 0;
using (var streamContent = new StreamContent(imageStream)) using var streamContent = new StreamContent(imageStream);
streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _photobucketConfiguration));
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{ {
streamContent.Headers.ContentType = new MediaTypeHeaderValue(surfaceToUpload.GenerateMimeType(CoreConfiguration, _photobucketConfiguration)); Name = "\"uploadfile\"",
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") FileName = "\"" + filename + "\""
{ };
Name = "\"uploadfile\"",
FileName = "\"" + filename + "\""
};
HttpBehaviour.Current.SetConfig(new HttpRequestMessageConfiguration HttpBehaviour.Current.SetConfig(new HttpRequestMessageConfiguration
{ {
Properties = signedParameters Properties = signedParameters
}); });
try try
{ {
responseString = await uploadUri.PostAsync<string>(streamContent, token); responseString = await uploadUri.PostAsync<string>(streamContent, token);
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error().WriteLine(ex, "Error uploading to Photobucket."); Log.Error().WriteLine(ex, "Error uploading to Photobucket.");
throw; throw;
}
} }
} }

View file

@ -145,21 +145,17 @@ namespace Greenshot.Addon.Tfs
var filename = surface.GenerateFilename(_coreConfiguration, _tfsConfiguration); var filename = surface.GenerateFilename(_coreConfiguration, _tfsConfiguration);
var attachmentUri = apiUri.AppendSegments("wit", "attachments").ExtendQuery("fileName", filename); var attachmentUri = apiUri.AppendSegments("wit", "attachments").ExtendQuery("fileName", filename);
using (var imageStream = new MemoryStream()) using var imageStream = new MemoryStream();
surface.WriteToStream(imageStream, _coreConfiguration, _tfsConfiguration);
imageStream.Position = 0;
using var content = new StreamContent(imageStream);
content.SetContentType("application/octet-stream");
var createAttachmentresult = await client.PostAsync<HttpResponse<CreateAttachmentResult, string>>(attachmentUri, content).ConfigureAwait(false);
if (createAttachmentresult.HasError)
{ {
surface.WriteToStream(imageStream, _coreConfiguration, _tfsConfiguration); throw new Exception(createAttachmentresult.ErrorResponse);
imageStream.Position = 0;
using (var content = new StreamContent(imageStream))
{
content.SetContentType("application/octet-stream");
var createAttachmentresult = await client.PostAsync<HttpResponse<CreateAttachmentResult, string>>(attachmentUri, content).ConfigureAwait(false);
if (createAttachmentresult.HasError)
{
throw new Exception(createAttachmentresult.ErrorResponse);
}
return createAttachmentresult.Response;
}
} }
return createAttachmentresult.Response;
} }
/// <summary> /// <summary>

View file

@ -165,10 +165,8 @@ namespace Greenshot.Addon.Tfs
get get
{ {
// TODO: Optimize this by using a cache // TODO: Optimize this by using a cache
using (var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "vsts.png")) using var bitmapStream = _resourceProvider.ResourceAsStream(GetType().Assembly, "vsts.png");
{ return BitmapHelper.FromStream(bitmapStream);
return BitmapHelper.FromStream(bitmapStream);
}
} }
} }
@ -224,11 +222,9 @@ namespace Greenshot.Addon.Tfs
if (_tfsConfiguration.AfterUploadLinkToClipBoard) if (_tfsConfiguration.AfterUploadLinkToClipBoard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); clipboardAccessToken.SetAsUrl(response.AbsoluteUri);
clipboardAccessToken.SetAsUrl(response.AbsoluteUri);
}
} }
return response; return response;

View file

@ -67,19 +67,14 @@ namespace Greenshot.Addons.Animation
/// </summary> /// </summary>
protected double EasingValue protected double EasingValue
{ {
get get =>
{ EasingMode switch
switch (EasingMode) {
{ EasingModes.EaseOut => Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType),
case EasingModes.EaseOut: EasingModes.EaseInOut => Easing.EaseInOut(CurrentFrameNr / (double) Frames, EasingType),
return Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType); _ => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType)
case EasingModes.EaseInOut: };
return Easing.EaseInOut(CurrentFrameNr / (double) Frames, EasingType); }
default:
return Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType);
}
}
}
/// <summary> /// <summary>
/// Final animation value, this is including the legs /// Final animation value, this is including the legs

View file

@ -47,27 +47,18 @@ namespace Greenshot.Addons.Animation
/// <param name="linearStep">double</param> /// <param name="linearStep">double</param>
/// <param name="type">EasingTypes</param> /// <param name="type">EasingTypes</param>
/// <returns>double</returns> /// <returns>double</returns>
public static double EaseIn(double linearStep, EasingTypes type) public static double EaseIn(double linearStep, EasingTypes type) =>
{ type switch
switch (type) {
{ EasingTypes.Step => (linearStep < 0.5 ? 0 : 1),
case EasingTypes.Step: EasingTypes.Linear => linearStep,
return linearStep < 0.5 ? 0 : 1; EasingTypes.Sine => EaseSine.EaseIn(linearStep),
case EasingTypes.Linear: EasingTypes.Quadratic => EasePower.EaseIn(linearStep, 2),
return linearStep; EasingTypes.Cubic => EasePower.EaseIn(linearStep, 3),
case EasingTypes.Sine: EasingTypes.Quartic => EasePower.EaseIn(linearStep, 4),
return EaseSine.EaseIn(linearStep); EasingTypes.Quintic => EasePower.EaseIn(linearStep, 5),
case EasingTypes.Quadratic: _ => throw new NotImplementedException()
return EasePower.EaseIn(linearStep, 2); };
case EasingTypes.Cubic:
return EasePower.EaseIn(linearStep, 3);
case EasingTypes.Quartic:
return EasePower.EaseIn(linearStep, 4);
case EasingTypes.Quintic:
return EasePower.EaseIn(linearStep, 5);
}
throw new NotImplementedException();
}
/// <summary> /// <summary>
/// Apply ease in-out /// Apply ease in-out
@ -87,54 +78,36 @@ namespace Greenshot.Addons.Animation
/// <param name="linearStep">double</param> /// <param name="linearStep">double</param>
/// <param name="type">EasingTypes</param> /// <param name="type">EasingTypes</param>
/// <returns>double</returns> /// <returns>double</returns>
public static double EaseInOut(double linearStep, EasingTypes type) public static double EaseInOut(double linearStep, EasingTypes type) =>
{ type switch
switch (type) {
{ EasingTypes.Step => (linearStep < 0.5 ? 0 : 1),
case EasingTypes.Step: EasingTypes.Linear => linearStep,
return linearStep < 0.5 ? 0 : 1; EasingTypes.Sine => EaseSine.EaseInOut(linearStep),
case EasingTypes.Linear: EasingTypes.Quadratic => EasePower.EaseInOut(linearStep, 2),
return linearStep; EasingTypes.Cubic => EasePower.EaseInOut(linearStep, 3),
case EasingTypes.Sine: EasingTypes.Quartic => EasePower.EaseInOut(linearStep, 4),
return EaseSine.EaseInOut(linearStep); EasingTypes.Quintic => EasePower.EaseInOut(linearStep, 5),
case EasingTypes.Quadratic: _ => throw new NotImplementedException()
return EasePower.EaseInOut(linearStep, 2); };
case EasingTypes.Cubic:
return EasePower.EaseInOut(linearStep, 3);
case EasingTypes.Quartic:
return EasePower.EaseInOut(linearStep, 4);
case EasingTypes.Quintic:
return EasePower.EaseInOut(linearStep, 5);
}
throw new NotImplementedException();
}
/// <summary> /// <summary>
/// Apply easy out /// Apply easy out
/// </summary> /// </summary>
/// <param name="linearStep">double</param> /// <param name="linearStep">double</param>
/// <param name="type">EasingTypes</param> /// <param name="type">EasingTypes</param>
/// <returns>double</returns> /// <returns>double</returns>
public static double EaseOut(double linearStep, EasingTypes type) public static double EaseOut(double linearStep, EasingTypes type) =>
{ type switch
switch (type) {
{ EasingTypes.Step => (linearStep < 0.5 ? 0 : 1),
case EasingTypes.Step: EasingTypes.Linear => linearStep,
return linearStep < 0.5 ? 0 : 1; EasingTypes.Sine => EaseSine.EaseOut(linearStep),
case EasingTypes.Linear: EasingTypes.Quadratic => EasePower.EaseOut(linearStep, 2),
return linearStep; EasingTypes.Cubic => EasePower.EaseOut(linearStep, 3),
case EasingTypes.Sine: EasingTypes.Quartic => EasePower.EaseOut(linearStep, 4),
return EaseSine.EaseOut(linearStep); EasingTypes.Quintic => EasePower.EaseOut(linearStep, 5),
case EasingTypes.Quadratic: _ => throw new NotImplementedException()
return EasePower.EaseOut(linearStep, 2); };
case EasingTypes.Cubic: }
return EasePower.EaseOut(linearStep, 3);
case EasingTypes.Quartic:
return EasePower.EaseOut(linearStep, 4);
case EasingTypes.Quintic:
return EasePower.EaseOut(linearStep, 5);
}
throw new NotImplementedException();
}
}
} }

View file

@ -81,13 +81,11 @@ namespace Greenshot.Addons.Controls
get get
{ {
if (_vRefresh == 0) if (_vRefresh == 0)
{ {
// get te hDC of the desktop to get the VREFRESH // get te hDC of the desktop to get the VREFRESH
using (var desktopHandle = SafeWindowDcHandle.FromDesktop()) using var desktopHandle = SafeWindowDcHandle.FromDesktop();
{ _vRefresh = Gdi32Api.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH);
_vRefresh = Gdi32Api.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); }
}
}
// A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate.
// As there is currently no know way to get the default, we guess it. // As there is currently no know way to get the default, we guess it.
if (_vRefresh <= 1) if (_vRefresh <= 1)

View file

@ -101,20 +101,18 @@ namespace Greenshot.Addons.Controls
/// <param name="screenCoordinates">Point with the coordinates</param> /// <param name="screenCoordinates">Point with the coordinates</param>
/// <returns>Color at the specified screenCoordinates</returns> /// <returns>Color at the specified screenCoordinates</returns>
private static Color GetPixelColor(Point screenCoordinates) private static Color GetPixelColor(Point screenCoordinates)
{ {
using (var screenDc = SafeWindowDcHandle.FromDesktop()) using var screenDc = SafeWindowDcHandle.FromDesktop();
{ try
try {
{ var pixel = Gdi32Api.GetPixel(screenDc, screenCoordinates.X, screenCoordinates.Y);
var pixel = Gdi32Api.GetPixel(screenDc, screenCoordinates.X, screenCoordinates.Y); var color = Color.FromArgb(255, (int) (pixel & 0xFF), (int) (pixel & 0xFF00) >> 8, (int) (pixel & 0xFF0000) >> 16);
var color = Color.FromArgb(255, (int) (pixel & 0xFF), (int) (pixel & 0xFF00) >> 8, (int) (pixel & 0xFF0000) >> 16); return color;
return color; }
} catch (Exception)
catch (Exception) {
{ return Color.Empty;
return Color.Empty; }
} }
}
}
} }
} }

View file

@ -132,6 +132,7 @@ namespace Greenshot.Addons.Core
_safeDibSectionHandle.Dispose(); _safeDibSectionHandle.Dispose();
_safeCompatibleDcHandle.Dispose(); _safeCompatibleDcHandle.Dispose();
_desktopDcHandle.Dispose(); _desktopDcHandle.Dispose();
_bitmap.Dispose();
} }
} }

View file

@ -122,26 +122,24 @@ EndSelection:<<<<<<<4
try try
{ {
User32Api.GetWindowThreadProcessId(hWnd, out var pid); User32Api.GetWindowThreadProcessId(hWnd, out var pid);
using (var me = Process.GetCurrentProcess()) using var me = Process.GetCurrentProcess();
using (var ownerProcess = Process.GetProcessById(pid)) using var ownerProcess = Process.GetProcessById(pid);
{ // Exclude myself
// Exclude myself if (me.Id != ownerProcess.Id)
if (me.Id != ownerProcess.Id) {
{ // Get Process Name
// Get Process Name owner = ownerProcess.ProcessName;
owner = ownerProcess.ProcessName; // Try to get the starting Process Filename, this might fail.
// Try to get the starting Process Filename, this might fail. try
try {
{ owner = ownerProcess.Modules[0].FileName;
owner = ownerProcess.Modules[0].FileName; }
} catch (Exception)
catch (Exception) {
{ // Ignore
// Ignore }
} }
} }
}
}
catch (Exception e) catch (Exception e)
{ {
Log.Warn().WriteLine(e, "Non critical error: Couldn't get clipboard process, trying to use the title."); Log.Warn().WriteLine(e, "Non critical error: Couldn't get clipboard process, trying to use the title.");
@ -483,18 +481,16 @@ EndSelection:<<<<<<<4
var fileHeader = BitmapFileHeader.Create(infoHeader); var fileHeader = BitmapFileHeader.Create(infoHeader);
var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
using (var bitmapStream = new MemoryStream()) using var 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); var image = BitmapHelper.FromStream(bitmapStream);
var image = BitmapHelper.FromStream(bitmapStream); if (image != null)
if (image != null) {
{ return image;
return image; }
} }
}
}
else else
{ {
Log.Info().WriteLine("Using special DIBV5 / Format17 format reader"); Log.Info().WriteLine("Using special DIBV5 / Format17 format reader");

View file

@ -326,8 +326,9 @@ namespace Greenshot.Addons.Core.Credentials
info.pszCaptionText = Caption; info.pszCaptionText = Caption;
info.pszMessageText = Message; info.pszMessageText = Message;
if (Banner != null) if (Banner != null)
{ {
info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); using var bitmap = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight);
info.hbmBanner = bitmap.GetHbitmap();
} }
info.cbSize = Marshal.SizeOf(info); info.cbSize = Marshal.SizeOf(info);
return info; return info;
@ -380,36 +381,21 @@ namespace Greenshot.Addons.Core.Credentials
/// <summary>Returns a DialogResult from the specified code.</summary> /// <summary>Returns a DialogResult from the specified code.</summary>
/// <param name="code">The credential return code.</param> /// <param name="code">The credential return code.</param>
private DialogResult GetDialogResult(CredUiReturnCodes code) private DialogResult GetDialogResult(CredUiReturnCodes code) =>
{ code switch
DialogResult result; {
switch (code) CredUiReturnCodes.NoError => DialogResult.OK,
{ CredUiReturnCodes.ErrorCancelled => DialogResult.Cancel,
case CredUiReturnCodes.NoError: CredUiReturnCodes.ErrorNoSuchLogonSession => throw new ApplicationException("No such logon session."),
result = DialogResult.OK; CredUiReturnCodes.ErrorNotFound => throw new ApplicationException("Not found."),
break; CredUiReturnCodes.ErrorInvalidAccountName => throw new ApplicationException("Invalid account name."),
case CredUiReturnCodes.ErrorCancelled: CredUiReturnCodes.ErrorInsufficientBuffer => throw new ApplicationException("Insufficient buffer."),
result = DialogResult.Cancel; CredUiReturnCodes.ErrorInvalidParameter => throw new ApplicationException("Invalid parameter."),
break; CredUiReturnCodes.ErrorInvalidFlags => throw new ApplicationException("Invalid flags."),
case CredUiReturnCodes.ErrorNoSuchLogonSession: _ => throw new ApplicationException("Unknown credential result encountered.")
throw new ApplicationException("No such logon session."); };
case CredUiReturnCodes.ErrorNotFound:
throw new ApplicationException("Not found.");
case CredUiReturnCodes.ErrorInvalidAccountName:
throw new ApplicationException("Invalid account name.");
case CredUiReturnCodes.ErrorInsufficientBuffer:
throw new ApplicationException("Insufficient buffer.");
case CredUiReturnCodes.ErrorInvalidParameter:
throw new ApplicationException("Invalid parameter.");
case CredUiReturnCodes.ErrorInvalidFlags:
throw new ApplicationException("Invalid flags.");
default:
throw new ApplicationException("Unknown credential result encountered.");
}
return result;
}
/// <summary> /// <summary>
/// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp
/// </summary> /// </summary>

View file

@ -56,12 +56,10 @@ namespace Greenshot.Addons.Core
/// </summary> /// </summary>
/// <returns>bool</returns> /// <returns>bool</returns>
public static bool HasMapi() public static bool HasMapi()
{ {
using (var key = Registry.LocalMachine.OpenSubKey(MapiLocationKey, false)) using var key = Registry.LocalMachine.OpenSubKey(MapiLocationKey, false);
{ return key != null && "1".Equals(key.GetValue(MapiKey, "0"));
return key != null && "1".Equals(key.GetValue(MapiKey, "0")); }
}
}
/// <summary> /// <summary>
/// Get the path of Outlook from the registry /// Get the path of Outlook from the registry

View file

@ -67,12 +67,10 @@ namespace Greenshot.Addons.Core
UseShellExecute = true UseShellExecute = true
}; };
// Start the explorer process and select the file // Start the explorer process and select the file
using (var explorer = Process.Start(processStartInfo)) using var explorer = Process.Start(processStartInfo);
{ explorer?.WaitForInputIdle(500);
explorer?.WaitForInputIdle(500); return true;
return true; }
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -96,7 +96,7 @@ namespace Greenshot.Addons.Core
// Set the text // Set the text
var byteString = Encoding.ASCII.GetBytes(text + " "); var byteString = Encoding.ASCII.GetBytes(text + " ");
// Set Zero byte for String end. // Set Zero byte for String end.
byteString[byteString.Length - 1] = 0; byteString[^1] = 0;
propertyItem.Value = byteString; propertyItem.Value = byteString;
propertyItem.Len = text.Length + 1; propertyItem.Len = text.Length + 1;
} }
@ -128,7 +128,7 @@ namespace Greenshot.Addons.Core
if (CoreConfiguration.OutputFilePromptQuality) if (CoreConfiguration.OutputFilePromptQuality)
{ {
// TODO: Use factory // TODO: Use factory
var qualityDialog = new QualityDialog(outputSettings, CoreConfiguration, GreenshotLanguage); using var qualityDialog = new QualityDialog(outputSettings, CoreConfiguration, GreenshotLanguage);
qualityDialog.ShowDialog(); qualityDialog.ShowDialog();
} }
// TODO: For now we always overwrite, should be changed // TODO: For now we always overwrite, should be changed
@ -309,25 +309,19 @@ namespace Greenshot.Addons.Core
} }
var imageStream = new MemoryStream(); var imageStream = new MemoryStream();
if (bitmap.Width == size && bitmap.Height == size) if (bitmap.Width == size && bitmap.Height == size)
{ {
using (var clonedImage = bitmap.CloneBitmap(PixelFormat.Format32bppArgb)) using var clonedImage = bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
{ clonedImage.NativeBitmap.Save(imageStream, ImageFormat.Png);
clonedImage.NativeBitmap.Save(imageStream, ImageFormat.Png); imageSizes.Add(new Size(size, size));
imageSizes.Add(new Size(size, size)); }
}
}
else else
{ {
// Resize to the specified size, first make sure the image is 32bpp // Resize to the specified size, first make sure the image is 32bpp
using (var clonedImage = bitmap.CloneBitmap(PixelFormat.Format32bppArgb)) using var clonedImage = bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
{ using var resizedImage = clonedImage.Resize(true, true, Color.Empty, size, size, null);
using (var resizedImage = clonedImage.Resize(true, true, Color.Empty, size, size, null)) resizedImage.NativeBitmap.Save(imageStream, ImageFormat.Png);
{ imageSizes.Add(resizedImage.Size);
resizedImage.NativeBitmap.Save(imageStream, ImageFormat.Png); }
imageSizes.Add(resizedImage.Size);
}
}
}
imageStream.Seek(0, SeekOrigin.Begin); imageStream.Seek(0, SeekOrigin.Begin);
encodedImages.Add(imageStream); encodedImages.Add(imageStream);
@ -395,13 +389,11 @@ namespace Greenshot.Addons.Core
Log.Info().WriteLine("Greenshot file format: {0}", greenshotMarker); Log.Info().WriteLine("Greenshot file format: {0}", greenshotMarker);
const int filesizeLocation = 8 + markerSize; const int filesizeLocation = 8 + markerSize;
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
using (var reader = new BinaryReader(surfaceFileStream)) using var reader = new BinaryReader(surfaceFileStream);
{ var bytesWritten = reader.ReadInt64();
var bytesWritten = reader.ReadInt64(); surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); returnSurface.LoadElementsFromStream(surfaceFileStream);
returnSurface.LoadElementsFromStream(surfaceFileStream); }
}
}
if (fileImage == null) if (fileImage == null)
{ {
return returnSurface; return returnSurface;
@ -566,20 +558,16 @@ namespace Greenshot.Addons.Core
// Output the surface elements, size and marker to the stream // Output the surface elements, size and marker to the stream
if (outputSettings.Format == OutputFormats.greenshot) if (outputSettings.Format == OutputFormats.greenshot)
{ {
using (var tmpStream = new MemoryStream()) using var tmpStream = new MemoryStream();
{ var bytesWritten = surface.SaveElementsToStream(tmpStream);
var bytesWritten = surface.SaveElementsToStream(tmpStream); using var writer = new BinaryWriter(tmpStream);
using (var writer = new BinaryWriter(tmpStream)) writer.Write(bytesWritten);
{ var v = Assembly.GetExecutingAssembly().GetName().Version;
writer.Write(bytesWritten); var marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
var v = Assembly.GetExecutingAssembly().GetName().Version; writer.Write(marker);
var marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); tmpStream.WriteTo(stream);
writer.Write(marker); }
tmpStream.WriteTo(stream);
}
}
}
} }
finally finally
{ {
@ -630,28 +618,26 @@ namespace Greenshot.Addons.Core
RedirectStandardError = true, RedirectStandardError = true,
UseShellExecute = true UseShellExecute = true
}; };
using (var process = Process.Start(processStartInfo)) using var process = Process.Start(processStartInfo);
{ if (process != null)
if (process != null) {
{ process.WaitForExit();
process.WaitForExit(); if (process.ExitCode == 0)
if (process.ExitCode == 0) {
{ if (Log.IsDebugEnabled())
if (Log.IsDebugEnabled()) {
{ Log.Debug().WriteLine("File size after processing {0}", new FileInfo(tmpFileName).Length);
Log.Debug().WriteLine("File size after processing {0}", new FileInfo(tmpFileName).Length); Log.Debug().WriteLine("Reading back tmp file: {0}", tmpFileName);
Log.Debug().WriteLine("Reading back tmp file: {0}", tmpFileName); }
} var processedImage = File.ReadAllBytes(tmpFileName);
var processedImage = File.ReadAllBytes(tmpFileName); targetStream.Write(processedImage, 0, processedImage.Length);
targetStream.Write(processedImage, 0, processedImage.Length); return true;
return true; }
} Log.Error().WriteLine("Error while processing PNG image: {0}", process.ExitCode);
Log.Error().WriteLine("Error while processing PNG image: {0}", process.ExitCode); Log.Error().WriteLine("Output: {0}", process.StandardOutput.ReadToEnd());
Log.Error().WriteLine("Output: {0}", process.StandardOutput.ReadToEnd()); Log.Error().WriteLine("Error: {0}", process.StandardError.ReadToEnd());
Log.Error().WriteLine("Error: {0}", process.StandardError.ReadToEnd()); }
} }
}
}
catch (Exception e) catch (Exception e)
{ {
Log.Error().WriteLine(e, "Error while processing PNG image: "); Log.Error().WriteLine(e, "Error while processing PNG image: ");
@ -721,33 +707,31 @@ namespace Greenshot.Addons.Core
} }
var isAlpha = Image.IsAlphaPixelFormat(bitmapToSave.PixelFormat); var isAlpha = Image.IsAlphaPixelFormat(bitmapToSave.PixelFormat);
if (outputSettings.ReduceColors || !isAlpha && CoreConfiguration.OutputFileAutoReduceColors) if (outputSettings.ReduceColors || !isAlpha && CoreConfiguration.OutputFileAutoReduceColors)
{ {
using (var quantizer = new WuQuantizer(bitmapToSave)) using var quantizer = new WuQuantizer(bitmapToSave);
{ var colorCount = quantizer.GetColorCount();
var colorCount = quantizer.GetColorCount(); Log.Info().WriteLine("Image with format {0} has {1} colors", bitmapToSave.PixelFormat, colorCount);
Log.Info().WriteLine("Image with format {0} has {1} colors", bitmapToSave.PixelFormat, colorCount); if (!outputSettings.ReduceColors && colorCount >= 256)
if (!outputSettings.ReduceColors && colorCount >= 256) {
{ return disposeImage;
return disposeImage; }
} try
try {
{ Log.Info().WriteLine("Reducing colors on bitmap to 256.");
Log.Info().WriteLine("Reducing colors on bitmap to 256."); tmpBitmap = quantizer.GetQuantizedImage(CoreConfiguration.OutputFileReduceColorsTo);
tmpBitmap = quantizer.GetQuantizedImage(CoreConfiguration.OutputFileReduceColorsTo); if (disposeImage)
if (disposeImage) {
{ bitmapToSave.Dispose();
bitmapToSave.Dispose(); }
} bitmapToSave = tmpBitmap;
bitmapToSave = tmpBitmap; // Make sure the "new" image is disposed
// Make sure the "new" image is disposed disposeImage = true;
disposeImage = true; }
} catch (Exception e)
catch (Exception e) {
{ Log.Warn().WriteLine(e, "Error occurred while Quantizing the image, ignoring and using original. Error: ");
Log.Warn().WriteLine(e, "Error occurred while Quantizing the image, ignoring and using original. Error: "); }
} }
}
}
else if (isAlpha && !outputSettings.ReduceColors) else if (isAlpha && !outputSettings.ReduceColors)
{ {
Log.Info().WriteLine("Skipping 'optional' color reduction as the image has alpha"); Log.Info().WriteLine("Skipping 'optional' color reduction as the image has alpha");
@ -837,14 +821,12 @@ namespace Greenshot.Addons.Core
// TODO: This should not be done here, remove this!! // TODO: This should not be done here, remove this!!
if (copyPathToClipboard) if (copyPathToClipboard)
{ {
using (var clipboardAccessToken = ClipboardNative.Access()) using var clipboardAccessToken = ClipboardNative.Access();
{ clipboardAccessToken.ClearContents();
clipboardAccessToken.ClearContents(); // TODO: File??
// TODO: File?? clipboardAccessToken.SetAsUnicodeString(fullPath);
clipboardAccessToken.SetAsUnicodeString(fullPath); }
}
}
} }
/// <summary> /// <summary>

View file

@ -187,36 +187,34 @@ namespace Greenshot.Addons.Core
{ {
// Assume using it's own location // Assume using it's own location
formLocation = windowRectangle.Location; formLocation = windowRectangle.Location;
using (var workingArea = new Region(Screen.PrimaryScreen.Bounds)) using var workingArea = new Region(Screen.PrimaryScreen.Bounds);
// Find the screen where the window is and check if it fits
foreach (var screen in Screen.AllScreens)
{ {
// Find the screen where the window is and check if it fits if (!Equals(screen, Screen.PrimaryScreen))
{
workingArea.Union(screen.Bounds);
}
}
// If the formLocation is not inside the visible area
if (!workingArea.AreRectangleCornersVisisble(windowRectangle))
{
// If none found we find the biggest screen
foreach (var screen in Screen.AllScreens) foreach (var screen in Screen.AllScreens)
{ {
if (!Equals(screen, Screen.PrimaryScreen)) var newWindowRectangle = new NativeRect(screen.WorkingArea.Location, windowRectangle.Size);
if (workingArea.AreRectangleCornersVisisble(newWindowRectangle))
{ {
workingArea.Union(screen.Bounds); formLocation = screen.Bounds.Location;
doesCaptureFit = true;
break;
} }
} }
}
// If the formLocation is not inside the visible area else
if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) {
{ doesCaptureFit = true;
// If none found we find the biggest screen
foreach (var screen in Screen.AllScreens)
{
var newWindowRectangle = new NativeRect(screen.WorkingArea.Location, windowRectangle.Size);
if (workingArea.AreRectangleCornersVisisble(newWindowRectangle))
{
formLocation = screen.Bounds.Location;
doesCaptureFit = true;
break;
}
}
}
else
{
doesCaptureFit = true;
}
} }
} }
else if (!WindowsVersion.IsWindows8OrLater) else if (!WindowsVersion.IsWindows8OrLater)
@ -251,13 +249,11 @@ namespace Greenshot.Addons.Core
if (!doesCaptureFit) if (!doesCaptureFit)
{ {
// if GDI is allowed.. (a screenshot won't be better than we comes if we continue) // if GDI is allowed.. (a screenshot won't be better than we comes if we continue)
using (var thisWindowProcess = Process.GetProcessById(interopWindow.GetProcessId())) using var thisWindowProcess = Process.GetProcessById(interopWindow.GetProcessId());
if (!interopWindow.IsApp() && WindowCapture.IsGdiAllowed(thisWindowProcess))
{ {
if (!interopWindow.IsApp() && WindowCapture.IsGdiAllowed(thisWindowProcess)) // we return null which causes the capturing code to try another method.
{ return null;
// we return null which causes the capturing code to try another method.
return null;
}
} }
} }
} }
@ -289,25 +285,21 @@ namespace Greenshot.Addons.Core
try try
{ {
using (var whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle)) using var whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle);
// Apply a white color
tempForm.BackColor = Color.Black;
// Make sure everything is visible
tempForm.Refresh();
if (!interopWindow.IsApp())
{ {
// Apply a white color // Make sure the application window is active, so the colors & buttons are right
tempForm.BackColor = Color.Black; // TODO: Await?
// Make sure everything is visible interopWindow.ToForegroundAsync();
tempForm.Refresh();
if (!interopWindow.IsApp())
{
// Make sure the application window is active, so the colors & buttons are right
// TODO: Await?
interopWindow.ToForegroundAsync();
}
// Make sure all changes are processed and visible
Application.DoEvents();
using (var blackBitmap = WindowCapture.CaptureRectangle(captureRectangle))
{
capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap);
}
} }
// Make sure all changes are processed and visible
Application.DoEvents();
using var blackBitmap = WindowCapture.CaptureRectangle(captureRectangle);
capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap);
} }
catch (Exception e) catch (Exception e)
{ {
@ -400,17 +392,15 @@ namespace Greenshot.Addons.Core
/// <param name="image">The bitmap to remove the corners from.</param> /// <param name="image">The bitmap to remove the corners from.</param>
private static void RemoveCorners(IBitmapWithNativeSupport image) private static void RemoveCorners(IBitmapWithNativeSupport image)
{ {
using (var fastBitmap = FastBitmapFactory.Create(image)) using var fastBitmap = FastBitmapFactory.Create(image);
for (var y = 0; y < CoreConfiguration.WindowCornerCutShape.Count; y++)
{ {
for (var y = 0; y < CoreConfiguration.WindowCornerCutShape.Count; y++) for (var x = 0; x < CoreConfiguration.WindowCornerCutShape[y]; x++)
{ {
for (var x = 0; x < CoreConfiguration.WindowCornerCutShape[y]; x++) fastBitmap.SetColorAt(x, y, ref _transparentColor);
{ fastBitmap.SetColorAt(image.Width - 1 - x, y, ref _transparentColor);
fastBitmap.SetColorAt(x, y, ref _transparentColor); fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, ref _transparentColor);
fastBitmap.SetColorAt(image.Width - 1 - x, y, ref _transparentColor); fastBitmap.SetColorAt(x, image.Height - 1 - y, ref _transparentColor);
fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, ref _transparentColor);
fastBitmap.SetColorAt(x, image.Height - 1 - y, ref _transparentColor);
}
} }
} }
} }
@ -425,50 +415,46 @@ namespace Greenshot.Addons.Core
/// <returns>Bitmap with transparency</returns> /// <returns>Bitmap with transparency</returns>
private static IBitmapWithNativeSupport ApplyTransparency(IBitmapWithNativeSupport blackBitmap, IBitmapWithNativeSupport whiteBitmap) private static IBitmapWithNativeSupport ApplyTransparency(IBitmapWithNativeSupport blackBitmap, IBitmapWithNativeSupport whiteBitmap)
{ {
using (var targetBuffer = FastBitmapFactory.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent)) using var targetBuffer = FastBitmapFactory.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent);
targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution);
using (var blackBuffer = FastBitmapFactory.Create(blackBitmap))
{ {
targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); using var whiteBuffer = FastBitmapFactory.Create(whiteBitmap);
using (var blackBuffer = FastBitmapFactory.Create(blackBitmap)) for (var y = 0; y < blackBuffer.Height; y++)
{ {
using (var whiteBuffer = FastBitmapFactory.Create(whiteBitmap)) for (var x = 0; x < blackBuffer.Width; x++)
{ {
for (var y = 0; y < blackBuffer.Height; y++) var c0 = blackBuffer.GetColorAt(x, y);
var c1 = whiteBuffer.GetColorAt(x, y);
// Calculate alpha as double in range 0-1
var alpha = c0.R - c1.R + 255;
if (alpha == 255)
{ {
for (var x = 0; x < blackBuffer.Width; x++) // Alpha == 255 means no change!
{ targetBuffer.SetColorAt(x, y, ref c0);
var c0 = blackBuffer.GetColorAt(x, y); }
var c1 = whiteBuffer.GetColorAt(x, y); else if (alpha == 0)
// Calculate alpha as double in range 0-1 {
var alpha = c0.R - c1.R + 255; // Complete transparency, use transparent pixel
if (alpha == 255) targetBuffer.SetColorAt(x, y, ref _transparentColor);
{ }
// Alpha == 255 means no change! else
targetBuffer.SetColorAt(x, y, ref c0); {
} // Calculate original color
else if (alpha == 0) var originalAlpha = (byte) Math.Min(255, alpha);
{ var alphaFactor = alpha / 255d;
// Complete transparency, use transparent pixel //Log.Debug().WriteLine("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1);
targetBuffer.SetColorAt(x, y, ref _transparentColor); var originalRed = (byte) Math.Min(255, c0.R / alphaFactor);
} var originalGreen = (byte) Math.Min(255, c0.G / alphaFactor);
else var originalBlue = (byte) Math.Min(255, c0.B / alphaFactor);
{ var originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue);
// Calculate original color //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B);
var originalAlpha = (byte) Math.Min(255, alpha); targetBuffer.SetColorAt(x, y, ref originalColor);
var alphaFactor = alpha / 255d;
//Log.Debug().WriteLine("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1);
var originalRed = (byte) Math.Min(255, c0.R / alphaFactor);
var originalGreen = (byte) Math.Min(255, c0.G / alphaFactor);
var originalBlue = (byte) Math.Min(255, c0.B / alphaFactor);
var originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue);
//Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B);
targetBuffer.SetColorAt(x, y, ref originalColor);
}
}
} }
} }
} }
return targetBuffer.UnlockAndReturnBitmap();
} }
return targetBuffer.UnlockAndReturnBitmap();
} }
} }
} }

View file

@ -52,13 +52,11 @@ namespace Greenshot.Addons.Core
} }
IFormatter formatter = new BinaryFormatter(); IFormatter formatter = new BinaryFormatter();
using (var stream = new MemoryStream()) using var stream = new MemoryStream();
{ formatter.Serialize(stream, source);
formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin);
stream.Seek(0, SeekOrigin.Begin); return (T) formatter.Deserialize(stream);
return (T) formatter.Deserialize(stream); }
}
}
/// <summary> /// <summary>
/// Clone the content from source to destination /// Clone the content from source to destination

View file

@ -116,10 +116,8 @@ namespace Greenshot.Addons.Core
// Set the location // Set the location
capture.CursorLocation = new NativePoint(x, y); capture.CursorLocation = new NativePoint(x, y);
using (var icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) using var icon = Icon.FromHandle(safeIcon.DangerousGetHandle());
{ capture.Cursor = icon;
capture.Cursor = icon;
}
} }
} }
return capture; return capture;
@ -305,121 +303,113 @@ namespace Greenshot.Addons.Core
} }
// create a device context we can copy to // create a device context we can copy to
using (var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle)) using var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle);
// Check if the device context is there, if not throw an error with as much info as possible!
if (safeCompatibleDcHandle.IsInvalid)
{ {
// Check if the device context is there, if not throw an error with as much info as possible! // Get Exception before the error is lost
if (safeCompatibleDcHandle.IsInvalid) var exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
// throw exception
throw exceptionToThrow;
}
// Create BitmapInfoHeader for CreateDIBSection
var bmi = BitmapInfoHeader.Create(captureBounds.Width, captureBounds.Height, 24);
// TODO: Enable when the function is available again
// Make sure the last error is set to 0
Win32.SetLastError(0);
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
// the returned (out) IntPtr _ is not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
using var safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bmi, DibColors.PalColors, out _, IntPtr.Zero, 0);
if (safeDibSectionHandle.IsInvalid)
{
// Get Exception before the error is lost
var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());
// Throw so people can report the problem
throw exceptionToThrow;
}
// select the bitmap object and store the old handle
using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle))
{
// bit-blt over (make copy)
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
}
// get a .NET image object for it
// A suggestion for the "A generic error occurred in GDI+." E_FAIL/0x80004005 error is to re-try...
ExternalException exception = null;
for (var i = 0; i < 3; i++)
{
try
{ {
// Get Exception before the error is lost // Collect all screens inside this capture
var exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); var screensInsideCapture = new List<Screen>();
// throw exception foreach (var screen in Screen.AllScreens)
throw exceptionToThrow;
}
// Create BitmapInfoHeader for CreateDIBSection
var bmi = BitmapInfoHeader.Create(captureBounds.Width, captureBounds.Height, 24);
// TODO: Enable when the function is available again
// Make sure the last error is set to 0
Win32.SetLastError(0);
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
// the returned (out) IntPtr _ is not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
using (var safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bmi, DibColors.PalColors, out _, IntPtr.Zero, 0))
{
if (safeDibSectionHandle.IsInvalid)
{ {
// Get Exception before the error is lost if (screen.Bounds.IntersectsWith(captureBounds))
var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());
// Throw so people can report the problem
throw exceptionToThrow;
}
// select the bitmap object and store the old handle
using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle))
{
// bit-blt over (make copy)
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
}
// get a .NET image object for it
// A suggestion for the "A generic error occurred in GDI+." E_FAIL/0x80004005 error is to re-try...
ExternalException exception = null;
for (var i = 0; i < 3; i++)
{
try
{ {
// Collect all screens inside this capture screensInsideCapture.Add(screen);
var screensInsideCapture = new List<Screen>(); }
}
// Check all all screens are of an equal size
bool offscreenContent;
using (var captureRegion = new Region(captureBounds))
{
// Exclude every visible part
foreach (var screen in screensInsideCapture)
{
captureRegion.Exclude(screen.Bounds);
}
// If the region is not empty, we have "offscreenContent"
using var screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow());
offscreenContent = !captureRegion.IsEmpty(screenGraphics);
}
// Check if we need to have a transparent background, needed for offscreen content
if (offscreenContent)
{
using var tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle());
// Create a new bitmap which has a transparent background
var returnBitmap = new UnmanagedBitmap<Bgra32>(tmpBitmap.Width, tmpBitmap.Height, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
returnBitmap.Span.Fill(Color.Transparent.FromColorWithAlpha());
// Content will be copied here
using (var graphics = Graphics.FromImage(returnBitmap.NativeBitmap))
{
// For all screens copy the content to the new bitmap
foreach (var screen in Screen.AllScreens) foreach (var screen in Screen.AllScreens)
{ {
if (screen.Bounds.IntersectsWith(captureBounds)) // Make sure the bounds are with an offset to the capture bounds
{ var screenBounds = screen.Bounds;
screensInsideCapture.Add(screen); screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
} graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
} }
// Check all all screens are of an equal size }
bool offscreenContent;
using (var captureRegion = new Region(captureBounds))
{
// Exclude every visible part
foreach (var screen in screensInsideCapture)
{
captureRegion.Exclude(screen.Bounds);
}
// If the region is not empty, we have "offscreenContent"
using (var screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow()))
{
offscreenContent = !captureRegion.IsEmpty(screenGraphics);
}
}
// Check if we need to have a transparent background, needed for offscreen content
if (offscreenContent)
{
using (var tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()))
{
// Create a new bitmap which has a transparent background
var returnBitmap = new UnmanagedBitmap<Bgra32>(tmpBitmap.Width, tmpBitmap.Height, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
returnBitmap.Span.Fill(Color.Transparent.FromColorWithAlpha());
// Content will be copied here
using (var graphics = Graphics.FromImage(returnBitmap.NativeBitmap))
{
// For all screens copy the content to the new bitmap
foreach (var screen in Screen.AllScreens)
{
// Make sure the bounds are with an offset to the capture bounds
var screenBounds = screen.Bounds;
screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
}
}
return returnBitmap; return returnBitmap;
}
}
else
{
// All screens, which are inside the capture, are of equal size
// assign image to Capture, the image will be disposed there..
// TODO: Optimize?
return BitmapWrapper.FromBitmap(Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()));
}
}
catch (ExternalException ee)
{
Log.Warn().WriteLine(ee, "Problem getting bitmap at try " + i + " : ");
exception = ee;
}
} }
Log.Error().WriteLine(null, "Still couldn't create Bitmap!"); else
if (exception != null)
{ {
throw exception; // All screens, which are inside the capture, are of equal size
// assign image to Capture, the image will be disposed there..
// TODO: Optimize?
return BitmapWrapper.FromBitmap(Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()));
} }
} }
catch (ExternalException ee)
{
Log.Warn().WriteLine(ee, "Problem getting bitmap at try " + i + " : ");
exception = ee;
}
}
Log.Error().WriteLine(null, "Still couldn't create Bitmap!");
if (exception != null)
{
throw exception;
} }
} }

View file

@ -178,14 +178,12 @@ namespace Greenshot.Addons.Extensions
/// <param name="outputSettings">SurfaceOutputSettings specifying how to output the surface</param> /// <param name="outputSettings">SurfaceOutputSettings specifying how to output the surface</param>
public static void SetAsBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, SurfaceOutputSettings outputSettings) public static void SetAsBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, SurfaceOutputSettings outputSettings)
{ {
using (var bitmapStream = new MemoryStream()) using var bitmapStream = new MemoryStream();
{ ImageOutput.SaveToStream(surface, bitmapStream, outputSettings);
ImageOutput.SaveToStream(surface, bitmapStream, outputSettings); bitmapStream.Seek(0, SeekOrigin.Begin);
bitmapStream.Seek(0, SeekOrigin.Begin); // Set the stream
// Set the stream var clipboardFormat = ClipboardFormatExtensions.MapFormatToId(outputSettings.Format.ToString().ToUpperInvariant());
var clipboardFormat = ClipboardFormatExtensions.MapFormatToId(outputSettings.Format.ToString().ToUpperInvariant()); clipboardAccessToken.SetAsStream(clipboardFormat, bitmapStream);
clipboardAccessToken.SetAsStream(clipboardFormat, bitmapStream);
}
} }
/// <summary> /// <summary>
@ -196,39 +194,37 @@ namespace Greenshot.Addons.Extensions
public static void SetAsFormat17(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration) public static void SetAsFormat17(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration)
{ {
// Create the stream for the clipboard // Create the stream for the clipboard
using (var dibV5Stream = new MemoryStream()) using var dibV5Stream = new MemoryStream();
var outputSettings = new SurfaceOutputSettings(coreConfiguration, OutputFormats.bmp, 100, false);
bool dispose = ImageOutput.CreateBitmapFromSurface(surface, outputSettings, out var bitmapToSave);
// Create the BITMAPINFOHEADER
var header = BitmapInfoHeader.Create(bitmapToSave.Width, bitmapToSave.Height, 32);
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
header.Compression = BitmapCompressionMethods.BI_BITFIELDS;
var headerBytes = BinaryStructHelper.ToByteArray(header);
// Write the BITMAPINFOHEADER to the stream
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
// As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added
var colorMask = BitfieldColorMask.Create();
// Create the byte[] from the struct
var colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask);
Array.Reverse(colorMaskBytes);
// Write to the stream
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
// Create the raw bytes for the pixels only
var bitmapBytes = BitmapToByteArray(bitmapToSave);
// Write to the stream
dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length);
// Reset the stream to the beginning so it can be written
dibV5Stream.Seek(0, SeekOrigin.Begin);
// Set the DIBv5 to the clipboard DataObject
clipboardAccessToken.SetAsStream("Format17", dibV5Stream);
if (dispose)
{ {
var outputSettings = new SurfaceOutputSettings(coreConfiguration, OutputFormats.bmp, 100, false); bitmapToSave.Dispose();
bool dispose = ImageOutput.CreateBitmapFromSurface(surface, outputSettings, out var bitmapToSave);
// Create the BITMAPINFOHEADER
var header = BitmapInfoHeader.Create(bitmapToSave.Width, bitmapToSave.Height, 32);
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
header.Compression = BitmapCompressionMethods.BI_BITFIELDS;
var headerBytes = BinaryStructHelper.ToByteArray(header);
// Write the BITMAPINFOHEADER to the stream
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
// As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added
var colorMask = BitfieldColorMask.Create();
// Create the byte[] from the struct
var colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask);
Array.Reverse(colorMaskBytes);
// Write to the stream
dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length);
// Create the raw bytes for the pixels only
var bitmapBytes = BitmapToByteArray(bitmapToSave);
// Write to the stream
dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length);
// Reset the stream to the beginning so it can be written
dibV5Stream.Seek(0, SeekOrigin.Begin);
// Set the DIBv5 to the clipboard DataObject
clipboardAccessToken.SetAsStream("Format17", dibV5Stream);
if (dispose)
{
bitmapToSave.Dispose();
}
} }
} }
@ -269,13 +265,11 @@ namespace Greenshot.Addons.Extensions
/// <param name="surface">ISurface</param> /// <param name="surface">ISurface</param>
public static void SetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration) public static void SetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration)
{ {
using (var bitmapStream = new MemoryStream()) using var bitmapStream = new MemoryStream();
{ ImageOutput.SaveToStream(surface, bitmapStream, new SurfaceOutputSettings(coreConfiguration) {Format = OutputFormats.bmp});
ImageOutput.SaveToStream(surface, bitmapStream, new SurfaceOutputSettings(coreConfiguration) {Format = OutputFormats.bmp}); bitmapStream.Seek(Marshal.SizeOf(typeof(BitmapFileHeader)), SeekOrigin.Begin);
bitmapStream.Seek(Marshal.SizeOf(typeof(BitmapFileHeader)), SeekOrigin.Begin); // Set the stream
// Set the stream clipboardAccessToken.SetAsStream(StandardClipboardFormats.DeviceIndependentBitmap, bitmapStream);
clipboardAccessToken.SetAsStream(StandardClipboardFormats.DeviceIndependentBitmap, bitmapStream);
}
} }
} }
} }

View file

@ -155,15 +155,13 @@ EndSelection:<<<<<<<4
/// <param name="coreConfiguration">ICoreConfiguration</param> /// <param name="coreConfiguration">ICoreConfiguration</param>
public static void SetAsEmbeddedHtml(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration) public static void SetAsEmbeddedHtml(this IClipboardAccessToken clipboardAccessToken, ISurface surface, ICoreConfiguration coreConfiguration)
{ {
using (var pngStream = new MemoryStream()) using var pngStream = new MemoryStream();
{ var pngOutputSettings = new SurfaceOutputSettings(coreConfiguration, OutputFormats.png, 100, false);
var pngOutputSettings = new SurfaceOutputSettings(coreConfiguration, OutputFormats.png, 100, false); ImageOutput.SaveToStream(surface, pngStream, pngOutputSettings);
ImageOutput.SaveToStream(surface, pngStream, pngOutputSettings); pngStream.Seek(0, SeekOrigin.Begin);
pngStream.Seek(0, SeekOrigin.Begin); // Set the PNG stream
// Set the PNG stream var htmlText = GenerateHtmlDataUrlString(new NativeSize(surface.Width, surface.Height), pngStream);
var htmlText = GenerateHtmlDataUrlString(new NativeSize(surface.Width, surface.Height), pngStream); clipboardAccessToken.SetAsHtml(htmlText);
clipboardAccessToken.SetAsHtml(htmlText);
}
} }
/// <summary> /// <summary>

View file

@ -16,10 +16,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapplo.CaliburnMicro.Configuration" Version="2.1.3" /> <PackageReference Include="Dapplo.CaliburnMicro.Configuration" Version="2.1.4" />
<PackageReference Include="Dapplo.CaliburnMicro.Metro" Version="2.1.3" /> <PackageReference Include="Dapplo.CaliburnMicro.Metro" Version="2.1.4" />
<PackageReference Include="Dapplo.CaliburnMicro.Toasts" Version="2.1.3" /> <PackageReference Include="Dapplo.CaliburnMicro.Toasts" Version="2.1.4" />
<PackageReference Include="Dapplo.CaliburnMicro.Translations" Version="2.1.3" /> <PackageReference Include="Dapplo.CaliburnMicro.Translations" Version="2.1.4" />
<PackageReference Include="Dapplo.HttpExtensions" Version="0.10.7" /> <PackageReference Include="Dapplo.HttpExtensions" Version="0.10.7" />
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.7" /> <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.7" />
<PackageReference Include="Dapplo.HttpExtensions.OAuth" Version="0.10.7" /> <PackageReference Include="Dapplo.HttpExtensions.OAuth" Version="0.10.7" />
@ -27,9 +27,9 @@
<PackageReference Include="Dapplo.Windows.Clipboard" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows.Clipboard" Version="0.11.6" />
<PackageReference Include="Dapplo.Windows.Dpi" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows.Dpi" Version="0.11.6" />
<PackageReference Include="Dapplo.Windows.Icons" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows.Icons" Version="0.11.6" />
<PackageReference Include="gong-wpf-dragdrop" Version="2.1.0" /> <PackageReference Include="gong-wpf-dragdrop" Version="2.2.0" />
<PackageReference Include="MahApps.Metro.IconPacks" Version="3.0.0-alpha0223" /> <PackageReference Include="MahApps.Metro.IconPacks" Version="3.0.0" />
<PackageReference Include="Svg" Version="3.0.49" /> <PackageReference Include="Svg" Version="3.0.84" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -47,11 +47,9 @@ namespace Greenshot.Addons.Resources
/// </summary> /// </summary>
/// <returns>BitmapSource</returns> /// <returns>BitmapSource</returns>
public BitmapSource GreenshotIconAsBitmapSource() public BitmapSource GreenshotIconAsBitmapSource()
{ {
using (var icon = GetGreenshotIcon()) using var icon = GetGreenshotIcon();
{ return icon.ToBitmapSource();
return icon.ToBitmapSource();
}
} }
/// <summary> /// <summary>
@ -70,12 +68,10 @@ namespace Greenshot.Addons.Resources
/// <param name="type">Type</param> /// <param name="type">Type</param>
/// <returns>Icon</returns> /// <returns>Icon</returns>
public Icon GetIcon(string name, Type type = null) public Icon GetIcon(string name, Type type = null)
{ {
using (var iconStream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", $"{name}.Icon.ico")) using var iconStream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", $"{name}.Icon.ico");
{ return new Icon(iconStream);
return new Icon(iconStream); }
}
}
/// <summary> /// <summary>
/// Get the Greenshot logo as a Bitmap /// Get the Greenshot logo as a Bitmap
@ -99,11 +95,10 @@ namespace Greenshot.Addons.Resources
name += ".png"; name += ".png";
} }
using (var imageStream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", name))
{ using var imageStream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", name);
return BitmapHelper.FromStream(imageStream); return BitmapHelper.FromStream(imageStream);
} }
}
/// <summary> /// <summary>
/// Get a byte[] from an embedded resource /// Get a byte[] from an embedded resource
@ -113,12 +108,10 @@ namespace Greenshot.Addons.Resources
/// <returns>bate[]</returns> /// <returns>bate[]</returns>
public byte[] GetBytes(string name, Type type = null) public byte[] GetBytes(string name, Type type = null)
{ {
using (var stream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", name)) using var stream = _resourceProvider.ResourceAsStream((type ?? GetType()).Assembly, "Resources", name);
using (var memoryStream = new MemoryStream()) using var memoryStream = new MemoryStream();
{ stream.CopyTo(memoryStream);
stream.CopyTo(memoryStream); return memoryStream.ToArray();
return memoryStream.ToArray();
}
} }
} }
} }

View file

@ -63,10 +63,8 @@ namespace Greenshot.Addons.ViewModels
Information = exportInformation; Information = exportInformation;
Source = source; Source = source;
using (var bitmap = exportedSurface.GetBitmapForExport()) using var bitmap = exportedSurface.GetBitmapForExport();
{ ExportBitmapSource = bitmap.NativeBitmap.ToBitmapSource();
ExportBitmapSource = bitmap.NativeBitmap.ToBitmapSource();
}
} }
/// <summary> /// <summary>

View file

@ -112,17 +112,17 @@ namespace Greenshot.Addons.ViewModels
/// </summary> /// </summary>
public void SelectOutputPath() public void SelectOutputPath()
{ {
using (var folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog()) using var folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog
{ {
// Get the storage location and replace the environment variables SelectedPath = FilenameHelper.FillVariables(CoreConfiguration.OutputFilePath, false)
folderBrowserDialog.SelectedPath = FilenameHelper.FillVariables(CoreConfiguration.OutputFilePath, false); };
if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) // Get the storage location and replace the environment variables
if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Only change if there is a change, otherwise we might overwrite the environment variables
if (folderBrowserDialog.SelectedPath != null && !folderBrowserDialog.SelectedPath.Equals(FilenameHelper.FillVariables(CoreConfiguration.OutputFilePath, false)))
{ {
// Only change if there is a change, otherwise we might overwrite the environment variables CoreConfiguration.OutputFilePath = folderBrowserDialog.SelectedPath;
if (folderBrowserDialog.SelectedPath != null && !folderBrowserDialog.SelectedPath.Equals(FilenameHelper.FillVariables(CoreConfiguration.OutputFilePath, false)))
{
CoreConfiguration.OutputFilePath = folderBrowserDialog.SelectedPath;
}
} }
} }
} }

View file

@ -166,36 +166,34 @@ namespace Greenshot.Core.Extensions
{ {
// Assume using it's own location // Assume using it's own location
formLocation = windowRectangle.Location; formLocation = windowRectangle.Location;
using (var workingArea = new Region()) using var workingArea = new Region();
// Find the screen where the window is and check if it fits
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{ {
// Find the screen where the window is and check if it fits workingArea.Union(displayInfo.WorkingArea);
}
// If the formLocation is not inside the visible area
if (!workingArea.AreRectangleCornersVisisble(windowRectangle))
{
// If none found we find the biggest screen
foreach (var displayInfo in DisplayInfo.AllDisplayInfos) foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{ {
workingArea.Union(displayInfo.WorkingArea); var newWindowRectangle = new NativeRect(displayInfo.WorkingArea.Location, windowRectangle.Size);
} if (!workingArea.AreRectangleCornersVisisble(newWindowRectangle))
// If the formLocation is not inside the visible area
if (!workingArea.AreRectangleCornersVisisble(windowRectangle))
{
// If none found we find the biggest screen
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{ {
var newWindowRectangle = new NativeRect(displayInfo.WorkingArea.Location, windowRectangle.Size); continue;
if (!workingArea.AreRectangleCornersVisisble(newWindowRectangle))
{
continue;
}
formLocation = displayInfo.Bounds.Location;
doesCaptureFit = true;
break;
} }
}
else formLocation = displayInfo.Bounds.Location;
{
doesCaptureFit = true; doesCaptureFit = true;
break;
} }
} }
else
{
doesCaptureFit = true;
}
} }
else if (!WindowsVersion.IsWindows8OrLater) else if (!WindowsVersion.IsWindows8OrLater)
{ {
@ -229,13 +227,11 @@ namespace Greenshot.Core.Extensions
if (!doesCaptureFit) if (!doesCaptureFit)
{ {
// if GDI is allowed.. (a screenshot won't be better than we comes if we continue) // if GDI is allowed.. (a screenshot won't be better than we comes if we continue)
using (var thisWindowProcess = Process.GetProcessById(interopWindow.GetProcessId())) using var thisWindowProcess = Process.GetProcessById(interopWindow.GetProcessId());
if (!interopWindow.IsApp() && IsGdiAllowed(thisWindowProcess, captureConfiguration))
{ {
if (!interopWindow.IsApp() && IsGdiAllowed(thisWindowProcess, captureConfiguration)) // we return null which causes the capturing code to try another method.
{ return null;
// we return null which causes the capturing code to try another method.
return null;
}
} }
} }
} }

View file

@ -95,85 +95,79 @@ namespace Greenshot.Core.Sources
} }
// create a device context we can copy to // create a device context we can copy to
using (var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle)) using var safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle);
// Check if the device context is there, if not throw an error with as much info as possible!
if (safeCompatibleDcHandle.IsInvalid)
{ {
// Check if the device context is there, if not throw an error with as much info as possible! // Get Exception before the error is lost
if (safeCompatibleDcHandle.IsInvalid) var exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
// throw exception
throw exceptionToThrow;
}
// Create BITMAPINFOHEADER for CreateDIBSection
var bmi = BitmapInfoHeader.Create(captureBounds.Width, captureBounds.Height, 24);
// Make sure the last error is set to 0
Win32.SetLastError(0);
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
using var safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bmi, 0, out var _, IntPtr.Zero, 0);
if (safeDibSectionHandle.IsInvalid)
{
// Get Exception before the error is lost
var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());
// Throw so people can report the problem
throw exceptionToThrow;
}
// select the bitmap object and store the old handle
using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle))
{
// bitblt over (make copy)
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
}
// Create BitmapSource from the DibSection
capturedBitmapSource = Imaging.CreateBitmapSourceFromHBitmap(safeDibSectionHandle.DangerousGetHandle(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
// Now cut away invisible parts
// Collect all screens inside this capture
var displaysInsideCapture = new List<DisplayInfo>();
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{
if (displayInfo.Bounds.IntersectsWith(captureBounds))
{ {
// Get Exception before the error is lost displaysInsideCapture.Add(displayInfo);
var exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds);
// throw exception
throw exceptionToThrow;
} }
// Create BITMAPINFOHEADER for CreateDIBSection }
var bmi = BitmapInfoHeader.Create(captureBounds.Width, captureBounds.Height, 24); // Check all all screens are of an equal size
bool offscreenContent;
// Make sure the last error is set to 0 using (var captureRegion = new Region(captureBounds))
Win32.SetLastError(0); {
// Exclude every visible part
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height foreach (var displayInfo in displaysInsideCapture)
using (var safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bmi, 0, out var _, IntPtr.Zero, 0))
{ {
if (safeDibSectionHandle.IsInvalid) captureRegion.Exclude(displayInfo.Bounds);
{
// Get Exception before the error is lost
var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds);
exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32());
exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32());
// Throw so people can report the problem
throw exceptionToThrow;
}
// select the bitmap object and store the old handle
using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle))
{
// bitblt over (make copy)
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
}
// Create BitmapSource from the DibSection
capturedBitmapSource = Imaging.CreateBitmapSourceFromHBitmap(safeDibSectionHandle.DangerousGetHandle(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
// Now cut away invisible parts
// Collect all screens inside this capture
var displaysInsideCapture = new List<DisplayInfo>();
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{
if (displayInfo.Bounds.IntersectsWith(captureBounds))
{
displaysInsideCapture.Add(displayInfo);
}
}
// Check all all screens are of an equal size
bool offscreenContent;
using (var captureRegion = new Region(captureBounds))
{
// Exclude every visible part
foreach (var displayInfo in displaysInsideCapture)
{
captureRegion.Exclude(displayInfo.Bounds);
}
// If the region is not empty, we have "offscreenContent"
using (var screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow()))
{
offscreenContent = !captureRegion.IsEmpty(screenGraphics);
}
}
// Check if we need to have a transparent background, needed for offscreen content
if (offscreenContent)
{
var modifiedImage = new WriteableBitmap(capturedBitmapSource.PixelWidth, capturedBitmapSource.PixelHeight, capturedBitmapSource.DpiX, capturedBitmapSource.DpiY, PixelFormats.Bgr32, capturedBitmapSource.Palette);
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{
modifiedImage.CopyPixels(capturedBitmapSource, displayInfo.Bounds);
}
capturedBitmapSource = modifiedImage;
}
} }
// If the region is not empty, we have "offscreenContent"
using var screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow());
offscreenContent = !captureRegion.IsEmpty(screenGraphics);
}
// Check if we need to have a transparent background, needed for offscreen content
if (offscreenContent)
{
var modifiedImage = new WriteableBitmap(capturedBitmapSource.PixelWidth, capturedBitmapSource.PixelHeight, capturedBitmapSource.DpiX, capturedBitmapSource.DpiY, PixelFormats.Bgr32, capturedBitmapSource.Palette);
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
{
modifiedImage.CopyPixels(capturedBitmapSource, displayInfo.Bounds);
}
capturedBitmapSource = modifiedImage;
} }
} }
var result = new CaptureElement<BitmapSource>(captureBounds.Location, capturedBitmapSource) var result = new CaptureElement<BitmapSource>(captureBounds.Location, capturedBitmapSource)

View file

@ -171,22 +171,20 @@ namespace Greenshot.Gfx
// Make sure both images have the same resolution // Make sure both images have the same resolution
newImage.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); newImage.SetResolution(sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution);
using (var graphics = Graphics.FromImage(newImage)) using var graphics = Graphics.FromImage(newImage);
if (fromTransparentToNon)
{ {
if (fromTransparentToNon) // Rule 2: Make sure the background color is white
{ graphics.Clear(Color.White);
// Rule 2: Make sure the background color is white }
graphics.Clear(Color.White); // decide fastest copy method
} if (isAreaEqual)
// decide fastest copy method {
if (isAreaEqual) graphics.DrawImageUnscaled(sourceBitmap.NativeBitmap, 0, 0);
{ }
graphics.DrawImageUnscaled(sourceBitmap.NativeBitmap, 0, 0); else
} {
else graphics.DrawImage(sourceBitmap.NativeBitmap, 0, 0, sourceRect, GraphicsUnit.Pixel);
{
graphics.DrawImage(sourceBitmap.NativeBitmap, 0, 0, sourceRect, GraphicsUnit.Pixel);
}
} }
} }
else else

View file

@ -462,13 +462,11 @@ namespace Greenshot.Gfx
graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// draw original with a TextureBrush so we have nice anti-aliasing! // draw original with a TextureBrush so we have nice anti-aliasing!
using (Brush textureBrush = new TextureBrush(sourceBitmap.NativeBitmap, WrapMode.Clamp)) using Brush textureBrush = new TextureBrush(sourceBitmap.NativeBitmap, WrapMode.Clamp);
{ // We need to do a translate-transform otherwise the image is wrapped
// We need to do a translate-transform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y);
graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height);
graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); }
}
}
return returnImage; return returnImage;
} }
@ -491,14 +489,12 @@ namespace Greenshot.Gfx
/// <param name="dest">Image to copy to</param> /// <param name="dest">Image to copy to</param>
/// <param name="colorMatrix">ColorMatrix to apply</param> /// <param name="colorMatrix">ColorMatrix to apply</param>
public static void ApplyColorMatrix(this IBitmapWithNativeSupport source, NativeRect sourceRect, IBitmapWithNativeSupport dest, NativeRect destRect, ColorMatrix colorMatrix) public static void ApplyColorMatrix(this IBitmapWithNativeSupport source, NativeRect sourceRect, IBitmapWithNativeSupport dest, NativeRect destRect, ColorMatrix colorMatrix)
{ {
using (var imageAttributes = new ImageAttributes()) using var imageAttributes = new ImageAttributes();
{ imageAttributes.ClearColorMatrix();
imageAttributes.ClearColorMatrix(); imageAttributes.SetColorMatrix(colorMatrix);
imageAttributes.SetColorMatrix(colorMatrix); source.ApplyImageAttributes(sourceRect, dest, destRect, imageAttributes);
source.ApplyImageAttributes(sourceRect, dest, destRect, imageAttributes); }
}
}
/// <summary> /// <summary>
/// Apply image attributes to the image /// Apply image attributes to the image
@ -532,18 +528,17 @@ namespace Greenshot.Gfx
{ {
destRect = new NativeRect(0, 0, dest.Width, dest.Height); destRect = new NativeRect(0, 0, dest.Width, dest.Height);
} }
using (var graphics = Graphics.FromImage(dest.NativeBitmap))
{
// Make sure we draw with the best quality!
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.DrawImage(source.NativeBitmap, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); using var graphics = Graphics.FromImage(dest.NativeBitmap);
} // Make sure we draw with the best quality!
} graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.DrawImage(source.NativeBitmap, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes);
}
/// <summary> /// <summary>
/// Checks if the supplied Bitmap has a PixelFormat we support /// Checks if the supplied Bitmap has a PixelFormat we support
@ -712,12 +707,10 @@ namespace Greenshot.Gfx
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = interpolationMode; graphics.InterpolationMode = interpolationMode;
using (var wrapMode = new ImageAttributes()) using var wrapMode = new ImageAttributes();
{ wrapMode.SetWrapMode(WrapMode.TileFlipXY);
wrapMode.SetWrapMode(WrapMode.TileFlipXY); graphics.DrawImage(sourceImage.NativeBitmap, new NativeRect(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode);
graphics.DrawImage(sourceImage.NativeBitmap, new NativeRect(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); }
}
}
return newBitmap; return newBitmap;
} }
@ -737,35 +730,34 @@ namespace Greenshot.Gfx
{ {
toCount = toCount & 0xffffff; toCount = toCount & 0xffffff;
} }
using (var bb = FastBitmapFactory.Create(sourceImage))
{
Parallel.For(0, bb.Height, () => 0, (y, state, initialColorCount) =>
{
var currentColors = initialColorCount;
for (var x = 0; x < bb.Width; x++)
{
var bitmapcolor = bb.GetColorAt(x, y).ToArgb();
if (!includeAlpha)
{
bitmapcolor = bitmapcolor & 0xffffff;
}
if (bitmapcolor == toCount)
{
currentColors++;
}
}
return currentColors;
}, lineColorCount =>
{
lock (lockObject)
{
colors += lineColorCount;
}
});
return colors; using var bb = FastBitmapFactory.Create(sourceImage);
} Parallel.For(0, bb.Height, () => 0, (y, state, initialColorCount) =>
} {
var currentColors = initialColorCount;
for (var x = 0; x < bb.Width; x++)
{
var bitmapcolor = bb.GetColorAt(x, y).ToArgb();
if (!includeAlpha)
{
bitmapcolor = bitmapcolor & 0xffffff;
}
if (bitmapcolor == toCount)
{
currentColors++;
}
}
return currentColors;
}, lineColorCount =>
{
lock (lockObject)
{
colors += lineColorCount;
}
});
return colors;
}
/// <summary> /// <summary>
/// Create an image from a stream, if an extension is supplied more formats are supported. /// Create an image from a stream, if an extension is supplied more formats are supported.
@ -833,12 +825,10 @@ namespace Greenshot.Gfx
return original.Scale3X(); return original.Scale3X();
} }
if (width == original.Width * 4) if (width == original.Width * 4)
{ {
using (var scale2X = original.Scale2X()) using var scale2X = original.Scale2X();
{ return scale2X.Scale2X();
return scale2X.Scale2X(); }
}
}
return original.Resize(true, width, width, interpolationMode: InterpolationMode.NearestNeighbor); return original.Resize(true, width, width, interpolationMode: InterpolationMode.NearestNeighbor);
} }
@ -865,30 +855,31 @@ namespace Greenshot.Gfx
} }
bool result = true; bool result = true;
using (var fastBitmap1 = FastBitmapFactory.Create(bitmap1)) using (var fastBitmap1 = FastBitmapFactory.Create(bitmap1))
using (var fastBitmap2 = FastBitmapFactory.Create(bitmap2)) {
{ using var fastBitmap2 = FastBitmapFactory.Create(bitmap2);
Parallel.For(0, fastBitmap1.Height, (y, state) => Parallel.For(0, fastBitmap1.Height, (y, state) =>
{ {
unsafe unsafe
{ {
var tmpColor1 = stackalloc byte[4]; var tmpColor1 = stackalloc byte[4];
var tmpColor2 = stackalloc byte[4]; var tmpColor2 = stackalloc byte[4];
for (int x = 0; x < fastBitmap1.Width; x++) for (int x = 0; x < fastBitmap1.Width; x++)
{ {
fastBitmap1.GetColorAt(x, y, tmpColor1); fastBitmap1.GetColorAt(x, y, tmpColor1);
fastBitmap2.GetColorAt(x, y, tmpColor2); fastBitmap2.GetColorAt(x, y, tmpColor2);
if (AreColorsSame(tmpColor1, tmpColor2, fastBitmap1.HasAlphaChannel)) if (AreColorsSame(tmpColor1, tmpColor2, fastBitmap1.HasAlphaChannel))
{ {
continue; continue;
} }
Log.Debug().WriteLine("Different colors at {0},{1}", x, y); Log.Debug().WriteLine("Different colors at {0},{1}", x, y);
result = false; result = false;
state.Break(); state.Break();
} }
} }
}); });
} }
return result;
return result;
} }
/// <summary> /// <summary>

View file

@ -36,10 +36,8 @@ namespace Greenshot.Gfx
public static void ApplyBoxBlur(this IBitmapWithNativeSupport destinationBitmap, int range) public static void ApplyBoxBlur(this IBitmapWithNativeSupport destinationBitmap, int range)
{ {
// We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V)
using (var fastBitmap = FastBitmapFactory.Create(destinationBitmap)) using var fastBitmap = FastBitmapFactory.Create(destinationBitmap);
{ fastBitmap.ApplyBoxBlur(range);
fastBitmap.ApplyBoxBlur(range);
}
} }
/// <summary> /// <summary>

View file

@ -76,22 +76,19 @@ namespace Greenshot.Gfx.Effects
using (var path = new GraphicsPath()) using (var path = new GraphicsPath())
{ {
path.AddRectangle(new NativeRect(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); path.AddRectangle(new NativeRect(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize));
using (var pen = new Pen(borderColor, borderSize)) using var pen = new Pen(borderColor, borderSize) {
{ LineJoin = LineJoin.Round,
pen.LineJoin = LineJoin.Round; StartCap = LineCap.Round,
pen.StartCap = LineCap.Round; EndCap = LineCap.Round
pen.EndCap = LineCap.Round; };
graphics.DrawPath(pen, path); graphics.DrawPath(pen, path);
} }
}
// draw original with a TextureBrush so we have nice anti-aliasing! // draw original with a TextureBrush so we have nice anti-aliasing!
using (Brush textureBrush = new TextureBrush(sourceBitmap.NativeBitmap, WrapMode.Clamp)) using Brush textureBrush = new TextureBrush(sourceBitmap.NativeBitmap, WrapMode.Clamp);
{ // We need to do a translate-tranform otherwise the image is wrapped
// We need to do a translate-tranform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y);
graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height);
graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); }
}
}
return newImage; return newImage;
} }

View file

@ -50,23 +50,21 @@ namespace Greenshot.Gfx.Effects
/// <param name="threshold">Threshold for monochrome filter (0 - 255), lower value means less black</param> /// <param name="threshold">Threshold for monochrome filter (0 - 255), lower value means less black</param>
/// <returns>b/w bitmap</returns> /// <returns>b/w bitmap</returns>
public static IBitmapWithNativeSupport CreateMonochrome(IBitmapWithNativeSupport sourceBitmap, byte threshold) public static IBitmapWithNativeSupport CreateMonochrome(IBitmapWithNativeSupport sourceBitmap, byte threshold)
{ {
using (var fastBitmap = FastBitmapFactory.CreateCloneOf(sourceBitmap, sourceBitmap.PixelFormat)) using var fastBitmap = FastBitmapFactory.CreateCloneOf(sourceBitmap, sourceBitmap.PixelFormat);
{ Parallel.For(0, fastBitmap.Height, y =>
Parallel.For(0, fastBitmap.Height, y => {
{ // TODO: use stackalloc / unsafe
// TODO: use stackalloc / unsafe for (var x = 0; x < fastBitmap.Width; x++)
for (var x = 0; x < fastBitmap.Width; x++) {
{ var color = fastBitmap.GetColorAt(x, y);
var color = fastBitmap.GetColorAt(x, y); var colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0;
var colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; var monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness);
var monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); fastBitmap.SetColorAt(x, y, ref monoColor);
fastBitmap.SetColorAt(x, y, ref monoColor); }
} });
}); return fastBitmap.UnlockAndReturnBitmap();
return fastBitmap.UnlockAndReturnBitmap(); }
}
}
} }

View file

@ -193,19 +193,15 @@ namespace Greenshot.Gfx.Effects
path.CloseFigure(); path.CloseFigure();
// Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing
using (var graphics = Graphics.FromImage(returnBitmap.NativeBitmap)) using var graphics = Graphics.FromImage(returnBitmap.NativeBitmap);
{ graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; using Brush brush = new TextureBrush(sourceBitmap.NativeBitmap);
using (Brush brush = new TextureBrush(sourceBitmap.NativeBitmap)) // Important note: If the target wouldn't be at 0,0 we need to translate-transform!!
{ graphics.FillPath(brush, path);
// Important note: If the target wouldn't be at 0,0 we need to translate-transform!! }
graphics.FillPath(brush, path);
}
}
}
return returnBitmap; return returnBitmap;
} }

View file

@ -34,35 +34,25 @@ namespace Greenshot.Gfx.Extensions
/// </summary> /// </summary>
/// <param name="bitmap">IBitmapWithNativeSupport</param> /// <param name="bitmap">IBitmapWithNativeSupport</param>
/// <returns>IBitmapWithNativeSupport</returns> /// <returns>IBitmapWithNativeSupport</returns>
public static IBitmapWithNativeSupport Scale2X(this IBitmapWithNativeSupport bitmap) public static IBitmapWithNativeSupport Scale2X(this IBitmapWithNativeSupport bitmap) =>
{ bitmap switch
switch (bitmap)
{ {
case UnmanagedBitmap<Bgra32> unmanagedBitmap: UnmanagedBitmap<Bgra32> unmanagedBitmap => unmanagedBitmap.Scale2X(),
return unmanagedBitmap.Scale2X(); UnmanagedBitmap<Bgr32> unmanagedBitmap => unmanagedBitmap.Scale2X(),
case UnmanagedBitmap<Bgr32> unmanagedBitmap: _ => ScaleX.Scale2X(bitmap)
return unmanagedBitmap.Scale2X(); };
}
return ScaleX.Scale2X(bitmap);
}
/// <summary> /// <summary>
/// Scale3x /// Scale3x
/// </summary> /// </summary>
/// <param name="bitmap">IBitmapWithNativeSupport</param> /// <param name="bitmap">IBitmapWithNativeSupport</param>
/// <returns>IBitmapWithNativeSupport</returns> /// <returns>IBitmapWithNativeSupport</returns>
public static IBitmapWithNativeSupport Scale3X(this IBitmapWithNativeSupport bitmap) public static IBitmapWithNativeSupport Scale3X(this IBitmapWithNativeSupport bitmap) =>
{ bitmap switch
switch (bitmap)
{ {
case UnmanagedBitmap<Bgra32> unmanagedBitmap: UnmanagedBitmap<Bgra32> unmanagedBitmap => unmanagedBitmap.Scale3X(),
return unmanagedBitmap.Scale3X(); UnmanagedBitmap<Bgr32> unmanagedBitmap => unmanagedBitmap.Scale3X(),
case UnmanagedBitmap<Bgr32> unmanagedBitmap: _ => ScaleX.Scale3X(bitmap)
return unmanagedBitmap.Scale3X(); };
}
return ScaleX.Scale3X(bitmap);
}
} }
} }

View file

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO; using System.IO;
@ -20,15 +19,13 @@ namespace Greenshot.Gfx.Formats
/// <inheritdoc/> /// <inheritdoc/>
public IBitmapWithNativeSupport Read(Stream stream, string extension = null) public IBitmapWithNativeSupport Read(Stream stream, string extension = null)
{ {
using (var tmpImage = Image.FromStream(stream, true, true)) using var tmpImage = Image.FromStream(stream, true, true);
if (!(tmpImage is Bitmap bitmap))
{ {
if (!(tmpImage is Bitmap bitmap)) return null;
{
return null;
}
Log.Debug().WriteLine("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", bitmap.Width, bitmap.Height, bitmap.PixelFormat);
return bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
} }
Log.Debug().WriteLine("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", bitmap.Width, bitmap.Height, bitmap.PixelFormat);
return bitmap.CloneBitmap(PixelFormat.Format32bppArgb);
} }
} }
} }

View file

@ -28,12 +28,10 @@ namespace Greenshot.Gfx.Formats
// Icon logic, try to get the Vista icon, else the biggest possible // Icon logic, try to get the Vista icon, else the biggest possible
try try
{ {
using (var tmpBitmap = ExtractVistaIcon(stream)) using var tmpBitmap = ExtractVistaIcon(stream);
if (tmpBitmap != null)
{ {
if (tmpBitmap != null) return tmpBitmap.CloneBitmap(PixelFormat.Format32bppArgb);
{
return tmpBitmap.CloneBitmap(PixelFormat.Format32bppArgb);
}
} }
} }
catch (Exception vistaIconException) catch (Exception vistaIconException)
@ -45,13 +43,9 @@ namespace Greenshot.Gfx.Formats
// No vista icon, try normal icon // No vista icon, try normal icon
stream.Position = 0; stream.Position = 0;
// We create a copy of the bitmap, so everything else can be disposed // We create a copy of the bitmap, so everything else can be disposed
using (var tmpIcon = new Icon(stream, new Size(1024, 1024))) using var tmpIcon = new Icon(stream, new Size(1024, 1024));
{ using var tmpImage = tmpIcon.ToBitmap();
using (var tmpImage = tmpIcon.ToBitmap()) return tmpImage.CloneBitmap(PixelFormat.Format32bppArgb);
{
return tmpImage.CloneBitmap(PixelFormat.Format32bppArgb);
}
}
} }
catch (Exception iconException) catch (Exception iconException)
{ {
@ -89,12 +83,10 @@ namespace Greenshot.Gfx.Formats
} }
var iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); var iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
var iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); var iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
using (var destStream = new MemoryStream()) using var destStream = new MemoryStream();
{ destStream.Write(srcBuf, iImageOffset, iImageSize);
destStream.Write(srcBuf, iImageOffset, iImageSize); destStream.Seek(0, SeekOrigin.Begin);
destStream.Seek(0, SeekOrigin.Begin); bmpPngExtracted = BitmapWrapper.FromBitmap(new Bitmap(destStream)); // This is PNG! :)
bmpPngExtracted = BitmapWrapper.FromBitmap(new Bitmap(destStream)); // This is PNG! :)
}
break; break;
} }
} }

View file

@ -10,7 +10,7 @@
<PackageReference Include="Dapplo.Log" Version="1.3.26" /> <PackageReference Include="Dapplo.Log" Version="1.3.26" />
<PackageReference Include="Dapplo.Windows" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows" Version="0.11.6" />
<PackageReference Include="Dapplo.Windows.Dpi" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows.Dpi" Version="0.11.6" />
<PackageReference Include="Svg" Version="3.0.49" /> <PackageReference Include="Svg" Version="3.0.84" />
<PackageReference Include="System.Memory" Version="4.5.3" /> <PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -105,53 +105,49 @@ namespace Greenshot.Gfx.Quantizer
} }
// Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage
using (var sourceFastBitmap = FastBitmapFactory.Create(sourceBitmap)) using var sourceFastBitmap = FastBitmapFactory.Create(sourceBitmap);
{ sourceFastBitmap.Lock();
sourceFastBitmap.Lock(); using var destinationFastBitmap = FastBitmapFactory.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap;
using (var destinationFastBitmap = FastBitmapFactory.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap) for (var y = 0; y < sourceFastBitmap.Height; y++)
{ {
for (var y = 0; y < sourceFastBitmap.Height; y++) for (var x = 0; x < sourceFastBitmap.Width; x++)
{ {
for (var x = 0; x < sourceFastBitmap.Width; x++) Color color;
{ if (!(sourceFastBitmap is IFastBitmapWithBlend sourceFastBitmapWithBlend))
Color color; {
if (!(sourceFastBitmap is IFastBitmapWithBlend sourceFastBitmapWithBlend)) color = sourceFastBitmap.GetColorAt(x, y);
{ }
color = sourceFastBitmap.GetColorAt(x, y); else
} {
else color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y);
{ }
color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); // To count the colors
} var index = color.ToArgb() & 0x00ffffff;
// To count the colors // Check if we already have this color
var index = color.ToArgb() & 0x00ffffff; if (!bitArray.Get(index))
// Check if we already have this color {
if (!bitArray.Get(index)) // If not, add 1 to the single colors
{ _colorCount++;
// If not, add 1 to the single colors bitArray.Set(index, true);
_colorCount++; }
bitArray.Set(index, true);
}
var indexRed = (color.R >> 3) + 1; var indexRed = (color.R >> 3) + 1;
var indexGreen = (color.G >> 3) + 1; var indexGreen = (color.G >> 3) + 1;
var indexBlue = (color.B >> 3) + 1; var indexBlue = (color.B >> 3) + 1;
_weights[indexRed, indexGreen, indexBlue]++; _weights[indexRed, indexGreen, indexBlue]++;
_momentsRed[indexRed, indexGreen, indexBlue] += color.R; _momentsRed[indexRed, indexGreen, indexBlue] += color.R;
_momentsGreen[indexRed, indexGreen, indexBlue] += color.G; _momentsGreen[indexRed, indexGreen, indexBlue] += color.G;
_momentsBlue[indexRed, indexGreen, indexBlue] += color.B; _momentsBlue[indexRed, indexGreen, indexBlue] += color.B;
_moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; _moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B];
// Store the initial "match" // Store the initial "match"
var paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; var paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue;
destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff)); destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff));
} }
} }
_resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); _resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap();
} }
}
}
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
@ -200,38 +196,36 @@ namespace Greenshot.Gfx.Quantizer
using (var bbbDest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap) using (var bbbDest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap)
{ {
bbbDest.Lock(); bbbDest.Lock();
using (var bbbSrc = FastBitmapFactory.Create(_sourceBitmap)) using var bbbSrc = FastBitmapFactory.Create(_sourceBitmap);
{ bbbSrc.Lock();
bbbSrc.Lock(); for (var y = 0; y < bbbSrc.Height; y++)
for (var y = 0; y < bbbSrc.Height; y++) {
{ for (var x = 0; x < bbbSrc.Width; x++)
for (var x = 0; x < bbbSrc.Width; x++) {
{ Color color;
Color color; if (bbbSrc is IFastBitmapWithBlend bbbSrcBlend)
if (bbbSrc is IFastBitmapWithBlend bbbSrcBlend) {
{ color = bbbSrcBlend.GetBlendedColorAt(x, y);
color = bbbSrcBlend.GetBlendedColorAt(x, y); }
} else
else {
{ color = bbbSrc.GetColorAt(x, y);
color = bbbSrc.GetColorAt(x, y); }
} byte index;
byte index; if (lookup.ContainsKey(color))
if (lookup.ContainsKey(color)) {
{ index = lookup[color];
index = lookup[color]; }
} else
else {
{ colors.Add(color);
colors.Add(color); index = (byte) (colors.Count - 1);
index = (byte) (colors.Count - 1); lookup.Add(color, index);
lookup.Add(color, index); }
} bbbDest.SetColorIndexAt(x, y, index);
bbbDest.SetColorIndexAt(x, y, index); }
} }
} }
}
}
// generates palette // generates palette
var imagePalette = _resultBitmap.NativeBitmap.Palette; var imagePalette = _resultBitmap.NativeBitmap.Palette;
@ -348,71 +342,69 @@ namespace Greenshot.Gfx.Quantizer
Log.Info().WriteLine("Starting bitmap reconstruction..."); Log.Info().WriteLine("Starting bitmap reconstruction...");
using (var dest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap) using (var dest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap)
{ {
using (var src = FastBitmapFactory.Create(_sourceBitmap)) using var src = FastBitmapFactory.Create(_sourceBitmap);
{ var lookup = new Dictionary<Color, byte>();
var lookup = new Dictionary<Color, byte>(); for (var y = 0; y < src.Height; y++)
for (var y = 0; y < src.Height; y++) {
{ for (var x = 0; x < src.Width; x++)
for (var x = 0; x < src.Width; x++) {
{ Color color;
Color color; if (src is IFastBitmapWithBlend srcBlend)
if (src is IFastBitmapWithBlend srcBlend) {
{ // WithoutAlpha, this makes it possible to ignore the alpha
// WithoutAlpha, this makes it possible to ignore the alpha color = srcBlend.GetBlendedColorAt(x, y);
color = srcBlend.GetBlendedColorAt(x, y); }
} else
else {
{ color = src.GetColorAt(x, y);
color = src.GetColorAt(x, y); }
}
// Check if we already matched the color // Check if we already matched the color
byte bestMatch; byte bestMatch;
if (!lookup.ContainsKey(color)) if (!lookup.ContainsKey(color))
{ {
// If not we need to find the best match // If not we need to find the best match
// First get initial match // First get initial match
bestMatch = dest.GetColorIndexAt(x, y); bestMatch = dest.GetColorIndexAt(x, y);
bestMatch = _tag[bestMatch]; bestMatch = _tag[bestMatch];
var bestDistance = 100000000; var bestDistance = 100000000;
for (var lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) for (var lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++)
{ {
var foundRed = lookupRed[lookupIndex]; var foundRed = lookupRed[lookupIndex];
var foundGreen = lookupGreen[lookupIndex]; var foundGreen = lookupGreen[lookupIndex];
var foundBlue = lookupBlue[lookupIndex]; var foundBlue = lookupBlue[lookupIndex];
var deltaRed = color.R - foundRed; var deltaRed = color.R - foundRed;
var deltaGreen = color.G - foundGreen; var deltaGreen = color.G - foundGreen;
var deltaBlue = color.B - foundBlue; var deltaBlue = color.B - foundBlue;
var distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; var distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue;
if (distance < bestDistance) if (distance < bestDistance)
{ {
bestDistance = distance; bestDistance = distance;
bestMatch = (byte) lookupIndex; bestMatch = (byte) lookupIndex;
} }
} }
lookup.Add(color, bestMatch); lookup.Add(color, bestMatch);
} }
else else
{ {
// Already matched, so we just use the lookup // Already matched, so we just use the lookup
bestMatch = lookup[color]; bestMatch = lookup[color];
} }
_reds[bestMatch] += color.R; _reds[bestMatch] += color.R;
_greens[bestMatch] += color.G; _greens[bestMatch] += color.G;
_blues[bestMatch] += color.B; _blues[bestMatch] += color.B;
_sums[bestMatch]++; _sums[bestMatch]++;
dest.SetColorIndexAt(x, y, bestMatch); dest.SetColorIndexAt(x, y, bestMatch);
} }
} }
} }
}
// generates palette // generates palette
@ -524,63 +516,46 @@ namespace Greenshot.Gfx.Quantizer
/// <summary> /// <summary>
/// Splits the cube in given position, and color direction. /// Splits the cube in given position, and color direction.
/// </summary> /// </summary>
private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) =>
{ direction switch
switch (direction) {
{ Red => (moment[position, cube.GreenMaximum, cube.BlueMaximum] -
case Red: moment[position, cube.GreenMaximum, cube.BlueMinimum] -
return moment[position, cube.GreenMaximum, cube.BlueMaximum] - moment[position, cube.GreenMinimum, cube.BlueMaximum] +
moment[position, cube.GreenMaximum, cube.BlueMinimum] - moment[position, cube.GreenMinimum, cube.BlueMinimum]),
moment[position, cube.GreenMinimum, cube.BlueMaximum] + Green => (moment[cube.RedMaximum, position, cube.BlueMaximum] -
moment[position, cube.GreenMinimum, cube.BlueMinimum]; moment[cube.RedMaximum, position, cube.BlueMinimum] -
moment[cube.RedMinimum, position, cube.BlueMaximum] +
moment[cube.RedMinimum, position, cube.BlueMinimum]),
Blue => (moment[cube.RedMaximum, cube.GreenMaximum, position] -
moment[cube.RedMaximum, cube.GreenMinimum, position] -
moment[cube.RedMinimum, cube.GreenMaximum, position] +
moment[cube.RedMinimum, cube.GreenMinimum, position]),
_ => 0
};
case Green: /// <summary>
return moment[cube.RedMaximum, position, cube.BlueMaximum] -
moment[cube.RedMaximum, position, cube.BlueMinimum] -
moment[cube.RedMinimum, position, cube.BlueMaximum] +
moment[cube.RedMinimum, position, cube.BlueMinimum];
case Blue:
return moment[cube.RedMaximum, cube.GreenMaximum, position] -
moment[cube.RedMaximum, cube.GreenMinimum, position] -
moment[cube.RedMinimum, cube.GreenMaximum, position] +
moment[cube.RedMinimum, cube.GreenMinimum, position];
default:
return 0;
}
}
/// <summary>
/// Splits the cube in a given color direction at its minimum. /// Splits the cube in a given color direction at its minimum.
/// </summary> /// </summary>
private static long Bottom(WuColorCube cube, int direction, long[,,] moment) private static long Bottom(WuColorCube cube, int direction, long[,,] moment) =>
{ direction switch
switch (direction) {
{ Red => (-moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] +
case Red: moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] +
return -moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] -
moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]),
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - Green => (-moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] +
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] +
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] -
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]),
Blue => (-moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] +
moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] +
moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] -
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]),
_ => 0
};
case Green: /// <summary>
return -moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] +
moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] +
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] -
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum];
case Blue:
return -moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] +
moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] +
moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] -
moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum];
default:
return 0;
}
}
/// <summary>
/// Calculates statistical variance for a given cube. /// Calculates statistical variance for a given cube.
/// </summary> /// </summary>
private float CalculateVariance(WuColorCube cube) private float CalculateVariance(WuColorCube cube)

View file

@ -36,56 +36,54 @@ namespace Greenshot.Gfx
/// <param name="original">Bitmap to scale 2x</param> /// <param name="original">Bitmap to scale 2x</param>
public static IBitmapWithNativeSupport Scale2X(IBitmapWithNativeSupport original) public static IBitmapWithNativeSupport Scale2X(IBitmapWithNativeSupport original)
{ {
using (var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original)) using var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original);
using (var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width << 1, original.Height << 1), original.PixelFormat)) using var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width << 1, original.Height << 1), original.PixelFormat);
// Every pixel from input texture produces 4 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html
Parallel.For(0, source.Height, y =>
{ {
// Every pixel from input texture produces 4 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html unsafe
Parallel.For(0, source.Height, y =>
{ {
unsafe var colorB = stackalloc byte[4];
var colorD = stackalloc byte[4];
var colorE = stackalloc byte[4];
var colorF = stackalloc byte[4];
var colorH = stackalloc byte[4];
var x = 0;
while (x < source.Width)
{ {
var colorB = stackalloc byte[4]; source.GetColorAt(x, y - 1, colorB);
var colorD = stackalloc byte[4]; source.GetColorAt(x, y + 1, colorH);
var colorE = stackalloc byte[4]; source.GetColorAt(x - 1, y, colorD);
var colorF = stackalloc byte[4]; source.GetColorAt(x + 1, y, colorF);
var colorH = stackalloc byte[4]; source.GetColorAt(x, y, colorE);
var x = 0;
while (x < source.Width) byte* colorE0, colorE1, colorE2, colorE3;
if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF))
{ {
source.GetColorAt(x, y - 1, colorB); colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE;
source.GetColorAt(x, y + 1, colorH); colorE1 = AreColorsSame(colorB, colorF) ? colorF : colorE;
source.GetColorAt(x - 1, y, colorD); colorE2 = AreColorsSame(colorD, colorH) ? colorD : colorE;
source.GetColorAt(x + 1, y, colorF); colorE3 = AreColorsSame(colorH, colorF) ? colorF : colorE;
source.GetColorAt(x, y, colorE); }
else
byte* colorE0, colorE1, colorE2, colorE3; {
if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF)) colorE0 = colorE;
{ colorE1 = colorE;
colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE; colorE2 = colorE;
colorE1 = AreColorsSame(colorB, colorF) ? colorF : colorE; colorE3 = colorE;
colorE2 = AreColorsSame(colorD, colorH) ? colorD : colorE;
colorE3 = AreColorsSame(colorH, colorF) ? colorF : colorE;
}
else
{
colorE0 = colorE;
colorE1 = colorE;
colorE2 = colorE;
colorE3 = colorE;
}
destination.SetColorAt(x << 1, y << 1, colorE0);
destination.SetColorAt((x << 1) + 1, y << 1, colorE1);
destination.SetColorAt(x << 1, (y << 1) + 1, colorE2);
destination.SetColorAt((x << 1) + 1, (y << 1) + 1, colorE3);
x++;
} }
destination.SetColorAt(x << 1, y << 1, colorE0);
destination.SetColorAt((x << 1) + 1, y << 1, colorE1);
destination.SetColorAt(x << 1, (y << 1) + 1, colorE2);
destination.SetColorAt((x << 1) + 1, (y << 1) + 1, colorE3);
x++;
} }
});
return destination.UnlockAndReturnBitmap(); }
} });
return destination.UnlockAndReturnBitmap();
} }
/// <summary> /// <summary>
@ -95,89 +93,87 @@ namespace Greenshot.Gfx
[SuppressMessage("ReSharper", "AccessToDisposedClosure")] [SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public static IBitmapWithNativeSupport Scale3X(IBitmapWithNativeSupport original) public static IBitmapWithNativeSupport Scale3X(IBitmapWithNativeSupport original)
{ {
using (var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original)) using var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original);
using (var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width * 3, original.Height * 3), original.PixelFormat)) using var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width * 3, original.Height * 3), original.PixelFormat);
// Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html
Parallel.For(0, source.Height, y =>
{ {
// Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html unsafe
Parallel.For(0, source.Height, y =>
{ {
unsafe var x = 0;
var colorA = stackalloc byte[4];
var colorB = stackalloc byte[4];
var colorC = stackalloc byte[4];
var colorD = stackalloc byte[4];
var colorE = stackalloc byte[4];
var colorF = stackalloc byte[4];
var colorG = stackalloc byte[4];
var colorH = stackalloc byte[4];
var colorI = stackalloc byte[4];
while (x < source.Width)
{ {
var x = 0; source.GetColorAt(x - 1, y - 1, colorA);
var colorA = stackalloc byte[4]; source.GetColorAt(x, y - 1, colorB);
var colorB = stackalloc byte[4]; source.GetColorAt(x + 1, y - 1, colorC);
var colorC = stackalloc byte[4];
var colorD = stackalloc byte[4]; source.GetColorAt(x - 1, y, colorD);
var colorE = stackalloc byte[4]; source.GetColorAt(x, y, colorE);
var colorF = stackalloc byte[4]; source.GetColorAt(x + 1, y, colorF);
var colorG = stackalloc byte[4];
var colorH = stackalloc byte[4]; source.GetColorAt(x - 1, y + 1, colorG);
var colorI = stackalloc byte[4]; source.GetColorAt(x, y + 1, colorH);
while (x < source.Width) source.GetColorAt(x + 1, y + 1, colorI);
byte* colorE0, colorE1, colorE2, colorE3, colorE4, colorE5, colorE6, colorE7, colorE8;
if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF))
{ {
source.GetColorAt(x - 1, y - 1, colorA); colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE;
source.GetColorAt(x, y - 1, colorB); colorE1 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorC) || AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorA) ? colorB : colorE;
source.GetColorAt(x + 1, y - 1, colorC); colorE2 = AreColorsSame(colorB, colorF) ? colorF : colorE;
colorE3 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorG) || AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorA) ? colorD : colorE;
source.GetColorAt(x - 1, y, colorD); colorE4 = colorE;
source.GetColorAt(x, y, colorE); colorE5 = AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorC) ? colorF : colorE;
source.GetColorAt(x + 1, y, colorF); colorE6 = AreColorsSame(colorD, colorH) ? colorD : colorE;
colorE7 = AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorG) ? colorH : colorE;
source.GetColorAt(x - 1, y + 1, colorG); colorE8 = AreColorsSame(colorH, colorF) ? colorF : colorE;
source.GetColorAt(x, y + 1, colorH);
source.GetColorAt(x + 1, y + 1, colorI);
byte* colorE0, colorE1, colorE2, colorE3, colorE4, colorE5, colorE6, colorE7, colorE8;
if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF))
{
colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE;
colorE1 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorC) || AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorA) ? colorB : colorE;
colorE2 = AreColorsSame(colorB, colorF) ? colorF : colorE;
colorE3 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorG) || AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorA) ? colorD : colorE;
colorE4 = colorE;
colorE5 = AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorC) ? colorF : colorE;
colorE6 = AreColorsSame(colorD, colorH) ? colorD : colorE;
colorE7 = AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorG) ? colorH : colorE;
colorE8 = AreColorsSame(colorH, colorF) ? colorF : colorE;
}
else
{
colorE0 = colorE;
colorE1 = colorE;
colorE2 = colorE;
colorE3 = colorE;
colorE4 = colorE;
colorE5 = colorE;
colorE6 = colorE;
colorE7 = colorE;
colorE8 = colorE;
}
var multipliedX = 3 * x;
var multipliedY = 3 * y;
destination.SetColorAt(multipliedX, multipliedY, colorE0);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE1);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE2);
multipliedY++;
destination.SetColorAt(multipliedX, multipliedY, colorE3);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE4);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE5);
multipliedY++;
destination.SetColorAt(multipliedX, multipliedY, colorE6);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE7);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE8);
x++;
} }
else
{
colorE0 = colorE;
colorE1 = colorE;
colorE2 = colorE;
colorE3 = colorE;
colorE4 = colorE;
colorE5 = colorE;
colorE6 = colorE;
colorE7 = colorE;
colorE8 = colorE;
}
var multipliedX = 3 * x;
var multipliedY = 3 * y;
destination.SetColorAt(multipliedX, multipliedY, colorE0);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE1);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE2);
multipliedY++;
destination.SetColorAt(multipliedX, multipliedY, colorE3);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE4);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE5);
multipliedY++;
destination.SetColorAt(multipliedX, multipliedY, colorE6);
destination.SetColorAt(multipliedX + 1, multipliedY, colorE7);
destination.SetColorAt(multipliedX + 2, multipliedY, colorE8);
x++;
} }
});
return destination.UnlockAndReturnBitmap(); }
} });
return destination.UnlockAndReturnBitmap();
} }
/// <summary> /// <summary>

View file

@ -133,24 +133,14 @@ namespace Greenshot.Gfx
{ {
get get
{ {
PixelFormat format;
TPixelLayout empty = default; TPixelLayout empty = default;
switch (empty) return empty switch
{ {
case Bgr24 _: Bgr24 _ => PixelFormat.Format24bppRgb,
format = PixelFormat.Format24bppRgb; Bgra32 _ => PixelFormat.Format32bppArgb,
break; Bgr32 _ => PixelFormat.Format32bppRgb,
case Bgra32 _: _ => throw new NotSupportedException("Unknown pixel format")
format = PixelFormat.Format32bppArgb; };
break;
case Bgr32 _:
format = PixelFormat.Format32bppRgb;
break;
default:
throw new NotSupportedException("Unknown pixel format");
}
return format;
} }
} }
@ -162,17 +152,13 @@ namespace Greenshot.Gfx
get get
{ {
TPixelLayout empty = default; TPixelLayout empty = default;
switch (empty) return empty switch
{ {
case Bgr24 _: Bgr24 _ => PixelFormats.Bgr24,
return PixelFormats.Bgr24; Bgra32 _ => PixelFormats.Bgra32,
case Bgra32 _: Bgr32 _ => PixelFormats.Bgr32,
return PixelFormats.Bgra32; _ => throw new NotSupportedException("Unknown pixel format")
case Bgr32 _: };
return PixelFormats.Bgr32;
default:
throw new NotSupportedException("Unknown pixel format");
}
} }
} }

View file

@ -18,7 +18,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Drawing.Imaging;
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Dapplo.Log; using Dapplo.Log;
@ -75,16 +74,14 @@ namespace Greenshot.PerformanceTests
//[Benchmark] //[Benchmark]
public void Capture() public void Capture()
{ {
using (var capture = WindowCapture.CaptureScreen()) using var capture = WindowCapture.CaptureScreen();
if (capture.Bitmap == null)
{ {
if (capture.Bitmap == null) throw new NotSupportedException();
{ }
throw new NotSupportedException(); if (capture.Bitmap.Width <= 0 || capture.Bitmap.Height <= 0)
} {
if (capture.Bitmap.Width <= 0 || capture.Bitmap.Height <= 0) throw new NotSupportedException();
{
throw new NotSupportedException();
}
} }
} }

View file

@ -40,11 +40,9 @@ namespace Greenshot.PerformanceTests
{ {
_unmanagedTestBitmap = new UnmanagedBitmap<Bgr32>(400, 400); _unmanagedTestBitmap = new UnmanagedBitmap<Bgr32>(400, 400);
_unmanagedTestBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0}); _unmanagedTestBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0});
using (var graphics = Graphics.FromImage(_unmanagedTestBitmap.NativeBitmap)) using var graphics = Graphics.FromImage(_unmanagedTestBitmap.NativeBitmap);
using (var pen = new SolidBrush(Color.Blue)) using var pen = new SolidBrush(Color.Blue);
{ graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
} }
[GlobalCleanup] [GlobalCleanup]
@ -60,19 +58,16 @@ namespace Greenshot.PerformanceTests
[Arguments(PixelFormat.Format32bppArgb)] [Arguments(PixelFormat.Format32bppArgb)]
public void WuQuantizer(PixelFormat pixelFormat) public void WuQuantizer(PixelFormat pixelFormat)
{ {
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White)) using var bitmap = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White);
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
var quantizer = new WuQuantizer(bitmap);
using (var quantizedImage = quantizer.GetQuantizedImage())
{
quantizedImage.NativeBitmap.Save(@"quantized.png", ImageFormat.Png);
}
} }
var quantizer = new WuQuantizer(bitmap);
using var quantizedImage = quantizer.GetQuantizedImage();
quantizedImage.NativeBitmap.Save(@"quantized.png", ImageFormat.Png);
} }
[Benchmark] [Benchmark]
@ -81,45 +76,41 @@ namespace Greenshot.PerformanceTests
[Arguments(PixelFormat.Format32bppArgb)] [Arguments(PixelFormat.Format32bppArgb)]
public void Blur_FastBitmap(PixelFormat pixelFormat) public void Blur_FastBitmap(PixelFormat pixelFormat)
{ {
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White)) using var bitmap = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White);
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
bitmap.ApplyBoxBlur(10);
} }
bitmap.ApplyBoxBlur(10);
} }
[Benchmark] [Benchmark]
public void Blur_UnmanagedBitmap() public void Blur_UnmanagedBitmap()
{ {
using (var unmanagedBitmap = new UnmanagedBitmap<Bgr32>(400, 400)) using var unmanagedBitmap = new UnmanagedBitmap<Bgr32>(400, 400);
unmanagedBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
using (var graphics = Graphics.FromImage(unmanagedBitmap.NativeBitmap))
{ {
unmanagedBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 }); using var pen = new SolidBrush(Color.Blue);
using (var graphics = Graphics.FromImage(unmanagedBitmap.NativeBitmap)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
using (var pen = new SolidBrush(Color.Blue))
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
unmanagedBitmap.ApplyBoxBlur(10);
} }
unmanagedBitmap.ApplyBoxBlur(10);
} }
[Benchmark] [Benchmark]
public void Blur_Old() public void Blur_Old()
{ {
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White)) using var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White);
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
BoxBlurOld.ApplyOldBoxBlur(bitmap, 10);
} }
BoxBlurOld.ApplyOldBoxBlur(bitmap, 10);
} }
[Benchmark] [Benchmark]

View file

@ -16,9 +16,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" /> <PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
<PackageReference Include="CommandLineParser" Version="2.6.0" /> <PackageReference Include="CommandLineParser" Version="2.6.0" />
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.0.0" /> <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.0" />
<PackageReference Include="SharpAvi" Version="2.1.2" /> <PackageReference Include="SharpAvi" Version="2.1.2" />
<PackageReference Include="System.Memory" Version="4.5.3" /> <PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup> </ItemGroup>

View file

@ -37,54 +37,54 @@ namespace Greenshot.Tests
[InlineData(PixelFormat.Format32bppArgb)] [InlineData(PixelFormat.Format32bppArgb)]
public void Test_Blur(PixelFormat pixelFormat) public void Test_Blur(PixelFormat pixelFormat)
{ {
using (var bitmapNew = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White)) using var bitmapNew = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White);
using (var bitmapOld = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White)) using var bitmapOld = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White);
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{ bitmapNew.ApplyBoxBlur(10);
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
bitmapNew.ApplyBoxBlur(10);
}
using (var graphics = Graphics.FromImage(bitmapOld.NativeBitmap))
using (var pen = new SolidBrush(Color.Blue))
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
}
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
} }
using (var graphics = Graphics.FromImage(bitmapOld.NativeBitmap))
{
using var pen = new SolidBrush(Color.Blue);
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
}
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
} }
[Fact] [Fact]
public void Test_Blur_UnmanagedBitmap() public void Test_Blur_UnmanagedBitmap()
{ {
using (var bitmapNew = new UnmanagedBitmap<Bgr32>(400, 400)) using var bitmapNew = new UnmanagedBitmap<Bgr32>(400, 400);
using (var bitmapOld = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White)) using var bitmapOld = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White);
using (var graphics = Graphics.FromImage(bitmapOld.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmapOld.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
using (var pen = new SolidBrush(Color.Blue))
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
bitmapNew.ApplyBoxBlur(10);
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
} }
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
{
using var pen = new SolidBrush(Color.Blue);
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
bitmapNew.ApplyBoxBlur(10);
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
} }
} }
} }

View file

@ -86,12 +86,11 @@ namespace Greenshot.Tests
[Fact] [Fact]
public void Test_GdiScreenCapture() public void Test_GdiScreenCapture()
{ {
using (var gdiScreenCapture = new GdiScreenCapture()) using var gdiScreenCapture = new GdiScreenCapture();
gdiScreenCapture.CaptureFrame();
using (var bitmap = gdiScreenCapture.CurrentFrameAsBitmap())
{ {
gdiScreenCapture.CaptureFrame(); Assert.True(bitmap.Width > 0);
using (var bitmap = gdiScreenCapture.CurrentFrameAsBitmap())
{
Assert.True(bitmap.Width > 0);
/* /*
// Write the capture to a file, for analysis // Write the capture to a file, for analysis
@ -100,13 +99,12 @@ namespace Greenshot.Tests
ImageOutput.SaveToStream(bitmap, null, stream, new SurfaceOutputSettings(null, OutputFormats.png)); ImageOutput.SaveToStream(bitmap, null, stream, new SurfaceOutputSettings(null, OutputFormats.png));
} }
*/ */
}
var bitmapSource = gdiScreenCapture.CurrentFrameAsBitmapSource();
Assert.True(bitmapSource.Width > 0);
gdiScreenCapture.CaptureFrame();
} }
var bitmapSource = gdiScreenCapture.CurrentFrameAsBitmapSource();
Assert.True(bitmapSource.Width > 0);
gdiScreenCapture.CaptureFrame();
} }
/// <summary> /// <summary>
@ -144,11 +142,12 @@ namespace Greenshot.Tests
var template = new SimpleTemplate(); var template = new SimpleTemplate();
var bitmapSource = template.Apply(capture).ToBitmapSource(); var bitmapSource = template.Apply(capture).ToBitmapSource();
using (var outputStream = bitmapSource.ToStream(OutputFormats.png)) using (var outputStream = bitmapSource.ToStream(OutputFormats.png))
using (var fileStream = File.Create("Test_CaptureFlow_DwmWindowSource.png"))
{ {
using var fileStream = File.Create("Test_CaptureFlow_DwmWindowSource.png");
outputStream.Seek(0, SeekOrigin.Begin); outputStream.Seek(0, SeekOrigin.Begin);
await outputStream.CopyToAsync(fileStream); await outputStream.CopyToAsync(fileStream);
} }
Assert.Equal(bounds.Size, bitmapSource.Size()); Assert.Equal(bounds.Size, bitmapSource.Size());
} }
@ -159,26 +158,22 @@ namespace Greenshot.Tests
[Fact] [Fact]
public void Test_BitmapCapture() public void Test_BitmapCapture()
{ {
using (var screenBitmapCapture = new BitmapScreenCapture()) using var screenBitmapCapture = new BitmapScreenCapture();
screenBitmapCapture.CaptureFrame();
Assert.NotNull(screenBitmapCapture.CurrentFrameAsBitmap());
var testFile1 = Path.Combine(Path.GetTempPath(), @"test-bitmap.png");
screenBitmapCapture.CurrentFrameAsBitmap().NativeBitmap.Save(testFile1, ImageFormat.Png);
var testFile2 = Path.Combine(Path.GetTempPath(), @"test-bitmapsource.png");
using var fileStream = new FileStream(testFile2, FileMode.Create);
var encoder = new PngBitmapEncoder
{ {
screenBitmapCapture.CaptureFrame(); Interlace = PngInterlaceOption.Off
};
Assert.NotNull(screenBitmapCapture.CurrentFrameAsBitmap()); encoder.Frames.Add(BitmapFrame.Create(screenBitmapCapture.CurrentFrameAsBitmap().NativeBitmapSource));
encoder.Save(fileStream);
var testFile1 = Path.Combine(Path.GetTempPath(), @"test-bitmap.png");
screenBitmapCapture.CurrentFrameAsBitmap().NativeBitmap.Save(testFile1, ImageFormat.Png);
var testFile2 = Path.Combine(Path.GetTempPath(), @"test-bitmapsource.png");
using (var fileStream = new FileStream(testFile2, FileMode.Create))
{
var encoder = new PngBitmapEncoder
{
Interlace = PngInterlaceOption.Off
};
encoder.Frames.Add(BitmapFrame.Create(screenBitmapCapture.CurrentFrameAsBitmap().NativeBitmapSource));
encoder.Save(fileStream);
}
}
} }
} }
} }

View file

@ -19,27 +19,27 @@ namespace Greenshot.Tests
[Fact] [Fact]
public void TestBlur() public void TestBlur()
{ {
using (var bitmap1 = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format24bppRgb, Color.White)) using var bitmap1 = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format24bppRgb, Color.White);
using (var bitmap2 = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format24bppRgb, Color.White)) using var bitmap2 = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format24bppRgb, Color.White);
using (var graphics = Graphics.FromImage(bitmap1.NativeBitmap))
{ {
using (var graphics = Graphics.FromImage(bitmap1.NativeBitmap)) using var pen = new SolidBrush(Color.Blue);
using (var pen = new SolidBrush(Color.Blue)) graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
bitmap1.NativeBitmap.Save("bitmap0.png", ImageFormat.Png);
bitmap1.ApplyBoxBlur(10);
bitmap1.NativeBitmap.Save("bitmap1.png", ImageFormat.Png);
using (var graphics = Graphics.FromImage(bitmap2.NativeBitmap))
using (var pen = new SolidBrush(Color.Blue))
{
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
BoxBlurOld.ApplyOldBoxBlur(bitmap2, 10);
bitmap2.NativeBitmap.Save("bitmap2.png", ImageFormat.Png);
Assert.True(bitmap1.IsEqualTo(bitmap2));
} }
bitmap1.NativeBitmap.Save("bitmap0.png", ImageFormat.Png);
bitmap1.ApplyBoxBlur(10);
bitmap1.NativeBitmap.Save("bitmap1.png", ImageFormat.Png);
using (var graphics = Graphics.FromImage(bitmap2.NativeBitmap))
{
using var pen = new SolidBrush(Color.Blue);
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
}
BoxBlurOld.ApplyOldBoxBlur(bitmap2, 10);
bitmap2.NativeBitmap.Save("bitmap2.png", ImageFormat.Png);
Assert.True(bitmap1.IsEqualTo(bitmap2));
} }
} }
} }

View file

@ -28,7 +28,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" /> <PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
<PackageReference Include="CommandLineParser" Version="2.6.0" /> <PackageReference Include="CommandLineParser" Version="2.6.0" />
<PackageReference Include="Dapplo.Log.XUnit" Version="1.3.26" /> <PackageReference Include="Dapplo.Log.XUnit" Version="1.3.26" />
<PackageReference Include="Dapplo.Windows" Version="0.11.6" /> <PackageReference Include="Dapplo.Windows" Version="0.11.6" />

View file

@ -18,10 +18,8 @@ namespace Greenshot.Tests.Implementation
public static void ApplyOldBoxBlur(this IBitmapWithNativeSupport destinationBitmap, int range) public static void ApplyOldBoxBlur(this IBitmapWithNativeSupport destinationBitmap, int range)
{ {
// We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V)
using (var fastBitmap = FastBitmapFactory.Create(destinationBitmap)) using var fastBitmap = FastBitmapFactory.Create(destinationBitmap);
{ fastBitmap.ApplyOldBoxBlur(range);
fastBitmap.ApplyOldBoxBlur(range);
}
} }
/// <summary> /// <summary>

Some files were not shown because too many files have changed in this diff Show more