mirror of
https://github.com/greenshot/greenshot
synced 2025-08-22 22:34:27 -07:00
Improved the UnmanagedBitmap, and all IBitmapWithNativeSupport to support both Bitmap and BitmapSource with minimal copying. This should make integrations of newer code a lot easier.
This commit is contained in:
parent
013810872e
commit
ee779cc97b
15 changed files with 330 additions and 68 deletions
|
@ -48,8 +48,8 @@
|
|||
<DebugSymbols>True</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))">
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="2.3.136">
|
||||
<!--ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))">
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="2.3.138">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
@ -57,7 +57,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</ItemGroup-->
|
||||
|
||||
<Target Name="PostBuild" BeforeTargets="PostBuildEvent" Condition="$(MSBuildProjectName.Contains('Addon.')) And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo')) And ($(OsProductName.Contains('Windows 10')) Or (!$(OsProductName.Contains('Windows 10')) And !$(MSBuildProjectName.Contains('Win10'))))">
|
||||
<Exec Command="
|
||||
|
|
138
src/Greenshot.Addons/Core/BitmapScreenCapture.cs
Normal file
138
src/Greenshot.Addons/Core/BitmapScreenCapture.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
// Greenshot - a free and open source screenshot tool
|
||||
// Copyright (C) 2007-2018 Thomas Braun, Jens Klingen, Robin Krom
|
||||
//
|
||||
// For more information see: http://getgreenshot.org/
|
||||
// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Gdi32;
|
||||
using Dapplo.Windows.Gdi32.Enums;
|
||||
using Dapplo.Windows.Gdi32.SafeHandles;
|
||||
using Dapplo.Windows.Gdi32.Structs;
|
||||
using Dapplo.Windows.User32;
|
||||
using Greenshot.Gfx;
|
||||
using Greenshot.Gfx.Structs;
|
||||
|
||||
namespace Greenshot.Addons.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This allows us to repeatedly capture the screen via GDI
|
||||
/// </summary>
|
||||
public class BitmapScreenCapture : IDisposable
|
||||
{
|
||||
private readonly bool _useStretch;
|
||||
private bool _hasFrame;
|
||||
private readonly SafeWindowDcHandle _desktopDcHandle;
|
||||
private readonly SafeCompatibleDcHandle _safeCompatibleDcHandle;
|
||||
private readonly SafeDibSectionHandle _safeDibSectionHandle;
|
||||
private readonly SafeSelectObjectHandle _safeSelectObjectHandle;
|
||||
private readonly IBitmapWithNativeSupport _bitmap;
|
||||
|
||||
/// <summary>
|
||||
/// Return the source rectangle
|
||||
/// </summary>
|
||||
public NativeRect SourceRect { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the source rectangle
|
||||
/// </summary>
|
||||
public NativeSize DestinationSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The constructor
|
||||
/// </summary>
|
||||
/// <param name="sourceCaptureBounds">NativeRect, optional, with the source area from the screen</param>
|
||||
/// <param name="requestedSize">NativeSize, optional, specifying the resulting size</param>
|
||||
public BitmapScreenCapture(NativeRect? sourceCaptureBounds = null, NativeSize? requestedSize = null)
|
||||
{
|
||||
SourceRect = sourceCaptureBounds ?? DisplayInfo.ScreenBounds;
|
||||
|
||||
// Check if a size was specified, if this differs we need to stretch / scale
|
||||
if (requestedSize.HasValue && requestedSize.Value != SourceRect.Size)
|
||||
{
|
||||
DestinationSize = requestedSize.Value;
|
||||
_useStretch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestinationSize = SourceRect.Size;
|
||||
_useStretch = false;
|
||||
}
|
||||
|
||||
// Get a Device Context for the desktop
|
||||
_desktopDcHandle = SafeWindowDcHandle.FromDesktop();
|
||||
|
||||
// Create a Device Context which is compatible with the desktop Device Context
|
||||
_safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(_desktopDcHandle);
|
||||
// Create BitmapInfoHeader, which is later used in the CreateDIBSection
|
||||
var bitmapInfoHeader = BitmapInfoHeader.Create(DestinationSize.Width, DestinationSize.Height, 32);
|
||||
// Create a DibSection, a device-independent bitmap (DIB)
|
||||
_safeDibSectionHandle = Gdi32Api.CreateDIBSection(_desktopDcHandle, ref bitmapInfoHeader, DibColors.RgbColors, out var bits, IntPtr.Zero, 0);
|
||||
|
||||
// select the device-independent bitmap in the device context, storing the previous.
|
||||
// This is needed, so every interaction with the DC will go into the DIB.
|
||||
_safeSelectObjectHandle = _safeCompatibleDcHandle.SelectObject(_safeDibSectionHandle);
|
||||
|
||||
// Create a wrapper around the bitmap data
|
||||
_bitmap = new UnmanagedBitmap<Bgr32>(bits, DestinationSize.Width, DestinationSize.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture a frame from the screen
|
||||
/// </summary>
|
||||
public void CaptureFrame()
|
||||
{
|
||||
if (_useStretch)
|
||||
{
|
||||
// capture from source and blt over (make copy) to the DIB (via the DC)
|
||||
// use stretching as the source and destination have different sizes
|
||||
Gdi32Api.StretchBlt(
|
||||
_safeCompatibleDcHandle, 0, 0, DestinationSize.Width, DestinationSize.Height, // Destination
|
||||
_desktopDcHandle, SourceRect.X, SourceRect.Y, SourceRect.Width, SourceRect.Height, // source
|
||||
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
|
||||
}
|
||||
else
|
||||
{
|
||||
// capture from source and blt over (make copy) to the DIB (via the DC)
|
||||
Gdi32Api.BitBlt(
|
||||
_safeCompatibleDcHandle, 0, 0, DestinationSize.Width, DestinationSize.Height, // Destination
|
||||
_desktopDcHandle, SourceRect.X, SourceRect.Y, // Source
|
||||
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
|
||||
}
|
||||
|
||||
_hasFrame = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the frame, captured with the previous CaptureFrame call
|
||||
/// </summary>
|
||||
/// <returns>IBitmapWithNativeSupport</returns>
|
||||
public IBitmapWithNativeSupport CurrentFrameAsBitmap() => _hasFrame ? _bitmap : null;
|
||||
|
||||
/// <summary>
|
||||
/// Dispose all DC, DIB, handles etc
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_safeSelectObjectHandle.Dispose();
|
||||
_safeDibSectionHandle.Dispose();
|
||||
_safeCompatibleDcHandle.Dispose();
|
||||
_desktopDcHandle.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -346,8 +346,7 @@ namespace Greenshot.Addons.Core
|
|||
}
|
||||
|
||||
// get a .NET image object for it
|
||||
// A suggestion for the "A generic error occurred in GDI+." E_FAIL/0<>80004005 error is to re-try...
|
||||
var success = false;
|
||||
// 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++)
|
||||
{
|
||||
|
@ -408,9 +407,6 @@ namespace Greenshot.Addons.Core
|
|||
// TODO: Optimize?
|
||||
return BitmapWrapper.FromBitmap(Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()));
|
||||
}
|
||||
// We got through the capture without exception
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
catch (ExternalException ee)
|
||||
{
|
||||
|
@ -418,8 +414,6 @@ namespace Greenshot.Addons.Core
|
|||
exception = ee;
|
||||
}
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
Log.Error().WriteLine(null, "Still couldn't create Bitmap!");
|
||||
if (exception != null)
|
||||
{
|
||||
|
@ -428,7 +422,6 @@ namespace Greenshot.Addons.Core
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
{
|
||||
|
@ -49,7 +51,7 @@ namespace Greenshot.Gfx
|
|||
public int Width => _bitmap.Width;
|
||||
|
||||
/// <inheritdoc />
|
||||
public PixelFormat PixelFormat => _bitmap.PixelFormat;
|
||||
public System.Drawing.Imaging.PixelFormat PixelFormat => _bitmap.PixelFormat;
|
||||
|
||||
/// <inheritdoc />
|
||||
public float HorizontalResolution => _bitmap.HorizontalResolution;
|
||||
|
@ -60,6 +62,24 @@ namespace Greenshot.Gfx
|
|||
/// <inheritdoc />
|
||||
public Bitmap NativeBitmap => _bitmap;
|
||||
|
||||
/// <inheritdoc />
|
||||
public BitmapSource NativeBitmapSource
|
||||
{
|
||||
get
|
||||
{
|
||||
var bitmapData = _bitmap.LockBits(new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), ImageLockMode.ReadOnly, _bitmap.PixelFormat);
|
||||
try
|
||||
{
|
||||
return BitmapSource.Create(bitmapData.Width, bitmapData.Height, _bitmap.HorizontalResolution, _bitmap.VerticalResolution, PixelFormats.Bgr24, null, bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_bitmap.UnlockBits(bitmapData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -87,8 +87,7 @@ namespace Greenshot.Gfx.FastBitmap
|
|||
/// <param name="horizontalResolution">float for horizontal DPI</param>
|
||||
/// <param name="verticalResolution">float for horizontal DPI</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat = PixelFormat.DontCare, Color? backgroundColor = null, float horizontalResolution = 96f,
|
||||
float verticalResolution = 96f)
|
||||
public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat = PixelFormat.DontCare, Color? backgroundColor = null, float horizontalResolution = 96f, float verticalResolution = 96f)
|
||||
{
|
||||
var destination = BitmapFactory.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, horizontalResolution, verticalResolution);
|
||||
var fastBitmap = Create(destination);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
{
|
||||
|
@ -61,10 +62,16 @@ namespace Greenshot.Gfx
|
|||
public interface IBitmapWithNativeSupport : IBitmap
|
||||
{
|
||||
/// <summary>
|
||||
/// Underlying image, or an on demand rendered version with different attributes as the original
|
||||
/// Retrieves a Bitmap which only can be used as long as the underlying implementation is not disposed.
|
||||
/// Do not dispose this.
|
||||
/// </summary>
|
||||
Bitmap NativeBitmap { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a BitmapSource which only can be used as long as the underlying implementation is not disposed.
|
||||
/// </summary>
|
||||
BitmapSource NativeBitmapSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the Size
|
||||
/// </summary>
|
||||
|
|
|
@ -149,12 +149,17 @@ namespace Greenshot.Gfx.Quantizer
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose implementation
|
||||
/// </summary>
|
||||
/// <param name="disposing">bool</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
|
@ -308,7 +313,7 @@ namespace Greenshot.Gfx.Quantizer
|
|||
|
||||
_tag = new byte[Maxvolume];
|
||||
|
||||
// precalculates lookup tables
|
||||
// pre-calculates lookup tables
|
||||
for (var k = 0; k < allowedColorCount; ++k)
|
||||
{
|
||||
Mark(_cubes[k], k, _tag);
|
||||
|
|
|
@ -20,7 +20,11 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Svg;
|
||||
using Color = System.Drawing.Color;
|
||||
using PixelFormat = System.Drawing.Imaging.PixelFormat;
|
||||
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
|
@ -111,6 +115,24 @@ namespace Greenshot.Gfx
|
|||
/// </summary>
|
||||
public Bitmap NativeBitmap => GenerateNativeBitmap();
|
||||
|
||||
/// <inheritdoc />
|
||||
public BitmapSource NativeBitmapSource
|
||||
{
|
||||
get
|
||||
{
|
||||
GenerateNativeBitmap();
|
||||
var bitmapData = _imageClone.LockBits(new Rectangle(0, 0, _imageClone.Width, _imageClone.Height), ImageLockMode.ReadOnly, _imageClone.PixelFormat);
|
||||
try
|
||||
{
|
||||
return BitmapSource.Create(bitmapData.Width, bitmapData.Height, _imageClone.HorizontalResolution, _imageClone.VerticalResolution, PixelFormats.Bgr24, null, bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_imageClone.UnlockBits(bitmapData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap GenerateNativeBitmap()
|
||||
{
|
||||
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||
|
@ -128,11 +150,6 @@ namespace Greenshot.Gfx
|
|||
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
public void DisposeNativeBitmap(Bitmap nativeBitmap)
|
||||
{
|
||||
// do nothing, we need this
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Greenshot.Gfx.Structs;
|
||||
using PixelFormat = System.Drawing.Imaging.PixelFormat;
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
{
|
||||
|
@ -34,8 +36,13 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
private readonly float _horizontalPixelsPerInch;
|
||||
private readonly float _verticalPixelsPerInch;
|
||||
// Bytes per line
|
||||
private readonly int _stride;
|
||||
// IntPtr to a global handle with the bitmap data, this will be freed on dispose
|
||||
private IntPtr _hGlobal;
|
||||
// IntPtr to the bits of the bitmap, if using the constructor with the IntPtr this will not be freed
|
||||
private readonly IntPtr _bits;
|
||||
// Optionally created when the user calls NativeBitmap
|
||||
private Bitmap _nativeBitmap;
|
||||
|
||||
/// <summary>
|
||||
|
@ -64,10 +71,30 @@ namespace Greenshot.Gfx
|
|||
Height = height;
|
||||
_stride = bytesPerPixel * width;
|
||||
var bytesAllocated = height * _stride;
|
||||
_hGlobal = Marshal.AllocHGlobal(bytesAllocated);
|
||||
_bits = _hGlobal = Marshal.AllocHGlobal(bytesAllocated);
|
||||
GC.AddMemoryPressure(bytesAllocated);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The constructor for the UnmanagedBitmap with already initialized bits
|
||||
/// </summary>
|
||||
/// <param name="bits">IntPtr to the bits, this will not be freed</param>
|
||||
/// <param name="width">int</param>
|
||||
/// <param name="height">int</param>
|
||||
/// <param name="horizontalPixelsPerInch">float</param>
|
||||
/// <param name="verticalPixelsPerInch">float</param>
|
||||
public UnmanagedBitmap(IntPtr bits, int width, int height, float horizontalPixelsPerInch = 0.96f, float verticalPixelsPerInch = 0.96f)
|
||||
{
|
||||
_horizontalPixelsPerInch = horizontalPixelsPerInch;
|
||||
_verticalPixelsPerInch = verticalPixelsPerInch;
|
||||
var bytesPerPixel = Marshal.SizeOf<TPixelLayout>();
|
||||
Width = width;
|
||||
Height = height;
|
||||
_stride = bytesPerPixel * width;
|
||||
_bits = bits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This returns a span with a the pixels for the specified line
|
||||
/// </summary>
|
||||
|
@ -79,7 +106,7 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
unsafe
|
||||
{
|
||||
var pixelRowPointer = _hGlobal + (y * _stride);
|
||||
var pixelRowPointer = _bits + (y * _stride);
|
||||
return new Span<TPixelLayout>(pixelRowPointer.ToPointer(), Width);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +123,7 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
unsafe
|
||||
{
|
||||
return new Span<TPixelLayout>(_hGlobal.ToPointer(), Height * Width);
|
||||
return new Span<TPixelLayout>(_bits.ToPointer(), Height * Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +154,25 @@ namespace Greenshot.Gfx
|
|||
}
|
||||
}
|
||||
|
||||
public System.Windows.Media.PixelFormat WpfPixelFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
TPixelLayout empty = default;
|
||||
switch (empty)
|
||||
{
|
||||
case Bgr24 _:
|
||||
return PixelFormats.Bgr24;
|
||||
case Bgra32 _:
|
||||
return PixelFormats.Bgra32;
|
||||
case Bgr32 _:
|
||||
return PixelFormats.Bgr32;
|
||||
default:
|
||||
throw new NotSupportedException("Unknown pixel format");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public float VerticalResolution => _verticalPixelsPerInch;
|
||||
|
||||
|
@ -141,7 +187,19 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
get
|
||||
{
|
||||
return _nativeBitmap ??= new Bitmap(Width, Height, _stride, PixelFormat, _hGlobal);
|
||||
return _nativeBitmap ??= new Bitmap(Width, Height, _stride, PixelFormat, _bits);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this to a real bitmap
|
||||
/// </summary>
|
||||
/// <returns>BitmapSource</returns>
|
||||
public BitmapSource NativeBitmapSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return BitmapSource.Create(Width, Height, HorizontalResolution, VerticalResolution, WpfPixelFormat, null, _bits, _stride * Height, _stride);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Dapplo.Log;
|
||||
|
@ -32,7 +33,7 @@ namespace Greenshot.PerformanceTests
|
|||
/// <summary>
|
||||
/// This defines the benchmarks which can be done
|
||||
/// </summary>
|
||||
[MinColumn, MaxColumn, MemoryDiagnoser]
|
||||
[MinColumn, MaxColumn, MemoryDiagnoser, CoreJob, ClrJob]
|
||||
public class CapturePerformance
|
||||
{
|
||||
private static readonly LogSource Log = new LogSource();
|
||||
|
@ -40,6 +41,8 @@ namespace Greenshot.PerformanceTests
|
|||
private GdiScreenCapture _screenCapture;
|
||||
// A ScreenCapture which captures the whole screen (multi-monitor) but with half the destination size, uses stretch-blt
|
||||
private GdiScreenCapture _screenCaptureResized;
|
||||
private BitmapScreenCapture _screenBitmapCapture;
|
||||
private BitmapScreenCapture _screenBitmapCaptureResized;
|
||||
private AviWriter _aviWriter;
|
||||
private IAviVideoStream _aviVideoStream;
|
||||
|
||||
|
@ -47,8 +50,10 @@ namespace Greenshot.PerformanceTests
|
|||
public void Setup()
|
||||
{
|
||||
_screenCapture = new GdiScreenCapture(DisplayInfo.ScreenBounds);
|
||||
_screenBitmapCapture = new BitmapScreenCapture();
|
||||
var resizedSize = new NativeSize(DisplayInfo.ScreenBounds.Width / 2, DisplayInfo.ScreenBounds.Height / 2);
|
||||
_screenCaptureResized = new GdiScreenCapture(DisplayInfo.ScreenBounds, resizedSize);
|
||||
_screenBitmapCaptureResized = new BitmapScreenCapture(DisplayInfo.ScreenBounds, resizedSize);
|
||||
|
||||
var aviFile = Path.Combine(Path.GetTempPath(), @"test.avi");
|
||||
Log.Info().WriteLine("Writing AVI to {0}", aviFile);
|
||||
|
@ -61,12 +66,13 @@ namespace Greenshot.PerformanceTests
|
|||
EmitIndex1 = true
|
||||
};
|
||||
_aviVideoStream = _aviWriter.AddVideoStream(resizedSize.Width, resizedSize.Height, BitsPerPixel.Bpp24);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This benchmarks a screen capture which does a lot of additional work
|
||||
/// </summary>
|
||||
[Benchmark]
|
||||
//[Benchmark]
|
||||
public void Capture()
|
||||
{
|
||||
using (var capture = WindowCapture.CaptureScreen())
|
||||
|
@ -91,6 +97,15 @@ namespace Greenshot.PerformanceTests
|
|||
_screenCapture.CaptureFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture the screen directly into a bitmap
|
||||
/// </summary>
|
||||
[Benchmark]
|
||||
public void CaptureBitmap()
|
||||
{
|
||||
_screenBitmapCapture.CaptureFrame();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Capture the screen with buffered settings, but resized (smaller) destination
|
||||
/// </summary>
|
||||
|
@ -100,6 +115,17 @@ namespace Greenshot.PerformanceTests
|
|||
_screenCaptureResized.CaptureFrame();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Capture the screen with buffered settings, but resized (smaller) destination
|
||||
/// </summary>
|
||||
//[Benchmark]
|
||||
public void CapturebitmapResized()
|
||||
{
|
||||
_screenBitmapCaptureResized.CaptureFrame();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Capture the screen with buffered settings, but resized (smaller) destination
|
||||
/// </summary>
|
||||
|
@ -115,6 +141,8 @@ namespace Greenshot.PerformanceTests
|
|||
public void Cleanup()
|
||||
{
|
||||
_screenCapture.Dispose();
|
||||
_screenBitmapCapture.Dispose();
|
||||
_screenBitmapCaptureResized.Dispose();
|
||||
_aviWriter.Close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Greenshot.PerformanceTests
|
|||
/// <summary>
|
||||
/// This defines the benchmarks which can be done
|
||||
/// </summary>
|
||||
[MinColumn, MaxColumn, MemoryDiagnoser]
|
||||
[MinColumn, MaxColumn, MemoryDiagnoser, CoreJob, ClrJob]
|
||||
public class GfxPerformance
|
||||
{
|
||||
private UnmanagedBitmap<Bgr32> _unmanagedTestBitmap;
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Greenshot.Gfx;
|
||||
|
||||
namespace Greenshot.PerformanceTests
|
||||
{
|
||||
/// <summary>
|
||||
/// This defines the benchmarks which can be done
|
||||
/// </summary>
|
||||
[MinColumn, MaxColumn, MemoryDiagnoser]
|
||||
public class GfxPerformanceShort
|
||||
{
|
||||
[Benchmark]
|
||||
[Arguments(PixelFormat.Format24bppRgb)]
|
||||
[Arguments(PixelFormat.Format32bppRgb)]
|
||||
[Arguments(PixelFormat.Format32bppArgb)]
|
||||
public void Blur(PixelFormat pixelFormat)
|
||||
{
|
||||
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, pixelFormat, Color.White))
|
||||
{
|
||||
using (var graphics = Graphics.FromImage(bitmap.NativeBitmap))
|
||||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
}
|
||||
bitmap.ApplyBoxBlur(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,9 +64,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.4" />
|
||||
<PackageReference Include="ClrHeapAllocationAnalyzer" Version="1.0.0.9" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.4.3" />
|
||||
<PackageReference Include="JeremyAnsel.ColorQuant" Version="1.0.55" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
|
||||
<Version>2.6.3</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
|
@ -75,7 +73,6 @@
|
|||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="2.1.0" />
|
||||
<PackageReference Include="SharpAvi" Version="2.1.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0006" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.2" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace Greenshot.PerformanceTests
|
|||
// ReSharper disable once UnusedParameter.Local
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
BenchmarkRunner.Run<GfxPerformance>();
|
||||
//BenchmarkRunner.Run<GfxPerformance>();
|
||||
BenchmarkRunner.Run<CapturePerformance>();
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -128,5 +129,34 @@ namespace Greenshot.Tests
|
|||
await outputStream.CopyToAsync(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Test if capturing works
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Test_BitmapCapture()
|
||||
{
|
||||
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
|
||||
{
|
||||
Interlace = PngInterlaceOption.Off
|
||||
};
|
||||
encoder.Frames.Add(BitmapFrame.Create(screenBitmapCapture.CurrentFrameAsBitmap().NativeBitmapSource));
|
||||
encoder.Save(fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue