| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- using System;
- using Avalonia.Platform;
- namespace Avalonia.Media.Imaging;
- internal interface IPixelFormatWriter
- {
- void WriteNext(Rgba8888Pixel pixel);
- void Reset(IntPtr address);
- }
- internal static unsafe 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;
- }
- private static void Write<T>(
- ReadOnlySpan<Rgba8888Pixel> pixels,
- IntPtr dest,
- PixelSize size,
- int stride,
- AlphaFormat alphaFormat,
- AlphaFormat srcAlphaFormat) where T : struct, IPixelFormatWriter
- {
- var writer = new T();
- var w = size.Width;
- var h = size.Height;
- var count = 0;
- for (var y = 0; y < h; y++)
- {
- writer.Reset(dest + stride * y);
- for (var x = 0; x < w; x++)
- {
- writer.WriteNext(GetConvertedPixel(pixels[count++], srcAlphaFormat, alphaFormat));
- }
- }
- }
- 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
- };
- }
- public static void Write(
- ReadOnlySpan<Rgba8888Pixel> pixels,
- IntPtr dest,
- PixelSize size,
- int stride,
- PixelFormat format,
- AlphaFormat alphaFormat,
- AlphaFormat srcAlphaFormat)
- {
- switch (format.FormatEnum)
- {
- case PixelFormatEnum.Rgb565:
- Write<Bgr565PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Rgba8888:
- Write<Rgba8888PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Bgra8888:
- Write<Bgra8888PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.BlackWhite:
- Write<BlackWhitePixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Gray2:
- Write<Gray2PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Gray4:
- Write<Gray4PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Gray8:
- Write<Gray8PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Gray16:
- Write<Gray16PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Gray32Float:
- Write<Gray32FloatPixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Rgba64:
- Write<Rgba64PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Rgb24:
- Write<Rgb24PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Bgr24:
- Write<Bgr24PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Bgr555:
- Write<Bgr555PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- case PixelFormatEnum.Bgr565:
- Write<Bgr565PixelFormatWriter>(pixels, dest, size, stride, alphaFormat, srcAlphaFormat);
- break;
- default:
- throw new NotSupportedException($"Pixel format {format} is not supported");
- }
- }
- }
|