Browse Source
Introduce PixelFormatTranscoder Introduce Bitmap.CopyPixels that transcodes pixel and alpha formatpull/12940/head
committed by
GitHub
17 changed files with 1093 additions and 112 deletions
@ -0,0 +1,154 @@ |
|||
using System; |
|||
using Avalonia.Platform; |
|||
namespace Avalonia.Media.Imaging; |
|||
|
|||
internal static unsafe class PixelFormatTranscoder |
|||
{ |
|||
public static void Transcode( |
|||
IntPtr source, |
|||
PixelSize srcSize, |
|||
int sourceStride, |
|||
PixelFormat srcFormat, |
|||
AlphaFormat srcAlphaFormat, |
|||
IntPtr dest, |
|||
int destStride, |
|||
PixelFormat destFormat, |
|||
AlphaFormat destAlphaFormat) |
|||
{ |
|||
var reader = GetReader(srcFormat); |
|||
var writer = GetWriter(destFormat); |
|||
|
|||
var w = srcSize.Width; |
|||
var h = srcSize.Height; |
|||
|
|||
for (var y = 0; y < h; y++) |
|||
{ |
|||
reader.Reset(source + sourceStride * y); |
|||
|
|||
writer.Reset(dest + destStride * y); |
|||
|
|||
for (var x = 0; x < w; x++) |
|||
{ |
|||
writer.WriteNext(GetConvertedPixel(reader.ReadNext(), srcAlphaFormat, destAlphaFormat)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static Rgba8888Pixel GetConvertedPixel(Rgba8888Pixel pixel, AlphaFormat sourceAlpha, AlphaFormat destAlpha) |
|||
{ |
|||
if (sourceAlpha != destAlpha) |
|||
{ |
|||
if (sourceAlpha == AlphaFormat.Premul && destAlpha != AlphaFormat.Premul) |
|||
{ |
|||
return ConvertFromPremultiplied(pixel); |
|||
} |
|||
|
|||
if (sourceAlpha != AlphaFormat.Premul && destAlpha == AlphaFormat.Premul) |
|||
{ |
|||
return ConvertToPremultiplied(pixel); |
|||
} |
|||
} |
|||
|
|||
return pixel; |
|||
} |
|||
|
|||
private static Rgba8888Pixel ConvertToPremultiplied(Rgba8888Pixel pixel) |
|||
{ |
|||
var factor = pixel.A / 255F; |
|||
|
|||
return new Rgba8888Pixel |
|||
{ |
|||
R = (byte)(pixel.R * factor), |
|||
G = (byte)(pixel.G * factor), |
|||
B = (byte)(pixel.B * factor), |
|||
A = pixel.A |
|||
}; |
|||
} |
|||
|
|||
private static Rgba8888Pixel ConvertFromPremultiplied(Rgba8888Pixel pixel) |
|||
{ |
|||
var factor = 1F / (pixel.A / 255F); |
|||
|
|||
return new Rgba8888Pixel |
|||
{ |
|||
R = (byte)(pixel.R * factor), |
|||
G = (byte)(pixel.G * factor), |
|||
B = (byte)(pixel.B * factor), |
|||
A = pixel.A |
|||
}; |
|||
} |
|||
|
|||
private static IPixelFormatReader GetReader(PixelFormat format) |
|||
{ |
|||
switch (format.FormatEnum) |
|||
{ |
|||
case PixelFormatEnum.Rgb565: |
|||
return new PixelFormatReader.Bgr565PixelFormatReader(); |
|||
case PixelFormatEnum.Rgba8888: |
|||
return new PixelFormatReader.Rgba8888PixelFormatReader(); |
|||
case PixelFormatEnum.Bgra8888: |
|||
return new PixelFormatReader.Bgra8888PixelFormatReader(); |
|||
case PixelFormatEnum.BlackWhite: |
|||
return new PixelFormatReader.BlackWhitePixelFormatReader(); |
|||
case PixelFormatEnum.Gray2: |
|||
return new PixelFormatReader.Gray2PixelFormatReader(); |
|||
case PixelFormatEnum.Gray4: |
|||
return new PixelFormatReader.Gray4PixelFormatReader(); |
|||
case PixelFormatEnum.Gray8: |
|||
return new PixelFormatReader.Gray8PixelFormatReader(); |
|||
case PixelFormatEnum.Gray16: |
|||
return new PixelFormatReader.Gray16PixelFormatReader(); |
|||
case PixelFormatEnum.Gray32Float: |
|||
return new PixelFormatReader.Gray32FloatPixelFormatReader(); |
|||
case PixelFormatEnum.Rgba64: |
|||
return new PixelFormatReader.Rgba64PixelFormatReader(); |
|||
case PixelFormatEnum.Rgb24: |
|||
return new PixelFormatReader.Rgb24PixelFormatReader(); |
|||
case PixelFormatEnum.Bgr24: |
|||
return new PixelFormatReader.Bgr24PixelFormatReader(); |
|||
case PixelFormatEnum.Bgr555: |
|||
return new PixelFormatReader.Bgr555PixelFormatReader(); |
|||
case PixelFormatEnum.Bgr565: |
|||
return new PixelFormatReader.Bgr565PixelFormatReader(); |
|||
default: |
|||
throw new NotSupportedException($"Pixel format {format} is not supported"); |
|||
} |
|||
} |
|||
|
|||
private static IPixelFormatWriter GetWriter(PixelFormat format) |
|||
{ |
|||
switch (format.FormatEnum) |
|||
{ |
|||
case PixelFormatEnum.Rgb565: |
|||
return new PixelFormatWriter.Bgr565PixelFormatWriter(); |
|||
case PixelFormatEnum.Rgba8888: |
|||
return new PixelFormatWriter.Rgba8888PixelFormatWriter(); |
|||
case PixelFormatEnum.Bgra8888: |
|||
return new PixelFormatWriter.Bgra8888PixelFormatWriter(); |
|||
case PixelFormatEnum.BlackWhite: |
|||
return new PixelFormatWriter.BlackWhitePixelFormatWriter(); |
|||
case PixelFormatEnum.Gray2: |
|||
return new PixelFormatWriter.Gray2PixelFormatWriter(); |
|||
case PixelFormatEnum.Gray4: |
|||
return new PixelFormatWriter.Gray4PixelFormatWriter(); |
|||
case PixelFormatEnum.Gray8: |
|||
return new PixelFormatWriter.Gray8PixelFormatWriter(); |
|||
case PixelFormatEnum.Gray16: |
|||
return new PixelFormatWriter.Gray16PixelFormatWriter(); |
|||
case PixelFormatEnum.Gray32Float: |
|||
return new PixelFormatWriter.Gray32FloatPixelFormatWriter(); |
|||
case PixelFormatEnum.Rgba64: |
|||
return new PixelFormatWriter.Rgba64PixelFormatWriter(); |
|||
case PixelFormatEnum.Rgb24: |
|||
return new PixelFormatWriter.Rgb24PixelFormatWriter(); |
|||
case PixelFormatEnum.Bgr24: |
|||
return new PixelFormatWriter.Bgr24PixelFormatWriter(); |
|||
case PixelFormatEnum.Bgr555: |
|||
return new PixelFormatWriter.Bgr555PixelFormatWriter(); |
|||
case PixelFormatEnum.Bgr565: |
|||
return new PixelFormatWriter.Bgr565PixelFormatWriter(); |
|||
default: |
|||
throw new NotSupportedException($"Pixel format {format} is not supported"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,324 @@ |
|||
using System; |
|||
namespace Avalonia.Media.Imaging; |
|||
|
|||
internal interface IPixelFormatWriter |
|||
{ |
|||
void WriteNext(Rgba8888Pixel pixel); |
|||
void Reset(IntPtr address); |
|||
} |
|||
|
|||
internal static class PixelFormatWriter |
|||
{ |
|||
public unsafe struct Rgb24PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private byte* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
addr[0] = pixel.R; |
|||
addr[1] = pixel.G; |
|||
addr[2] = pixel.B; |
|||
|
|||
_address += 3; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Rgba64PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private Rgba64Pixel* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
*addr = new Rgba64Pixel((ushort)(pixel.R << 8), (ushort)(pixel.G << 8), (ushort)(pixel.B << 8), (ushort)(pixel.A << 8)); |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (Rgba64Pixel*)address; |
|||
} |
|||
|
|||
public unsafe struct Rgba8888PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private Rgba8888Pixel* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
*addr = pixel; |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (Rgba8888Pixel*)address; |
|||
} |
|||
|
|||
public unsafe struct Bgra8888PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private byte* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
addr[0] = pixel.B; |
|||
addr[1] = pixel.G; |
|||
addr[2] = pixel.R; |
|||
addr[3] = pixel.A; |
|||
|
|||
_address += 4; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Bgr24PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private byte* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
addr[2] = pixel.R; |
|||
addr[1] = pixel.G; |
|||
addr[0] = pixel.B; |
|||
|
|||
_address += 3; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Bgra32PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private byte* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
addr[3] = pixel.A; |
|||
addr[2] = pixel.R; |
|||
addr[1] = pixel.G; |
|||
addr[0] = pixel.B; |
|||
|
|||
_address += 4; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Bgr565PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private ushort* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
*addr = Pack(pixel); |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (ushort*)address; |
|||
|
|||
private static ushort Pack(Rgba8888Pixel pixel) |
|||
{ |
|||
return (ushort)((((int)Math.Round(pixel.R / 255F * 31F) & 0x1F) << 11) |
|||
| (((int)Math.Round(pixel.G / 255F * 63F) & 0x3F) << 5) |
|||
| ((int)Math.Round(pixel.B / 255F * 31F) & 0x1F)); |
|||
} |
|||
} |
|||
|
|||
public unsafe struct Bgr555PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private ushort* _address; |
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
*addr = Pack(pixel); |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (ushort*)address; |
|||
|
|||
private static ushort Pack(Rgba8888Pixel pixel) |
|||
{ |
|||
return (ushort)( |
|||
(((int)Math.Round(pixel.R / 255F * 31F) & 0x1F) << 10) |
|||
| (((int)Math.Round(pixel.G / 255F * 31F) & 0x1F) << 5) |
|||
| (((int)Math.Round(pixel.B / 255F * 31F) & 0x1F) << 0)); |
|||
} |
|||
} |
|||
|
|||
public unsafe struct Gray32FloatPixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private float* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
*addr = Pack(pixel); |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
private static float Pack(Rgba8888Pixel pixel) |
|||
{ |
|||
return (float)Math.Pow(pixel.R / 255F, 2.2); |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (float*)address; |
|||
} |
|||
|
|||
public unsafe struct BlackWhitePixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private int _bit; |
|||
private byte* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
var grayscale = Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
var value = grayscale > 0x7F ? 1 : 0; |
|||
|
|||
var shift = 7 - _bit; |
|||
var mask = 1 << shift; |
|||
|
|||
*addr = (byte)((*addr & ~mask) | value << shift); |
|||
|
|||
_bit++; |
|||
|
|||
if (_bit == 8) |
|||
{ |
|||
_address++; |
|||
|
|||
_bit = 0; |
|||
} |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Gray2PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private int _bit; |
|||
private byte* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
var value = 0; |
|||
|
|||
var grayscale = (byte)Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
if (grayscale > 0 && grayscale <= 0x55) |
|||
{ |
|||
//01
|
|||
value = 1; |
|||
} |
|||
|
|||
if (grayscale > 0x55 && grayscale <= 0xAA) |
|||
{ |
|||
//10
|
|||
|
|||
value = 2; |
|||
} |
|||
|
|||
if (grayscale > 0xAA) |
|||
{ |
|||
//11
|
|||
value = 3; |
|||
} |
|||
|
|||
var shift = 6 - _bit; |
|||
var mask = 3 << shift; |
|||
|
|||
*addr = (byte)((*addr & ~mask) | value << shift); |
|||
|
|||
_bit += 2; |
|||
|
|||
if (_bit == 8) |
|||
{ |
|||
_address++; |
|||
_bit = 0; |
|||
} |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Gray4PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private int _bit; |
|||
private byte* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
var grayscale = (byte)Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
var value = (byte)(grayscale / 255F * 0xF); |
|||
|
|||
var shift = 4 - _bit; |
|||
var mask = 0xF << shift; |
|||
|
|||
*addr = (byte)((*addr & ~mask) | value << shift); |
|||
|
|||
_bit += 4; |
|||
|
|||
if (_bit == 8) |
|||
{ |
|||
_address++; |
|||
_bit = 0; |
|||
} |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Gray8PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private byte* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
var grayscale = (byte)Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
*addr = grayscale; |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (byte*)address; |
|||
} |
|||
|
|||
public unsafe struct Gray16PixelFormatWriter : IPixelFormatWriter |
|||
{ |
|||
private ushort* _address; |
|||
|
|||
public void WriteNext(Rgba8888Pixel pixel) |
|||
{ |
|||
var addr = _address; |
|||
|
|||
var grayscale = (ushort)Math.Round((0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B) * 0x0101); |
|||
|
|||
*addr = grayscale; |
|||
|
|||
_address++; |
|||
} |
|||
|
|||
public void Reset(IntPtr address) => _address = (ushort*)address; |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -1,7 +1,16 @@ |
|||
using Avalonia.Metadata; |
|||
|
|||
namespace Avalonia.Platform; |
|||
|
|||
public interface IReadableBitmapImpl |
|||
{ |
|||
PixelFormat? Format { get; } |
|||
ILockedFramebuffer Lock(); |
|||
} |
|||
} |
|||
|
|||
//TODO12: Remove me once we can change IReadableBitmapImpl
|
|||
[Unstable] |
|||
public interface IReadableBitmapWithAlphaImpl : IReadableBitmapImpl |
|||
{ |
|||
AlphaFormat? AlphaFormat { get; } |
|||
} |
|||
|
|||
@ -0,0 +1,355 @@ |
|||
using System; |
|||
using Avalonia.Media.Imaging; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Base.UnitTests.Media.Imaging |
|||
{ |
|||
public class PixelFormatWriterTests |
|||
{ |
|||
private static readonly Rgba8888Pixel s_white = new Rgba8888Pixel |
|||
{ |
|||
A = 255, |
|||
B = 255, |
|||
G = 255, |
|||
R = 255 |
|||
}; |
|||
|
|||
private static readonly Rgba8888Pixel s_black = new Rgba8888Pixel |
|||
{ |
|||
A = 255, |
|||
B = 0, |
|||
G = 0, |
|||
R = 0 |
|||
}; |
|||
|
|||
[Fact] |
|||
public void Should_Write_Bgr555() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Bgr555), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Bgr555PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Bgr555PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { G = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { G = 255, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { B = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { B = 255, A = 255 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Bgra8888() |
|||
{ |
|||
var sourceMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Bgra8888), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(3, 1)); |
|||
|
|||
var sourceWriter = new PixelFormatWriter.Bgra8888PixelFormatWriter(); |
|||
var sourceReader = new PixelFormatReader.Bgra8888PixelFormatReader(); |
|||
|
|||
sourceWriter.Reset(sourceMemory.Address); |
|||
sourceReader.Reset(sourceMemory.Address); |
|||
|
|||
sourceWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255 }, sourceReader.ReadNext()); |
|||
|
|||
sourceWriter.WriteNext(new Rgba8888Pixel { G = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { G = 255 }, sourceReader.ReadNext()); |
|||
|
|||
sourceWriter.WriteNext(new Rgba8888Pixel { B = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { B = 255 }, sourceReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Rgba8888() |
|||
{ |
|||
var sourceMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Rgba8888), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Rgba8888PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Rgba8888PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(sourceMemory.Address); |
|||
pixelReader.Reset(sourceMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255, G = 125, B = 125, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, G = 125, B = 125, A = 125 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 255, B = 125, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 255, B = 125, A = 125 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 125, B = 255, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 125, B = 255, A = 125 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Rgb24() |
|||
{ |
|||
var sourceMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Rgb24), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Rgb24PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Rgb24PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(sourceMemory.Address); |
|||
pixelReader.Reset(sourceMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255, G = 125, B = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, G = 125, B = 125, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 255, B = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 255, B = 125, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 125, B = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 125, B = 255, A = 255 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void Should_Write_Rgba64() |
|||
{ |
|||
var sourceMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Rgba64), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Rgba64PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Rgba64PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(sourceMemory.Address); |
|||
pixelReader.Reset(sourceMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255, G = 125, B = 125, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, G = 125, B = 125, A = 125 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 255, B = 125, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 255, B = 125, A = 125 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125, G = 125, B = 255, A = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 125, B = 255, A = 125 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Bgr565() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Bgr565), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Bgr565PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Bgr565PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { G = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { G = 255, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { B = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { B = 255, A = 255 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Gray32Float() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Gray32Float), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Gray32FloatPixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Gray32FloatPixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 255, G = 255, B = 255, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 125 }); |
|||
Assert.Equal(new Rgba8888Pixel { R = 125, G = 125, B = 125, A = 255 }, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel()); |
|||
Assert.Equal(new Rgba8888Pixel { A = 255 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_BlackWhite() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.BlackWhite), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.BlackWhitePixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.BlackWhitePixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(s_white); |
|||
Assert.Equal(s_white, pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(s_black); |
|||
Assert.Equal(s_black, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Gray2() |
|||
{ |
|||
var palette = new[] |
|||
{ |
|||
s_black, |
|||
new Rgba8888Pixel |
|||
{ |
|||
A = 255, B = 0x55, G = 0x55, R = 0x55 |
|||
}, |
|||
new Rgba8888Pixel |
|||
{ |
|||
A = 255, B = 0xAA, G = 0xAA, R = 0xAA |
|||
}, |
|||
s_white |
|||
}; |
|||
|
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Gray2), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Gray2PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Gray2PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(palette[0]); |
|||
Assert.Equal(palette[0], pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(palette[1]); |
|||
Assert.Equal(palette[1], pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(palette[2]); |
|||
Assert.Equal(palette[2], pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(palette[3]); |
|||
Assert.Equal(palette[3], pixelReader.ReadNext()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Gray4() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Gray4), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Gray4PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Gray4PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(GetGray4(new Rgba8888Pixel { R = 255 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 17 }); |
|||
Assert.Equal(GetGray4(new Rgba8888Pixel { R = 17 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel()); |
|||
Assert.Equal(new Rgba8888Pixel { A = 255 }, pixelReader.ReadNext()); |
|||
} |
|||
|
|||
private static Rgba8888Pixel GetGray4(Rgba8888Pixel pixel) |
|||
{ |
|||
var grayscale = (byte)Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
var value = (byte)(grayscale / 255F * 0xF); |
|||
|
|||
value = (byte)(value | (value << 4)); |
|||
|
|||
return new Rgba8888Pixel(value, value, value, 255); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Gray8() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Gray8), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Gray8PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Gray8PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(GetGray8(new Rgba8888Pixel { R = 255 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 120 }); |
|||
Assert.Equal(GetGray8(new Rgba8888Pixel { R = 120 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel()); |
|||
Assert.Equal(GetGray8(new Rgba8888Pixel { A = 255 }), pixelReader.ReadNext()); |
|||
} |
|||
|
|||
private static Rgba8888Pixel GetGray8(Rgba8888Pixel pixel) |
|||
{ |
|||
var value = (byte)Math.Round(0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B); |
|||
|
|||
return new Rgba8888Pixel(value, value, value, 255); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Write_Gray16() |
|||
{ |
|||
var bitmapMemory = new BitmapMemory( |
|||
new Platform.PixelFormat(Platform.PixelFormatEnum.Gray16), |
|||
Platform.AlphaFormat.Unpremul, |
|||
new PixelSize(10, 10)); |
|||
|
|||
var pixelWriter = new PixelFormatWriter.Gray16PixelFormatWriter(); |
|||
var pixelReader = new PixelFormatReader.Gray16PixelFormatReader(); |
|||
|
|||
pixelWriter.Reset(bitmapMemory.Address); |
|||
pixelReader.Reset(bitmapMemory.Address); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 255 }); |
|||
Assert.Equal(GetGray16(new Rgba8888Pixel { R = 255 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel { R = 120 }); |
|||
Assert.Equal(GetGray16(new Rgba8888Pixel { R = 120 }), pixelReader.ReadNext()); |
|||
|
|||
pixelWriter.WriteNext(new Rgba8888Pixel()); |
|||
Assert.Equal(GetGray16(new Rgba8888Pixel { A = 255 }), pixelReader.ReadNext()); |
|||
} |
|||
|
|||
private static Rgba8888Pixel GetGray16(Rgba8888Pixel pixel) |
|||
{ |
|||
var grayscale = (ushort)Math.Round((0.299F * pixel.R + 0.587F * pixel.G + 0.114F * pixel.B) * 0x0101); |
|||
|
|||
var value = (byte)(grayscale >> 8); |
|||
|
|||
return new Rgba8888Pixel(value, value, value, 255); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue