mirror of
https://github.com/greenshot/greenshot
synced 2025-08-22 14:24:43 -07:00
Optimized the ScaleX code, now working on the blur [skip ci]
This commit is contained in:
parent
694e2f3f4d
commit
803ddf3b24
6 changed files with 345 additions and 354 deletions
|
@ -18,7 +18,6 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Greenshot.Gfx.Structs;
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
|
@ -89,61 +88,61 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
var halfRange = range / 2;
|
||||
|
||||
Parallel.For(0, unmanagedBitmap.Height, y =>
|
||||
for(var y = 0; y <unmanagedBitmap.Height; y++)
|
||||
{
|
||||
unsafe {
|
||||
var rgb32 = unmanagedBitmap[y];
|
||||
Span<Bgr32> averages = stackalloc Bgr32[range];
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
var hits = halfRange;
|
||||
for (var x = 0; x < halfRange; x++)
|
||||
{
|
||||
ref Bgr32 color = ref rgb32[x];
|
||||
var rgb32 = unmanagedBitmap[y];
|
||||
Span<Bgr32> averages = stackalloc Bgr32[range];
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
var hits = halfRange;
|
||||
for (var x = 0; x < halfRange; x++)
|
||||
{
|
||||
ref var color = ref rgb32[x];
|
||||
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
for (var x = 0; x < unmanagedBitmap.Width; x++)
|
||||
{
|
||||
var leftSide = x - halfRange - 1;
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
// Get value at the left side of range
|
||||
ref var color = ref rgb32[leftSide];
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var rightSide = x + halfRange;
|
||||
if (rightSide < unmanagedBitmap.Width)
|
||||
{
|
||||
ref var color = ref rgb32[rightSide];
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var x = 0; x < unmanagedBitmap.Width; x++)
|
||||
|
||||
ref var average = ref averages[x % range];
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (leftSide < 0)
|
||||
{
|
||||
var leftSide = x - halfRange - 1;
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
// Get value at the left side of range
|
||||
ref Bgr32 color = ref rgb32[leftSide];
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var rightSide = x + halfRange;
|
||||
if (rightSide < unmanagedBitmap.Width)
|
||||
{
|
||||
ref Bgr32 color = ref rgb32[rightSide];
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
|
||||
ref Bgr32 average = ref averages[x % range];
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
// Now we can write the value from the calculated avarages
|
||||
var readLocation = (leftSide % range);
|
||||
|
||||
rgb32[leftSide] = averages[readLocation];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we can write the value from the calculated averages
|
||||
var readLocation = (leftSide % range);
|
||||
|
||||
rgb32[leftSide] = averages[readLocation];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -154,61 +153,61 @@ namespace Greenshot.Gfx
|
|||
private static void BoxBlurVertical(UnmanagedBitmap<Bgr32> unmanagedBitmap, int range)
|
||||
{
|
||||
var halfRange = range / 2;
|
||||
Parallel.For(0, unmanagedBitmap.Width, x =>
|
||||
for(var x = 0; x <unmanagedBitmap.Width; x++)
|
||||
{
|
||||
unsafe {
|
||||
var rgb32 = unmanagedBitmap.Span;
|
||||
Span<Bgr32> averages = stackalloc Bgr32[range];
|
||||
var hits = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
for (var y = 0; y < halfRange; y++)
|
||||
var rgb32 = unmanagedBitmap.Span;
|
||||
Span<Bgr32> averages = stackalloc Bgr32[range];
|
||||
var hits = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
for (var y = 0; y < halfRange; y++)
|
||||
{
|
||||
ref var color = ref rgb32[(y * unmanagedBitmap.Width) + x];
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var y = 0; y < unmanagedBitmap.Height; y++)
|
||||
{
|
||||
var topSide = y - halfRange - 1;
|
||||
if (topSide >= 0)
|
||||
{
|
||||
ref Bgr32 color = ref rgb32[(y * unmanagedBitmap.Width) + x];
|
||||
// Get value at the top side of range
|
||||
ref var color = ref rgb32[x + (topSide * unmanagedBitmap.Width)];
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var bottomSide = y + halfRange;
|
||||
if (bottomSide < unmanagedBitmap.Height)
|
||||
{
|
||||
ref var color = ref rgb32[x + (bottomSide * unmanagedBitmap.Width)];
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var y = 0; y < unmanagedBitmap.Height; y++)
|
||||
|
||||
ref var average = ref averages[y % range];
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (topSide < 0)
|
||||
{
|
||||
var topSide = y - halfRange - 1;
|
||||
if (topSide >= 0)
|
||||
{
|
||||
// Get value at the top side of range
|
||||
ref Bgr32 color = ref rgb32[x + (topSide * unmanagedBitmap.Width)];
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var bottomSide = y + halfRange;
|
||||
if (bottomSide < unmanagedBitmap.Height)
|
||||
{
|
||||
ref Bgr32 color = ref rgb32[x + (bottomSide * unmanagedBitmap.Width)];
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
|
||||
ref Bgr32 average = ref averages[y % range];
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (topSide >= 0)
|
||||
{
|
||||
// Write the value from the calculated avarages
|
||||
var readLocation = topSide % range;
|
||||
|
||||
rgb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write the value from the calculated averages
|
||||
var readLocation = topSide % range;
|
||||
|
||||
rgb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -220,65 +219,65 @@ namespace Greenshot.Gfx
|
|||
{
|
||||
var halfRange = range / 2;
|
||||
|
||||
Parallel.For(0, unmanagedBitmap.Height, y =>
|
||||
for(var y = 0; y <unmanagedBitmap.Height; y++)
|
||||
{
|
||||
unsafe {
|
||||
var argb32 = unmanagedBitmap[y];
|
||||
Span<Bgra32> averages = stackalloc Bgra32[range];
|
||||
var a = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
var hits = halfRange;
|
||||
for (var x = 0; x < halfRange; x++)
|
||||
var argb32 = unmanagedBitmap[y];
|
||||
Span<Bgra32> averages = stackalloc Bgra32[range];
|
||||
var a = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
var hits = halfRange;
|
||||
for (var x = 0; x < halfRange; x++)
|
||||
{
|
||||
ref var color = ref argb32[x];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
}
|
||||
for (var x = 0; x < unmanagedBitmap.Width; x++)
|
||||
{
|
||||
var leftSide = x - halfRange - 1;
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
ref Bgra32 color = ref argb32[x];
|
||||
// Get value at the left side of range
|
||||
ref var color = ref argb32[leftSide];
|
||||
a -= color.A;
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var rightSide = x + halfRange;
|
||||
if (rightSide < unmanagedBitmap.Width)
|
||||
{
|
||||
ref var color = ref argb32[rightSide];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var x = 0; x < unmanagedBitmap.Width; x++)
|
||||
|
||||
ref var average = ref averages[x % range];
|
||||
average.A = (byte)(a / hits);
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (leftSide < 0)
|
||||
{
|
||||
var leftSide = x - halfRange - 1;
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
// Get value at the left side of range
|
||||
ref Bgra32 color = ref argb32[leftSide];
|
||||
a -= color.A;
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var rightSide = x + halfRange;
|
||||
if (rightSide < unmanagedBitmap.Width)
|
||||
{
|
||||
ref Bgra32 color = ref argb32[rightSide];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
|
||||
ref Bgra32 average = ref averages[x % range];
|
||||
average.A = (byte)(a / hits);
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (leftSide >= 0)
|
||||
{
|
||||
// Now we can write the value from the calculated avarages
|
||||
var readLocation = leftSide % range;
|
||||
|
||||
argb32[leftSide] = averages[readLocation];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we can write the value from the calculated averages
|
||||
var readLocation = leftSide % range;
|
||||
|
||||
argb32[leftSide] = averages[readLocation];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -289,67 +288,66 @@ namespace Greenshot.Gfx
|
|||
private static void BoxBlurVertical(UnmanagedBitmap<Bgra32> unmanagedBitmap, int range)
|
||||
{
|
||||
var halfRange = range / 2;
|
||||
Parallel.For(0, unmanagedBitmap.Width, x =>
|
||||
for(var x = 0; x <unmanagedBitmap.Width; x++)
|
||||
{
|
||||
unsafe
|
||||
var argb32 = unmanagedBitmap.Span;
|
||||
Span<Bgra32> averages = stackalloc Bgra32[range];
|
||||
var hits = 0;
|
||||
var a = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
for (var y = 0; y < halfRange; y++)
|
||||
{
|
||||
var argb32 = unmanagedBitmap.Span;
|
||||
Span<Bgra32> averages = stackalloc Bgra32[range];
|
||||
var hits = 0;
|
||||
var a = 0;
|
||||
var r = 0;
|
||||
var g = 0;
|
||||
var b = 0;
|
||||
for (var y = 0; y < halfRange; y++)
|
||||
ref var color = ref argb32[x + (y * unmanagedBitmap.Width)];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var y = 0; y < unmanagedBitmap.Height; y++)
|
||||
{
|
||||
var topSide = y - halfRange - 1;
|
||||
if (topSide >= 0)
|
||||
{
|
||||
ref Bgra32 color = ref argb32[x + (y * unmanagedBitmap.Width)];
|
||||
// Get value at the top side of range
|
||||
ref var color = ref argb32[x + (topSide * unmanagedBitmap.Width)];
|
||||
a -= color.A;
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var bottomSide = y + halfRange;
|
||||
if (bottomSide < unmanagedBitmap.Height)
|
||||
{
|
||||
ref var color = ref argb32[x + (bottomSide * unmanagedBitmap.Width)];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
for (var y = 0; y < unmanagedBitmap.Height; y++)
|
||||
|
||||
ref var average = ref averages[(y % range)];
|
||||
average.A = (byte)(a / hits);
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (topSide < 0)
|
||||
{
|
||||
var topSide = y - halfRange - 1;
|
||||
if (topSide >= 0)
|
||||
{
|
||||
// Get value at the top side of range
|
||||
ref Bgra32 color = ref argb32[x + (topSide * unmanagedBitmap.Width)];
|
||||
a -= color.A;
|
||||
r -= color.R;
|
||||
g -= color.G;
|
||||
b -= color.B;
|
||||
hits--;
|
||||
}
|
||||
|
||||
var bottomSide = y + halfRange;
|
||||
if (bottomSide < unmanagedBitmap.Height)
|
||||
{
|
||||
ref Bgra32 color = ref argb32[x + (bottomSide * unmanagedBitmap.Width)];
|
||||
a += color.A;
|
||||
r += color.R;
|
||||
g += color.G;
|
||||
b += color.B;
|
||||
hits++;
|
||||
}
|
||||
|
||||
ref Bgra32 average = ref averages[(y % range)];
|
||||
average.A = (byte)(a / hits);
|
||||
average.R = (byte)(r / hits);
|
||||
average.G = (byte)(g / hits);
|
||||
average.B = (byte)(b / hits);
|
||||
|
||||
if (topSide >= 0)
|
||||
{
|
||||
// Write the value from the calculated avarages
|
||||
var readLocation = (topSide % range);
|
||||
|
||||
argb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write the value from the calculated averages
|
||||
var readLocation = (topSide % range);
|
||||
|
||||
argb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Greenshot.Gfx
|
||||
|
@ -44,45 +45,44 @@ namespace Greenshot.Gfx
|
|||
|
||||
var sourceWidth = sourceBitmap.Width;
|
||||
var destinationWidth = destinationBitmap.Width;
|
||||
ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span);
|
||||
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span);
|
||||
ref var destinationPointer = ref Unsafe.As<TPixelLayout, uint>(ref destinationBitmap.Span.GetPinnableReference());
|
||||
ref var sourcePointer = ref Unsafe.As<TPixelLayout, uint>(ref sourceBitmap.Span.GetPinnableReference());
|
||||
for (var y = 0; y < sourceBitmap.Height; y++)
|
||||
{
|
||||
var sourceYOffset = y * sourceWidth;
|
||||
var destinationYOffset = (y << 1) * destinationWidth;
|
||||
for (var x = 0; x < sourceWidth; x++)
|
||||
{
|
||||
var sourceOffset = sourceYOffset + x;
|
||||
ref readonly uint colorE = ref sourceSpan[sourceOffset];
|
||||
ref var colorE = ref Unsafe.Add(ref sourcePointer, sourceYOffset + x);
|
||||
|
||||
ref readonly uint colorB = ref colorE;
|
||||
ref readonly var colorB = ref colorE;
|
||||
if (y != 0)
|
||||
{
|
||||
colorB = ref sourceSpan[sourceOffset - sourceWidth];
|
||||
colorB = ref Unsafe.Subtract(ref colorE, sourceWidth);
|
||||
}
|
||||
|
||||
ref readonly uint colorH = ref colorE;
|
||||
ref readonly var colorH = ref colorE;
|
||||
if (y != sourceBitmap.Height - 1)
|
||||
{
|
||||
colorH = ref sourceSpan[sourceOffset + sourceWidth];
|
||||
colorH = ref Unsafe.Add(ref colorE, sourceWidth);
|
||||
}
|
||||
|
||||
ref readonly uint colorD = ref colorE;
|
||||
ref readonly var colorD = ref colorE;
|
||||
if (x > 0)
|
||||
{
|
||||
colorD = ref sourceSpan[sourceOffset - 1];
|
||||
colorD = ref Unsafe.Subtract(ref colorE, 1);
|
||||
}
|
||||
|
||||
ref readonly uint colorF = ref colorE;
|
||||
ref readonly var colorF = ref colorE;
|
||||
if (x < sourceBitmap.Width - 1)
|
||||
{
|
||||
colorF = ref sourceSpan[sourceOffset + 1];
|
||||
colorF = ref Unsafe.Add(ref colorE, 1);
|
||||
}
|
||||
|
||||
ref readonly uint colorE0 = ref colorE;
|
||||
ref readonly uint colorE1 = ref colorE;
|
||||
ref readonly uint colorE2 = ref colorE;
|
||||
ref readonly uint colorE3 = ref colorE;
|
||||
ref readonly var colorE0 = ref colorE;
|
||||
ref readonly var colorE1 = ref colorE;
|
||||
ref readonly var colorE2 = ref colorE;
|
||||
ref readonly var colorE3 = ref colorE;
|
||||
if (colorB != colorH && colorD != colorF)
|
||||
{
|
||||
if (colorH == colorF)
|
||||
|
@ -102,17 +102,19 @@ namespace Greenshot.Gfx
|
|||
colorE0 = ref colorD;
|
||||
}
|
||||
}
|
||||
var destinationOffset = (x << 1) + destinationYOffset;
|
||||
destinationSpan[destinationOffset + 1 + destinationWidth] = colorE3;
|
||||
destinationSpan[destinationOffset + destinationWidth] = colorE2;
|
||||
destinationSpan[destinationOffset + 1] = colorE1;
|
||||
destinationSpan[destinationOffset] = colorE0;
|
||||
|
||||
ref var destColorE0 = ref Unsafe.Add(ref destinationPointer, (x << 1) + destinationYOffset);
|
||||
destColorE0 = colorE0;
|
||||
Unsafe.Add(ref destColorE0, 1 + destinationWidth) = colorE3;
|
||||
Unsafe.Add(ref destColorE0, destinationWidth) = colorE2;
|
||||
Unsafe.Add(ref destColorE0, 1) = colorE1;
|
||||
}
|
||||
}
|
||||
|
||||
return destinationBitmap;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use "Scale3x" algorithm to produce bitmap from the original.
|
||||
/// Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html
|
||||
|
@ -128,133 +130,129 @@ namespace Greenshot.Gfx
|
|||
// Create destination bitmap, where the scaled image is written to
|
||||
var destinationBitmap = new UnmanagedBitmap<TPixelLayout>(sourceBitmap.Width * 3, sourceBitmap.Height * 3);
|
||||
|
||||
ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span);
|
||||
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span);
|
||||
|
||||
var sourceWidth = sourceBitmap.Width;
|
||||
var destinationWidth = destinationBitmap.Width;
|
||||
|
||||
unchecked
|
||||
ref var destinationPointer = ref Unsafe.As<TPixelLayout, uint>(ref destinationBitmap.Span.GetPinnableReference());
|
||||
ref var sourcePointer = ref Unsafe.As<TPixelLayout, uint>(ref sourceBitmap.Span.GetPinnableReference());
|
||||
|
||||
for (var y = 0; y < sourceBitmap.Height; y++)
|
||||
{
|
||||
for (var y = 0; y < sourceBitmap.Height; y++)
|
||||
var sourceYOffset = y * sourceWidth;
|
||||
var destinationYOffset = y * 3 * destinationWidth;
|
||||
for (var x = 0; x < sourceWidth; x++)
|
||||
{
|
||||
var sourceYOffset = y * sourceWidth;
|
||||
var destinationYOffset = y * 3 * destinationWidth;
|
||||
for (var x = 0; x < sourceWidth; x++)
|
||||
ref var colorE = ref Unsafe.Add(ref sourcePointer, sourceYOffset + x);
|
||||
ref readonly var colorA = ref colorE;
|
||||
ref readonly var colorB = ref colorE;
|
||||
ref readonly var colorC = ref colorE;
|
||||
ref readonly var colorD = ref colorE;
|
||||
ref readonly var colorF = ref colorE;
|
||||
ref readonly var colorG = ref colorE;
|
||||
ref readonly var colorH = ref colorE;
|
||||
ref readonly var colorI = ref colorE;
|
||||
|
||||
if (y != 0 && x != 0)
|
||||
{
|
||||
var sourceOffset = sourceYOffset + x;
|
||||
ref readonly uint colorE = ref sourceSpan[sourceOffset];
|
||||
ref readonly uint colorA = ref colorE;
|
||||
ref readonly uint colorB = ref colorE;
|
||||
ref readonly uint colorC = ref colorE;
|
||||
ref readonly uint colorD = ref colorE;
|
||||
ref readonly uint colorF = ref colorE;
|
||||
ref readonly uint colorG = ref colorE;
|
||||
ref readonly uint colorH = ref colorE;
|
||||
ref readonly uint colorI = ref colorE;
|
||||
|
||||
if (y != 0 && x != 0)
|
||||
{
|
||||
colorA = ref sourceSpan[sourceOffset - 1 - sourceWidth];
|
||||
}
|
||||
|
||||
if (y != 0)
|
||||
{
|
||||
colorB = ref sourceSpan[sourceOffset - sourceWidth];
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1 && y != 0)
|
||||
{
|
||||
colorC = ref sourceSpan[sourceOffset + 1 - sourceWidth];
|
||||
}
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
colorD = ref sourceSpan[sourceOffset - 1];
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1)
|
||||
{
|
||||
colorF = ref sourceSpan[sourceOffset + 1];
|
||||
}
|
||||
|
||||
if (x != 0 && y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorG = ref sourceSpan[sourceOffset - 1 + sourceWidth];
|
||||
}
|
||||
|
||||
if (y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorH = ref sourceSpan[sourceOffset + sourceWidth];
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorI = ref sourceSpan[sourceOffset + 1 + sourceWidth];
|
||||
}
|
||||
|
||||
ref readonly uint colorE0 = ref colorE;
|
||||
ref readonly uint colorE1 = ref colorE;
|
||||
ref readonly uint colorE2 = ref colorE;
|
||||
ref readonly uint colorE3 = ref colorE;
|
||||
ref readonly uint colorE4 = ref colorE;
|
||||
ref readonly uint colorE5 = ref colorE;
|
||||
ref readonly uint colorE6 = ref colorE;
|
||||
ref readonly uint colorE7 = ref colorE;
|
||||
ref readonly uint colorE8 = ref colorE;
|
||||
if (colorB != colorH && colorD != colorF)
|
||||
{
|
||||
if (colorH == colorF)
|
||||
{
|
||||
colorE8 = ref colorF;
|
||||
}
|
||||
if (colorD == colorH && colorE != colorI || colorH == colorF && colorE != colorG)
|
||||
{
|
||||
colorE7 = ref colorH;
|
||||
}
|
||||
if (colorD == colorH)
|
||||
{
|
||||
colorE6 = ref colorD;
|
||||
}
|
||||
if (colorB == colorF && colorE != colorI || colorH == colorF && colorE != colorC)
|
||||
{
|
||||
colorE5 = ref colorF;
|
||||
}
|
||||
|
||||
if (colorD == colorB && colorE != colorG || colorD == colorH && colorE != colorA)
|
||||
{
|
||||
colorE3 = ref colorD;
|
||||
}
|
||||
if (colorB == colorF)
|
||||
{
|
||||
colorE2 = ref colorF;
|
||||
}
|
||||
if (colorD == colorB && colorE != colorC || colorB == colorF && colorE != colorA)
|
||||
{
|
||||
colorE1 = ref colorB;
|
||||
}
|
||||
if (colorD == colorB)
|
||||
{
|
||||
colorE0 = ref colorD;
|
||||
}
|
||||
}
|
||||
|
||||
var destinationOffset = x * 3 + destinationYOffset;
|
||||
|
||||
destinationSpan[destinationOffset] = colorE0;
|
||||
destinationSpan[destinationOffset + 1] = colorE1;
|
||||
destinationSpan[destinationOffset + 2] = colorE2;
|
||||
|
||||
destinationOffset += destinationWidth;
|
||||
destinationSpan[destinationOffset] = colorE3;
|
||||
destinationSpan[destinationOffset + 1] = colorE4;
|
||||
destinationSpan[destinationOffset + 2] = colorE5;
|
||||
|
||||
destinationOffset += destinationWidth;
|
||||
destinationSpan[destinationOffset] = colorE6;
|
||||
destinationSpan[destinationOffset + 1] = colorE7;
|
||||
destinationSpan[destinationOffset + 2] = colorE8;
|
||||
colorA = ref Unsafe.Subtract(ref colorE, 1 + sourceWidth);
|
||||
}
|
||||
|
||||
if (y != 0)
|
||||
{
|
||||
colorB = ref Unsafe.Subtract(ref colorE, sourceWidth);
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1 && y != 0)
|
||||
{
|
||||
colorC = ref Unsafe.Subtract(ref colorE, sourceWidth - 1);
|
||||
}
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
colorD = ref Unsafe.Subtract(ref colorE, 1);
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1)
|
||||
{
|
||||
colorF = ref Unsafe.Add(ref colorE, 1);
|
||||
}
|
||||
|
||||
if (x != 0 && y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorG = ref Unsafe.Add(ref colorE, sourceWidth - 1);
|
||||
}
|
||||
|
||||
if (y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorH = ref Unsafe.Add(ref colorE, sourceWidth);
|
||||
}
|
||||
|
||||
if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1)
|
||||
{
|
||||
colorI = ref Unsafe.Add(ref colorE, sourceWidth + 1);
|
||||
}
|
||||
|
||||
ref readonly var colorE0 = ref colorE;
|
||||
ref readonly var colorE1 = ref colorE;
|
||||
ref readonly var colorE2 = ref colorE;
|
||||
ref readonly var colorE3 = ref colorE;
|
||||
ref readonly var colorE4 = ref colorE;
|
||||
ref readonly var colorE5 = ref colorE;
|
||||
ref readonly var colorE6 = ref colorE;
|
||||
ref readonly var colorE7 = ref colorE;
|
||||
ref readonly var colorE8 = ref colorE;
|
||||
if (colorB != colorH && colorD != colorF)
|
||||
{
|
||||
if (colorH == colorF)
|
||||
{
|
||||
colorE8 = ref colorF;
|
||||
}
|
||||
if (colorD == colorH && colorE != colorI || colorH == colorF && colorE != colorG)
|
||||
{
|
||||
colorE7 = ref colorH;
|
||||
}
|
||||
if (colorD == colorH)
|
||||
{
|
||||
colorE6 = ref colorD;
|
||||
}
|
||||
if (colorB == colorF && colorE != colorI || colorH == colorF && colorE != colorC)
|
||||
{
|
||||
colorE5 = ref colorF;
|
||||
}
|
||||
|
||||
if (colorD == colorB && colorE != colorG || colorD == colorH && colorE != colorA)
|
||||
{
|
||||
colorE3 = ref colorD;
|
||||
}
|
||||
if (colorB == colorF)
|
||||
{
|
||||
colorE2 = ref colorF;
|
||||
}
|
||||
if (colorD == colorB && colorE != colorC || colorB == colorF && colorE != colorA)
|
||||
{
|
||||
colorE1 = ref colorB;
|
||||
}
|
||||
if (colorD == colorB)
|
||||
{
|
||||
colorE0 = ref colorD;
|
||||
}
|
||||
}
|
||||
|
||||
var destinationOffset = x * 3 + destinationYOffset;
|
||||
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset) = colorE0;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE1;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE2;
|
||||
|
||||
destinationOffset += destinationWidth;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset) = colorE3;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE4;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE5;
|
||||
|
||||
destinationOffset += destinationWidth;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset) = colorE6;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE7;
|
||||
Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE8;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ namespace Greenshot.PerformanceTests
|
|||
{
|
||||
_unmanagedTestBitmap = new UnmanagedBitmap<Bgr32>(400, 400);
|
||||
_unmanagedTestBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0});
|
||||
using (var bitmap = _unmanagedTestBitmap.NativeBitmap)
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
using (var graphics = Graphics.FromImage(_unmanagedTestBitmap.NativeBitmap))
|
||||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
|
@ -57,7 +56,7 @@ namespace Greenshot.PerformanceTests
|
|||
}
|
||||
}
|
||||
|
||||
//[Benchmark]
|
||||
[Benchmark]
|
||||
public void Blur_FastBitmap()
|
||||
{
|
||||
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White))
|
||||
|
@ -71,14 +70,13 @@ namespace Greenshot.PerformanceTests
|
|||
}
|
||||
}
|
||||
|
||||
//[Benchmark]
|
||||
[Benchmark]
|
||||
public void Blur_UnmanagedBitmap()
|
||||
{
|
||||
using (var unmanagedBitmap = new UnmanagedBitmap<Bgr32>(400, 400))
|
||||
{
|
||||
unmanagedBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
|
||||
using (var bitmap = unmanagedBitmap.NativeBitmap)
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
using (var graphics = Graphics.FromImage(unmanagedBitmap.NativeBitmap))
|
||||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
|
@ -89,7 +87,7 @@ namespace Greenshot.PerformanceTests
|
|||
}
|
||||
|
||||
|
||||
//[Benchmark]
|
||||
[Benchmark]
|
||||
public void Blur_Old()
|
||||
{
|
||||
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White))
|
||||
|
@ -121,19 +119,19 @@ namespace Greenshot.PerformanceTests
|
|||
_unmanagedTestBitmap.Scale2XReference().Dispose();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
//[Benchmark]
|
||||
public void Scale3x_FastBitmap()
|
||||
{
|
||||
ScaleX.Scale3X(_unmanagedTestBitmap).Dispose();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
//[Benchmark]
|
||||
public void Scale3x_Unmanaged()
|
||||
{
|
||||
_unmanagedTestBitmap.Scale3X().Dispose();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
//[Benchmark]
|
||||
public void Scale3x_Unmanaged_Reference()
|
||||
{
|
||||
_unmanagedTestBitmap.Scale3XReference().Dispose();
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace Greenshot.PerformanceTests
|
|||
// ReSharper disable once UnusedParameter.Local
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
//BenchmarkRunner.Run<GfxPerformance>();
|
||||
BenchmarkRunner.Run<CapturePerformance>();
|
||||
BenchmarkRunner.Run<GfxPerformance>();
|
||||
//BenchmarkRunner.Run<CapturePerformance>();
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,19 +70,18 @@ namespace Greenshot.Tests
|
|||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
|
||||
}
|
||||
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
|
||||
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
|
||||
|
||||
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
|
||||
using (var bitmap = bitmapNew.NativeBitmap)
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
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);
|
||||
bitmap.Save(@"new.png", ImageFormat.Png);
|
||||
}
|
||||
bitmapNew.ApplyBoxBlur(10);
|
||||
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
|
||||
|
||||
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Greenshot.Tests
|
|||
{
|
||||
LogSettings.RegisterDefaultLogger<XUnitLogger>(LogLevels.Verbose, testOutputHelper);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Test_Scale2X_UnmanagedBitmap()
|
||||
{
|
||||
|
@ -50,8 +50,7 @@ namespace Greenshot.Tests
|
|||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
}
|
||||
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 });
|
||||
using (var bitmap = bitmapNew.NativeBitmap)
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
|
||||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
|
@ -78,13 +77,12 @@ namespace Greenshot.Tests
|
|||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
}
|
||||
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 });
|
||||
using (var bitmap = bitmapNew.NativeBitmap)
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
|
||||
using (var pen = new SolidBrush(Color.Blue))
|
||||
{
|
||||
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
|
||||
using (var scaledUnmanagedBitmap = bitmapNew.Scale3X())
|
||||
using (var scaledBitmap = ScaleX.Scale2X(bitmapOld))
|
||||
using (var scaledBitmap = ScaleX.Scale3X(bitmapOld))
|
||||
{
|
||||
scaledUnmanagedBitmap.NativeBitmap.Save(@"new3x.png", ImageFormat.Png);
|
||||
scaledBitmap.NativeBitmap.Save(@"old3x.png", ImageFormat.Png);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue