diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs index a6dc19ded..f1161eb6f 100644 --- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ByteExtensions.cs @@ -5,10 +5,13 @@ namespace ImageSharp { + using System; using System.Runtime.CompilerServices; + using ImageSharp.PixelFormats; + /// - /// Extension methods for the struct. + /// Extension methods for the struct buffers. /// internal static class ByteExtensions { @@ -44,5 +47,45 @@ namespace ImageSharp j--; } } + + /// + /// Returns a reference to the given position of the array unsafe casted to . + /// + /// The byte array. + /// The offset in bytes. + /// The reference at the given offset. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref Rgb24 GetRgb24(this byte[] bytes, int offset) + { + DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset)); + + return ref Unsafe.As(ref bytes[offset]); + } + + /// + /// Returns a reference to the given position of the span unsafe casted to . + /// + /// The byte span. + /// The offset in bytes. + /// The reference at the given offset. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref Rgb24 GetRgb24(this Span bytes, int offset) + { + DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset)); + + return ref Unsafe.As(ref bytes[offset]); + } + + /// + /// Returns a reference to the given position of the buffer pointed by `baseRef` unsafe casted to . + /// + /// A reference to the beginning of the buffer + /// The offset in bytes. + /// The reference at the given offset. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref Rgb24 GetRgb24(ref byte baseRef, int offset) + { + return ref Unsafe.As(ref Unsafe.Add(ref baseRef, offset)); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index a4b392fcf..8e55c18af 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -242,7 +242,6 @@ namespace ImageSharp /// is true /// public static void MustBeSizedAtLeast(Span target, int minLength, string parameterName) - where T : struct { if (target.Length < minLength) { diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index dd91aa11d..997a77d6c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -6,7 +6,8 @@ namespace ImageSharp.Formats { using System; using System.IO; - + using System.Runtime.CompilerServices; + using ImageSharp.Memory; using ImageSharp.PixelFormats; /// @@ -243,13 +244,16 @@ namespace ImageSharp.Formats byte[] row = new byte[arrayWidth + padding]; TPixel color = default(TPixel); + Rgba32 rgba = default(Rgba32); + for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); - this.currentStream.Read(row, 0, row.Length); - int offset = 0; + Span pixelRow = pixels.GetRowSpan(y); + + // TODO: Could use PixelOperations here! for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; @@ -260,8 +264,9 @@ namespace ImageSharp.Formats int newX = colOffset + shift; // Stored in b-> g-> r order. - color.PackFromBytes(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex], 255); - pixels[newX, newY] = color; + rgba.Bgr = Unsafe.As(ref colors[colorIndex]); + color.PackFromRgba32(rgba); + pixelRow[newX] = color; } offset++; @@ -286,6 +291,8 @@ namespace ImageSharp.Formats const int ComponentCount = 2; TPixel color = default(TPixel); + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + using (PixelArea row = new PixelArea(width, ComponentOrder.Xyz)) { for (int y = 0; y < height; y++) @@ -294,17 +301,19 @@ namespace ImageSharp.Formats int newY = Invert(y, height, inverted); + Span pixelRow = pixels.GetRowSpan(newY); + int offset = 0; for (int x = 0; x < width; x++) { short temp = BitConverter.ToInt16(row.Bytes, offset); - byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR); - byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG); - byte b = (byte)((temp & Rgb16BMask) * ScaleR); + rgba.R = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR); + rgba.G = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG); + rgba.B = (byte)((temp & Rgb16BMask) * ScaleR); - color.PackFromBytes(r, g, b, 255); - pixels[x, newY] = color; + color.PackFromRgba32(rgba); + pixelRow[x] = color; offset += ComponentCount; } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 618d268f7..5b56c4c02 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -435,6 +435,8 @@ namespace ImageSharp.Formats Span rowSpan = image.GetRowSpan(writeY); + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { int index = indices[i]; @@ -446,7 +448,9 @@ namespace ImageSharp.Formats int indexOffset = index * 3; ref TPixel pixel = ref rowSpan[x]; - pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255); + rgba.Rgb = colorTable.GetRgb24(indexOffset); + + pixel.PackFromRgba32(rgba); } i++; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs index 27324b5f6..5c9e8f9fc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs @@ -91,7 +91,7 @@ namespace ImageSharp.Formats.Jpg // float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero); byte b = (byte)(y + tables->CbBTable[cb]).Clamp(0, 255); - packed.PackFromBytes(r, g, b, byte.MaxValue); + packed.PackFromRgba32(new Rgba32(r, g, b, 255)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index d65c095da..971684371 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -613,25 +613,23 @@ namespace ImageSharp.Formats private void ConvertFromGrayScale(Image image) where TPixel : struct, IPixel { - using (PixelAccessor pixels = image.Lock()) - { - Parallel.For( - 0, - image.Height, - image.Configuration.ParallelOptions, - y => + Parallel.For( + 0, + image.Height, + image.Configuration.ParallelOptions, + y => { + ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y); + int yoff = this.grayImage.GetRowOffset(y); + for (int x = 0; x < image.Width; x++) { byte rgb = this.grayImage.Pixels[yoff + x]; - - TPixel packed = default(TPixel); - packed.PackFromBytes(rgb, rgb, rgb, 255); - pixels[x, y] = packed; + ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x); + pixel.PackFromRgba32(new Rgba32(rgb, rgb, rgb, 255)); } }); - } this.AssignResolution(image); } @@ -646,30 +644,29 @@ namespace ImageSharp.Formats { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - using (PixelAccessor pixels = image.Lock()) - { - Parallel.For( - 0, - image.Height, - image.Configuration.ParallelOptions, - y => + Parallel.For( + 0, + image.Height, + image.Configuration.ParallelOptions, + y => { // TODO: Simplify + optimize + share duplicate code across converter methods int yo = this.ycbcrImage.GetRowYOffset(y); int co = this.ycbcrImage.GetRowCOffset(y); + ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); for (int x = 0; x < image.Width; x++) { - byte red = this.ycbcrImage.YChannel[yo + x]; - byte green = this.ycbcrImage.CbChannel[co + (x / scale)]; - byte blue = this.ycbcrImage.CrChannel[co + (x / scale)]; + rgba.R = this.ycbcrImage.YChannel[yo + x]; + rgba.G = this.ycbcrImage.CbChannel[co + (x / scale)]; + rgba.B = this.ycbcrImage.CrChannel[co + (x / scale)]; - TPixel packed = default(TPixel); - packed.PackFromBytes(red, green, blue, 255); - pixels[x, y] = packed; + ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x); + pixel.PackFromRgba32(rgba); } }); - } this.AssignResolution(image); } @@ -729,16 +726,15 @@ namespace ImageSharp.Formats { int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor; - using (PixelAccessor pixels = image.Lock()) - { - Parallel.For( - 0, - image.Height, - y => + Parallel.For( + 0, + image.Height, + y => { // TODO: Simplify + optimize + share duplicate code across converter methods int yo = this.ycbcrImage.GetRowYOffset(y); int co = this.ycbcrImage.GetRowCOffset(y); + ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y); for (int x = 0; x < image.Width; x++) { @@ -746,12 +742,10 @@ namespace ImageSharp.Formats byte cb = this.ycbcrImage.CbChannel[co + (x / scale)]; byte cr = this.ycbcrImage.CrChannel[co + (x / scale)]; - TPixel packed = default(TPixel); - this.PackYcck(ref packed, yy, cb, cr, x, y); - pixels[x, y] = packed; + ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x); + this.PackYcck(ref pixel, yy, cb, cr, x, y); } }); - } this.AssignResolution(image); } @@ -860,7 +854,7 @@ namespace ImageSharp.Formats byte g = (byte)(((m / 255F) * (1F - keyline)).Clamp(0, 1) * 255); byte b = (byte)(((y / 255F) * (1F - keyline)).Clamp(0, 1) * 255); - packed.PackFromBytes(r, g, b, 255); + packed.PackFromRgba32(new Rgba32(r, g, b)); } /// @@ -904,7 +898,7 @@ namespace ImageSharp.Formats byte g = (byte)(((1 - magenta) * (1 - keyline)).Clamp(0, 1) * 255); byte b = (byte)(((1 - yellow) * (1 - keyline)).Clamp(0, 1) * 255); - packed.PackFromBytes(r, g, b, 255); + packed.PackFromRgba32(new Rgba32(r, g, b)); } /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index b18845aaa..e0bd153e6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -574,7 +574,7 @@ namespace ImageSharp.Formats for (int x = 0; x < this.header.Width; x++) { byte intensity = (byte)(newScanline1[x] * factor); - color.PackFromBytes(intensity, intensity, intensity, 255); + color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); rowSpan[x] = color; } @@ -589,7 +589,7 @@ namespace ImageSharp.Formats byte intensity = defilteredScanline[offset]; byte alpha = defilteredScanline[offset + this.bytesPerSample]; - color.PackFromBytes(intensity, intensity, intensity, alpha); + color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); rowSpan[x] = color; } @@ -603,13 +603,13 @@ namespace ImageSharp.Formats case PngColorType.Rgb: - PixelOperations.Instance.PackFromXyzBytes(scanlineBuffer, rowSpan, this.header.Width); + PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width); break; case PngColorType.RgbWithAlpha: - PixelOperations.Instance.PackFromXyzwBytes(scanlineBuffer, rowSpan, this.header.Width); + PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width); break; } @@ -628,6 +628,8 @@ namespace ImageSharp.Formats byte[] palette = this.palette; var color = default(TPixel); + Rgba32 rgba = default(Rgba32); + if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha @@ -637,35 +639,33 @@ namespace ImageSharp.Formats int index = newScanline[x + 1]; int pixelOffset = index * 3; - byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; + rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - if (a > 0) + if (rgba.A > 0) { - byte r = palette[pixelOffset]; - byte g = palette[pixelOffset + 1]; - byte b = palette[pixelOffset + 2]; - color.PackFromBytes(r, g, b, a); + rgba.Rgb = palette.GetRgb24(pixelOffset); } else { - color.PackFromBytes(0, 0, 0, 0); + rgba = default(Rgba32); } + color.PackFromRgba32(rgba); row[x] = color; } } else { + rgba.A = 255; + for (int x = 0; x < this.header.Width; x++) { int index = newScanline[x + 1]; int pixelOffset = index * 3; - byte r = palette[pixelOffset]; - byte g = palette[pixelOffset + 1]; - byte b = palette[pixelOffset + 2]; + rgba.Rgb = palette.GetRgb24(pixelOffset); - color.PackFromBytes(r, g, b, 255); + color.PackFromRgba32(rgba); row[x] = color; } } @@ -692,7 +692,7 @@ namespace ImageSharp.Formats for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) { byte intensity = (byte)(newScanline1[o] * factor); - color.PackFromBytes(intensity, intensity, intensity, 255); + color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); rowSpan[x] = color; } @@ -704,8 +704,7 @@ namespace ImageSharp.Formats { byte intensity = defilteredScanline[o]; byte alpha = defilteredScanline[o + this.bytesPerSample]; - - color.PackFromBytes(intensity, intensity, intensity, alpha); + color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); rowSpan[x] = color; } @@ -714,6 +713,7 @@ namespace ImageSharp.Formats case PngColorType.Palette: byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + Rgba32 rgba = default(Rgba32); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { @@ -724,35 +724,33 @@ namespace ImageSharp.Formats int index = newScanline[o]; int offset = index * 3; - byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; + rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - if (a > 0) + if (rgba.A > 0) { - byte r = this.palette[offset]; - byte g = this.palette[offset + 1]; - byte b = this.palette[offset + 2]; - color.PackFromBytes(r, g, b, a); + rgba.Rgb = this.palette.GetRgb24(offset); } else { - color.PackFromBytes(0, 0, 0, 0); + rgba = default(Rgba32); } + color.PackFromRgba32(rgba); rowSpan[x] = color; } } else { + rgba.A = 255; + for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; int offset = index * 3; - byte r = this.palette[offset]; - byte g = this.palette[offset + 1]; - byte b = this.palette[offset + 2]; + rgba.Rgb = this.palette.GetRgb24(offset); - color.PackFromBytes(r, g, b, 255); + color.PackFromRgba32(rgba); rowSpan[x] = color; } } @@ -761,13 +759,14 @@ namespace ImageSharp.Formats case PngColorType.Rgb: + rgba.A = 255; for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - byte r = defilteredScanline[o]; - byte g = defilteredScanline[o + this.bytesPerSample]; - byte b = defilteredScanline[o + (2 * this.bytesPerSample)]; + rgba.R = defilteredScanline[o]; + rgba.G = defilteredScanline[o + this.bytesPerSample]; + rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; - color.PackFromBytes(r, g, b, 255); + color.PackFromRgba32(rgba); rowSpan[x] = color; } @@ -777,12 +776,12 @@ namespace ImageSharp.Formats for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - byte r = defilteredScanline[o]; - byte g = defilteredScanline[o + this.bytesPerSample]; - byte b = defilteredScanline[o + (2 * this.bytesPerSample)]; - byte a = defilteredScanline[o + (3 * this.bytesPerSample)]; + rgba.R = defilteredScanline[o]; + rgba.G = defilteredScanline[o + this.bytesPerSample]; + rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; + rgba.A = defilteredScanline[o + (3 * this.bytesPerSample)]; - color.PackFromBytes(r, g, b, a); + color.PackFromRgba32(rgba); rowSpan[x] = color; } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 3fcf1fc81..645df0548 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -338,11 +338,11 @@ namespace ImageSharp.Formats { if (this.bytesPerPixel == 4) { - PixelOperations.Instance.ToXyzwBytes(rowSpan, this.rawScanline, this.width); + PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline, this.width); } else { - PixelOperations.Instance.ToXyzBytes(rowSpan, this.rawScanline, this.width); + PixelOperations.Instance.ToRgb24Bytes(rowSpan, this.rawScanline, this.width); } } diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index 4baae8615..3902ba425 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -275,7 +275,7 @@ namespace ImageSharp Span source = area.GetRowSpan(y); Span destination = this.GetRowSpan(targetX, targetY + y); - Operations.PackFromZyxBytes(source, destination, width); + Operations.PackFromBgr24Bytes(source, destination, width); } } @@ -295,7 +295,7 @@ namespace ImageSharp Span source = area.GetRowSpan(y); Span destination = this.GetRowSpan(targetX, targetY + y); - Operations.PackFromZyxwBytes(source, destination, width); + Operations.PackFromBgra32Bytes(source, destination, width); } } @@ -315,7 +315,7 @@ namespace ImageSharp Span source = area.GetRowSpan(y); Span destination = this.GetRowSpan(targetX, targetY + y); - Operations.PackFromXyzBytes(source, destination, width); + Operations.PackFromRgb24Bytes(source, destination, width); } } @@ -334,7 +334,7 @@ namespace ImageSharp { Span source = area.GetRowSpan(y); Span destination = this.GetRowSpan(targetX, targetY + y); - Operations.PackFromXyzwBytes(source, destination, width); + Operations.PackFromRgba32Bytes(source, destination, width); } } @@ -353,7 +353,7 @@ namespace ImageSharp { Span source = this.GetRowSpan(sourceX, sourceY + y); Span destination = area.GetRowSpan(y); - Operations.ToZyxBytes(source, destination, width); + Operations.ToBgr24Bytes(source, destination, width); } } @@ -372,7 +372,7 @@ namespace ImageSharp { Span source = this.GetRowSpan(sourceX, sourceY + y); Span destination = area.GetRowSpan(y); - Operations.ToZyxwBytes(source, destination, width); + Operations.ToBgra32Bytes(source, destination, width); } } @@ -391,7 +391,7 @@ namespace ImageSharp { Span source = this.GetRowSpan(sourceX, sourceY + y); Span destination = area.GetRowSpan(y); - Operations.ToXyzBytes(source, destination, width); + Operations.ToRgb24Bytes(source, destination, width); } } @@ -410,7 +410,7 @@ namespace ImageSharp { Span source = this.GetRowSpan(sourceX, sourceY + y); Span destination = area.GetRowSpan(y); - Operations.ToXyzwBytes(source, destination, width); + Operations.ToRgba32Bytes(source, destination, width); } } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 6194be1bf..17f7bf58f 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -53,6 +53,35 @@ TextTemplatingFileGenerator + Block8x8F.Generated.cs + + TextTemplatingFileGenerator + PixelOperations{TPixel}.Generated.cs + + + TextTemplatingFileGenerator + Rgba32.PixelOperations.Generated.cs + + + + + + + + True + True + Block8x8F.Generated.tt + + + True + True + PixelOperations{TPixel}.Generated.tt + + + True + True + Rgba32.PixelOperations.Generated.tt + \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index c184ed9cf..59934fdc6 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -62,7 +62,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -80,47 +80,43 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackedValue = w; + this.PackedValue = source.A; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - bytes[startIndex] = 0; - bytes[startIndex + 1] = 0; - bytes[startIndex + 2] = 0; + dest = default(Rgb24); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - bytes[startIndex] = 0; - bytes[startIndex + 1] = 0; - bytes[startIndex + 2] = 0; - bytes[startIndex + 3] = this.PackedValue; + dest.R = 0; + dest.G = 0; + dest.B = 0; + dest.A = this.PackedValue; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - bytes[startIndex] = 0; - bytes[startIndex + 1] = 0; - bytes[startIndex + 2] = 0; + dest = default(Bgr24); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - bytes[startIndex] = 0; - bytes[startIndex + 1] = 0; - bytes[startIndex + 2] = 0; - bytes[startIndex + 3] = this.PackedValue; + dest.R = 0; + dest.G = 0; + dest.B = 0; + dest.A = this.PackedValue; } /// diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index bd47f72f9..f389723dc 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -59,11 +59,24 @@ namespace ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - public Argb32(byte r, byte g, byte b, byte a = 255) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Argb32(byte r, byte g, byte b, byte a) { this.PackedValue = Pack(r, g, b, a); } + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Argb32(byte r, byte g, byte b) + { + this.PackedValue = Pack(r, g, b, 255); + } + /// /// Initializes a new instance of the struct. /// @@ -224,7 +237,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -235,47 +248,47 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackedValue = Pack(x, y, z, w); + this.PackedValue = Pack(source.R, source.G, source.B, source.A); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - bytes[startIndex] = this.R; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.B; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - bytes[startIndex] = this.R; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.B; - bytes[startIndex + 3] = this.A; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - bytes[startIndex] = this.B; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.R; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - bytes[startIndex] = this.B; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.R; - bytes[startIndex + 3] = this.A; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs new file mode 100644 index 000000000..aaed5c385 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -0,0 +1,135 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. + /// The color components are stored in blue, green, red order. + /// + [StructLayout(LayoutKind.Sequential)] + public struct Bgr24 : IPixel + { + /// + /// The blue component. + /// + public byte B; + + /// + /// The green component. + /// + public byte G; + + /// + /// The red component. + /// + public byte R; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Bgr24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Bgr24 other) + { + return this.R == other.R && this.G == other.G && this.B == other.B; + } + + /// + public override bool Equals(object obj) + { + return obj?.GetType() == typeof(Bgr24) && this.Equals((Bgr24)obj); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + unchecked + { + int hashCode = this.B; + hashCode = (hashCode * 397) ^ this.G; + hashCode = (hashCode * 397) ^ this.R; + return hashCode; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this = source.Bgr; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + var rgba = default(Rgba32); + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = 255; + } + + /// + public void ToBgr24(ref Bgr24 dest) + { + dest = this; + } + + /// + public void ToBgra32(ref Bgra32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = 255; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 92bbac14c..af22b14a0 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -71,7 +71,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// /// Expands the packed representation into a . @@ -103,51 +103,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs new file mode 100644 index 000000000..f1ac20b56 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -0,0 +1,187 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255. + /// The color components are stored in blue, green, red, and alpha order. + /// + [StructLayout(LayoutKind.Sequential)] + public struct Bgra32 : IPixel, IPackedVector + { + /// + /// Gets or sets the blue component. + /// + public byte B; + + /// + /// Gets or sets the green component. + /// + public byte G; + + /// + /// Gets or sets the red component. + /// + public byte R; + + /// + /// Gets or sets the alpha component. + /// + public byte A; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Bgra32(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + this.A = 255; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Bgra32(byte r, byte g, byte b, byte a) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + /// + /// Gets or sets the packed representation of the Bgra32 struct. + /// + public uint Bgra + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + Unsafe.As(ref this) = value; + } + } + + /// + public uint PackedValue + { + get => this.Bgra; + set => this.Bgra = value; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + public bool Equals(Bgra32 other) + { + return this.R == other.R && this.G == other.G && this.B == other.B && this.A == other.A; + } + + /// + public override bool Equals(object obj) => obj?.GetType() == typeof(Bgra32) && this.Equals((Bgra32)obj); + + /// + public override int GetHashCode() + { + unchecked + { + int hashCode = this.B; + hashCode = (hashCode * 397) ^ this.G; + hashCode = (hashCode * 397) ^ this.R; + hashCode = (hashCode * 397) ^ this.A; + return hashCode; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + var rgba = default(Rgba32); + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return this.ToRgba32().ToVector4(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgr24(ref Bgr24 dest) + { + dest = Unsafe.As(ref this); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgra32(ref Bgra32 dest) + { + dest = this; + } + + /// + /// Converts the pixel to format. + /// + /// The RGBA value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 0bac00dfe..746e1062b 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -70,7 +70,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -79,10 +79,10 @@ namespace ImageSharp.PixelFormats const float Max = 1 / 15F; return new Vector4( - ((this.PackedValue >> 8) & 0x0F) * Max, - ((this.PackedValue >> 4) & 0x0F) * Max, - (this.PackedValue & 0x0F) * Max, - ((this.PackedValue >> 12) & 0x0F) * Max); + ((this.PackedValue >> 8) & 0x0F) * Max, + ((this.PackedValue >> 4) & 0x0F) * Max, + (this.PackedValue & 0x0F) * Max, + ((this.PackedValue >> 12) & 0x0F) * Max); } /// @@ -94,51 +94,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -179,9 +179,9 @@ namespace ImageSharp.PixelFormats private static ushort Pack(float x, float y, float z, float w) { return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | - (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | - (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | - ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); + (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | + (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | + ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); } } } diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index f151db644..198f91108 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -72,7 +72,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -94,51 +94,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -190,5 +190,8 @@ namespace ImageSharp.PixelFormats (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) | (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() => this.ToVector4() * 255f; } } diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 264bc7497..14053ba12 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -73,7 +73,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -95,51 +95,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w)); + this.PackFromVector4(source.ToUnscaledVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { Vector4 vector = this.ToVector4(); - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { Vector4 vector = this.ToVector4(); - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { Vector4 vector = this.ToVector4(); - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { Vector4 vector = this.ToVector4(); - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 4b21130c0..92fb006ab 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -35,12 +35,13 @@ namespace ImageSharp.PixelFormats } TPixel result = default(TPixel); - - result.PackFromBytes( + Rgba32 rgba = new Rgba32( (byte)(packedValue >> 24), (byte)(packedValue >> 16), (byte)(packedValue >> 8), (byte)(packedValue >> 0)); + + result.PackFromRgba32(rgba); return result; } @@ -51,12 +52,7 @@ namespace ImageSharp.PixelFormats /// The green intensity. /// The blue intensity. /// Returns a that represents the color defined by the provided RGB values with 100% opacity. - public static TPixel FromRGB(byte red, byte green, byte blue) - { - TPixel color = default(TPixel); - color.PackFromBytes(red, green, blue, 255); - return color; - } + public static TPixel FromRGB(byte red, byte green, byte blue) => FromRGBA(red, green, blue, 255); /// /// Creates a new representation from standard RGBA bytes. @@ -69,7 +65,7 @@ namespace ImageSharp.PixelFormats public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) { TPixel color = default(TPixel); - color.PackFromBytes(red, green, blue, alpha); + color.PackFromRgba32(new Rgba32(red, green, blue, alpha)); return color; } diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs new file mode 100644 index 000000000..c042d7678 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -0,0 +1,302 @@ +// + +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + + public partial class PixelOperations + { + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromRgba32(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Rgba32 sourceRef = ref source.DangerousGetPinnableReference(); + ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + rgba = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromRgba32Bytes(Span sourceBytes, Span destPixels, int count) + { + this.PackFromRgba32(sourceBytes.NonPortableCast(), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToRgba32(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Rgba32 destBaseRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToRgba32(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba32Bytes(Span sourceColors, Span destBytes, int count) + { + this.ToRgba32(sourceColors, destBytes.NonPortableCast(), count); + } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromBgra32(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference(); + ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + rgba = Unsafe.Add(ref sourceRef, i).ToRgba32(); + dp.PackFromRgba32(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromBgra32Bytes(Span sourceBytes, Span destPixels, int count) + { + this.PackFromBgra32(sourceBytes.NonPortableCast(), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToBgra32(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Bgra32 destBaseRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToBgra32(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgra32Bytes(Span sourceColors, Span destBytes, int count) + { + this.ToBgra32(sourceColors, destBytes.NonPortableCast(), count); + } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromRgb24(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference(); + ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + rgba.Rgb = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromRgb24Bytes(Span sourceBytes, Span destPixels, int count) + { + this.PackFromRgb24(sourceBytes.NonPortableCast(), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToRgb24(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Rgb24 destBaseRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToRgb24(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgb24Bytes(Span sourceColors, Span destBytes, int count) + { + this.ToRgb24(sourceColors, destBytes.NonPortableCast(), count); + } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromBgr24(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference(); + ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + rgba.Bgr = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromBgr24Bytes(Span sourceBytes, Span destPixels, int count) + { + this.PackFromBgr24(sourceBytes.NonPortableCast(), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToBgr24(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Bgr24 destBaseRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToBgr24(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgr24Bytes(Span sourceColors, Span destBytes, int count) + { + this.ToBgr24(sourceColors, destBytes.NonPortableCast(), count); + } + + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt new file mode 100644 index 000000000..16292489f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -0,0 +1,130 @@ +<# +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateToDestFormatMethods(string pixelType) + { + #> + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void To<#=pixelType#>(Span sourcePixels, Span<<#=pixelType#>> dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); + ref <#=pixelType#> destBaseRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); + sp.To<#=pixelType#>(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void To<#=pixelType#>Bytes(Span sourceColors, Span destBytes, int count) + { + this.To<#=pixelType#>(sourceColors, destBytes.NonPortableCast>(), count); + } + <# + } + + void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) + { + #> + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference(); + ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); + + Rgba32 rgba = new Rgba32(0, 0, 0, 255); + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + <#=rgbaOperationCode#> + dp.PackFromRgba32(rgba); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFrom<#=pixelType#>Bytes(Span sourceBytes, Span destPixels, int count) + { + this.PackFrom<#=pixelType#>(sourceBytes.NonPortableCast>(), destPixels, count); + } + <# + } + +#> +// + +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + + public partial class PixelOperations + { + <# + + GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Rgba32"); + + GeneratePackFromMethodUsingPackFromRgba32("Bgra32", "rgba = Unsafe.Add(ref sourceRef, i).ToRgba32();"); + GenerateToDestFormatMethods("Bgra32"); + + GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Rgb24"); + + GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Bgr24"); + + #> + + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs new file mode 100644 index 000000000..e42c575d8 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -0,0 +1,130 @@ +// + +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using ImageSharp.Memory; + using ImageSharp.PixelFormats; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba32 + { + internal partial class PixelOperations : PixelOperations + { + + /// + internal override void PackFromRgb24(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference(); + ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + Unsafe.As(ref dp) = sp; dp.A = 255; + } + } + + + /// + internal override void ToRgb24(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Rgb24 destRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + dp = Unsafe.As(ref sp); + } + } + + + /// + internal override void PackFromBgr24(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference(); + ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + dp.Bgr = sp; dp.A = 255; + } + } + + + /// + internal override void ToBgr24(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Bgr24 destRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.Bgr; + } + } + + + /// + internal override void PackFromBgra32(Span source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference(); + ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToRgba32(); + } + } + + + /// + internal override void ToBgra32(Span sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); + ref Bgra32 destRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToBgra32(); + } + } + + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt new file mode 100644 index 000000000..9c01fa915 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -0,0 +1,99 @@ +<# +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + + void GeneratePackFromMethod(string pixelType, string converterCode) + { + #> + + /// + internal override void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference(); + ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + <#=converterCode#> + } + } + + <# + } + + void GenerateConvertToMethod(string pixelType, string converterCode) + { + #> + + /// + internal override void To<#=pixelType#>(Span sourcePixels, Span<<#=pixelType#>> dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); + ref <#=pixelType#> destRef = ref dest.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + <#=converterCode#> + } + } + + <# + } + +#> +// + +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using ImageSharp.Memory; + using ImageSharp.PixelFormats; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba32 + { + internal partial class PixelOperations : PixelOperations + { + <# + GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;"); + GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); + + GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); + GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); + + GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); + GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 4cc9acc22..3bdfc9f1c 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -76,7 +76,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// /// Expands the packed representation into a . @@ -104,67 +104,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -192,5 +176,15 @@ namespace ImageSharp.PixelFormats { return this.PackedValue.GetHashCode(); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index f490f7169..7f1fe4ebd 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -86,7 +86,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// /// Expands the packed representation into a . @@ -118,67 +118,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; + dest.A = 255; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; + dest.A = 255; } /// @@ -220,5 +204,15 @@ namespace ImageSharp.PixelFormats uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); return num2 | num; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 7c496c161..062287dbe 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -89,7 +89,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -111,67 +111,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -214,5 +198,15 @@ namespace ImageSharp.PixelFormats ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; return num4 | num3 | num2 | num1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 030cb93f4..9090e1210 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -20,7 +20,7 @@ namespace ImageSharp.PixelFormats /// This method is not intended to be consumed directly. Use instead. /// /// The instance. - PixelOperations CreateBulkOperations(); + PixelOperations CreatePixelOperations(); } /// @@ -42,44 +42,33 @@ namespace ImageSharp.PixelFormats Vector4 ToVector4(); /// - /// Sets the packed representation from the given byte array. + /// Packs the pixel from an value. /// - /// The x-component. - /// The y-component. - /// The z-component. - /// The w-component. - void PackFromBytes(byte x, byte y, byte z, byte w); + /// The value. + void PackFromRgba32(Rgba32 source); /// - /// Expands the packed representation into a given byte array. - /// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in + /// Converts the pixel to format. /// - /// The bytes to set the color in. - /// The starting index of the . - void ToXyzBytes(Span bytes, int startIndex); + /// The destination pixel to write to + void ToRgb24(ref Rgb24 dest); /// - /// Expands the packed representation into a given byte array. - /// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in + /// Converts the pixel to format. /// - /// The bytes to set the color in. - /// The starting index of the . - void ToXyzwBytes(Span bytes, int startIndex); + /// The destination pixel to write to + void ToRgba32(ref Rgba32 dest); /// - /// Expands the packed representation into a given byte array. - /// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in + /// Converts the pixel to format. /// - /// The bytes to set the color in. - /// The starting index of the . - void ToZyxBytes(Span bytes, int startIndex); + /// The destination pixel to write to + void ToBgr24(ref Bgr24 dest); /// - /// Expands the packed representation into a given byte array. - /// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in + /// Converts the pixel to format. /// - /// The bytes to set the color in. - /// The starting index of the . - void ToZyxwBytes(Span bytes, int startIndex); + /// The destination pixel to write to + void ToBgra32(ref Bgra32 dest); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 47a4f3005..992986f92 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -91,7 +91,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// /// Expands the packed representation into a . @@ -122,9 +122,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector4 vector = new Vector4(x, y, z, w); + Vector4 vector = source.ToUnscaledVector4(); vector -= Round; vector -= Half; vector -= Round; @@ -134,68 +134,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = 0; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = 0; - bytes[startIndex + 3] = 255; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; + dest.A = 255; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = 255; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = 0; + dest.A = 255; } /// @@ -238,5 +214,17 @@ namespace ImageSharp.PixelFormats return (ushort)(byte2 | byte1); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= Half; + vector += Round; + vector += Half; + vector += Round; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 4559bd082..99f603f69 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -93,7 +93,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -115,9 +115,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector4 vector = new Vector4(x, y, z, w); + Vector4 vector = source.ToUnscaledVector4(); vector -= Round; vector -= Half; vector -= Round; @@ -127,68 +127,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -235,5 +211,17 @@ namespace ImageSharp.PixelFormats return byte4 | byte3 | byte2 | byte1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= Half; + vector += Round; + vector += Half; + vector += Round; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 648b68905..a0615563f 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -91,7 +91,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -109,9 +109,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector4 vector = new Vector4(x, y, z, w); + Vector4 vector = source.ToUnscaledVector4(); vector -= Round; vector -= Half; vector -= Round; @@ -121,68 +121,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = 0; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = 0; - bytes[startIndex + 3] = 255; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; + dest.A = 255; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = 255; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; + dest.A = 255; } /// @@ -245,5 +221,17 @@ namespace ImageSharp.PixelFormats return word2 | word1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= Half; + vector += Round; + vector += Half; + vector += Round; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 7b520aace..f35fb6368 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -93,7 +93,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -117,9 +117,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector4 vector = new Vector4(x, y, z, w); + Vector4 vector = source.ToUnscaledVector4(); vector -= Round; vector -= Half; vector -= Round; @@ -129,68 +129,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// @@ -241,5 +217,17 @@ namespace ImageSharp.PixelFormats return word4 | word3 | word2 | word1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector *= Half; + vector += Round; + vector += Half; + vector += Round; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } diff --git a/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs b/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs new file mode 100644 index 000000000..1ea262895 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs @@ -0,0 +1,76 @@ +namespace ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + + /// + /// Extension methods for copying single pixel data into byte Spans. + /// TODO: This utility class exists for legacy reasons. Need to do a lot of chore work to remove it (mostly in test classes). + /// + internal static class PixelConversionExtensions + { + /// + /// Expands the packed representation into a given byte array. + /// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in + /// + /// The pixel type. + /// The pixel to copy the data from. + /// The bytes to set the color in. + /// The starting index of the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToXyzBytes(this TPixel pixel, Span bytes, int startIndex) + where TPixel : struct, IPixel + { + ref Rgb24 dest = ref bytes.GetRgb24(startIndex); + pixel.ToRgb24(ref dest); + } + + /// + /// Expands the packed representation into a given byte array. + /// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in + /// + /// The pixel type. + /// The pixel to copy the data from. + /// The bytes to set the color in. + /// The starting index of the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToXyzwBytes(this TPixel pixel, Span bytes, int startIndex) + where TPixel : struct, IPixel + { + ref Rgba32 dest = ref Unsafe.As(ref bytes[startIndex]); + pixel.ToRgba32(ref dest); + } + + /// + /// Expands the packed representation into a given byte array. + /// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in + /// + /// The pixel type. + /// The pixel to copy the data from. + /// The bytes to set the color in. + /// The starting index of the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToZyxBytes(this TPixel pixel, Span bytes, int startIndex) + where TPixel : struct, IPixel + { + ref Bgr24 dest = ref Unsafe.As(ref bytes[startIndex]); + pixel.ToBgr24(ref dest); + } + + /// + /// Expands the packed representation into a given byte array. + /// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in + /// + /// The pixel type. + /// The pixel to copy the data from. + /// The bytes to set the color in. + /// The starting index of the . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ToZyxwBytes(this TPixel pixel, Span bytes, int startIndex) + where TPixel : struct, IPixel + { + ref Bgra32 dest = ref Unsafe.As(ref bytes[startIndex]); + pixel.ToBgra32(ref dest); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 993a11232..a62d14527 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -20,7 +20,7 @@ namespace ImageSharp.PixelFormats /// /// Gets the global instance for the pixel type /// - public static PixelOperations Instance { get; } = default(TPixel).CreateBulkOperations(); + public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// /// Bulk version of @@ -30,8 +30,7 @@ namespace ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(Span sourceVectors, Span destColors, int count) { - Guard.MustBeSizedAtLeast(sourceVectors, count, nameof(sourceVectors)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); + GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count); ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference(); ref TPixel destRef = ref destColors.DangerousGetPinnableReference(); @@ -52,8 +51,7 @@ namespace ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(Span sourceColors, Span destVectors, int count) { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors)); + GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference(); ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference(); @@ -67,187 +65,25 @@ namespace ImageSharp.PixelFormats } /// - /// Bulk version of that converts data in . + /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. + /// Throwing an if the condition is not met. /// - /// The to the source bytes. - /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromXyzBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference(); - ref TPixel destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBytes( - Unsafe.Add(ref sourceRef, i3), - Unsafe.Add(ref sourceRef, i3 + 1), - Unsafe.Add(ref sourceRef, i3 + 2), - 255); - } - } - - /// - /// Bulk version of . - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - internal virtual void ToXyzBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes)); - - ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - sp.ToXyzBytes(destBytes, i * 3); - } - } - - /// - /// Bulk version of that converts data in . - /// - /// The to the source bytes. - /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromXyzwBytes(Span sourceBytes, Span destColors, int count) + /// The source element type + /// The destination element type + /// The source span + /// The source parameter name + /// The destination span + /// The destination parameter name + /// The minimum length + protected internal static void GuardSpans( + Span source, + string sourceParamName, + Span dest, + string destParamName, + int minLength) { - Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference(); - ref TPixel destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBytes( - Unsafe.Add(ref sourceRef, i4), - Unsafe.Add(ref sourceRef, i4 + 1), - Unsafe.Add(ref sourceRef, i4 + 2), - Unsafe.Add(ref sourceRef, i4 + 3)); - } - } - - /// - /// Bulk version of - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - internal virtual void ToXyzwBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 4, nameof(destBytes)); - - ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - sp.ToXyzwBytes(destBytes, i * 4); - } - } - - /// - /// Bulk version of that converts data in . - /// - /// The to the source bytes. - /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromZyxBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference(); - ref TPixel destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBytes( - Unsafe.Add(ref sourceRef, i3 + 2), - Unsafe.Add(ref sourceRef, i3 + 1), - Unsafe.Add(ref sourceRef, i3), - 255); - } - } - - /// - /// Bulk version of . - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - internal virtual void ToZyxBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes)); - - ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - sp.ToZyxBytes(destBytes, i * 3); - } - } - - /// - /// Bulk version of that converts data in . - /// - /// The to the source bytes. - /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromZyxwBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference(); - ref TPixel destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBytes( - Unsafe.Add(ref sourceRef, i4 + 2), - Unsafe.Add(ref sourceRef, i4 + 1), - Unsafe.Add(ref sourceRef, i4), - Unsafe.Add(ref sourceRef, i4 + 3)); - } - } - - /// - /// Bulk version of . - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - internal virtual void ToZyxwBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 4, nameof(destBytes)); - - ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - sp.ToZyxwBytes(destBytes, i * 4); - } + Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); + Guard.MustBeSizedAtLeast(dest, minLength, destParamName); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index ea7d8729b..0575689a7 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -76,7 +76,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// /// Expands the packed representation into a . @@ -107,55 +107,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)vector.X; + dest.G = (byte)vector.Y; + dest.B = (byte)vector.Z; + dest.A = (byte)vector.W; } /// @@ -197,5 +193,8 @@ namespace ImageSharp.PixelFormats ((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | (((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() => this.ToVector4() * 255f; } } diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs new file mode 100644 index 000000000..b8cc8dc24 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -0,0 +1,132 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats +{ + using System; + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. + /// The color components are stored in red, green, blue order. + /// + [StructLayout(LayoutKind.Sequential)] + public struct Rgb24 : IPixel + { + /// + /// The red component. + /// + public byte R; + + /// + /// The green component. + /// + public byte G; + + /// + /// The blue component. + /// + public byte B; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Rgb24 other) + { + return this.R == other.R && this.G == other.G && this.B == other.B; + } + + /// + public override bool Equals(object obj) + { + return obj?.GetType() == typeof(Rgb24) && this.Equals((Rgb24)obj); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + unchecked + { + int hashCode = this.R; + hashCode = (hashCode * 397) ^ this.G; + hashCode = (hashCode * 397) ^ this.B; + return hashCode; + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + var rgba = default(Rgba32); + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + dest = this; + } + + /// + public void ToRgba32(ref Rgba32 dest) + { + dest.Rgb = this; + dest.A = 255; + } + + /// + public void ToBgr24(ref Bgr24 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + } + + /// + public void ToBgra32(ref Bgra32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = 255; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index ca7b74fbb..e682aa477 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -79,7 +79,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -101,55 +101,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 2ba663603..63e40e9cf 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -21,7 +21,7 @@ namespace ImageSharp /// /// implementation optimized for . /// - internal class PixelOperations : PixelOperations + internal partial class PixelOperations : PixelOperations { /// /// SIMD optimized bulk implementation of @@ -121,164 +121,19 @@ namespace ImageSharp } /// - internal override void PackFromXyzBytes(Span sourceBytes, Span destColors, int count) + internal override void PackFromRgba32(Span source, Span destPixels, int count) { - Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref RGB24 sourceRef = ref Unsafe.As(ref sourceBytes.DangerousGetPinnableReference()); - ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - Unsafe.As(ref dp) = sp; - dp.A = 255; - } - } - - /// - internal override void ToXyzBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes)); - - ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference(); - ref RGB24 destRef = ref Unsafe.As(ref destBytes.DangerousGetPinnableReference()); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref RGB24 dp = ref Unsafe.Add(ref destRef, i); - - dp = Unsafe.As(ref sp); - } - } - - /// - internal override unsafe void PackFromXyzwBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - SpanHelper.Copy(sourceBytes, destColors.AsBytes(), count * sizeof(Rgba32)); + SpanHelper.Copy(source, destPixels, count); } /// - internal override unsafe void ToXyzwBytes(Span sourceColors, Span destBytes, int count) + internal override void ToRgba32(Span sourcePixels, Span dest, int count) { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 4, nameof(destBytes)); - - SpanHelper.Copy(sourceColors.AsBytes(), destBytes, count * sizeof(Rgba32)); - } - - /// - internal override void PackFromZyxBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref RGB24 sourceRef = ref Unsafe.As(ref sourceBytes.DangerousGetPinnableReference()); - ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - Unsafe.As(ref dp) = sp.ToZyx(); - dp.A = 255; - } - } - - /// - internal override void ToZyxBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes)); - - ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference(); - ref RGB24 destRef = ref Unsafe.As(ref destBytes.DangerousGetPinnableReference()); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref RGB24 dp = ref Unsafe.Add(ref destRef, i); + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - dp = Unsafe.As(ref sp).ToZyx(); - } - } - - /// - internal override void PackFromZyxwBytes(Span sourceBytes, Span destColors, int count) - { - Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes)); - Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors)); - - ref RGBA32 sourceRef = ref Unsafe.As(ref sourceBytes.DangerousGetPinnableReference()); - ref Rgba32 destRef = ref destColors.DangerousGetPinnableReference(); - - for (int i = 0; i < count; i++) - { - ref RGBA32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - RGBA32 zyxw = sp.ToZyxw(); - dp = Unsafe.As(ref zyxw); - } - } - - /// - internal override void ToZyxwBytes(Span sourceColors, Span destBytes, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destBytes, count * 4, nameof(destBytes)); - - ref Rgba32 sourceRef = ref sourceColors.DangerousGetPinnableReference(); - ref RGBA32 destRef = ref Unsafe.As(ref destBytes.DangerousGetPinnableReference()); - - for (int i = 0; i < count; i++) - { - ref RGBA32 sp = ref Unsafe.As(ref Unsafe.Add(ref sourceRef, i)); - ref RGBA32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToZyxw(); - } - } - - /// - /// Helper struct to manipulate 3-byte RGB data. - /// - [StructLayout(LayoutKind.Sequential)] - private struct RGB24 - { - private byte x; - - private byte y; - - private byte z; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RGB24 ToZyx() => new RGB24 { x = this.z, y = this.y, z = this.x }; - } - - /// - /// Helper struct to manipulate 4-byte RGBA data. - /// - [StructLayout(LayoutKind.Sequential)] - private struct RGBA32 - { - private byte x; - - private byte y; - - private byte z; - - private byte w; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RGBA32 ToZyxw() => new RGBA32 { x = this.z, y = this.y, z = this.x, w = this.w }; + SpanHelper.Copy(sourcePixels, dest, count); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 9b82a3701..85322c7c5 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -23,39 +23,29 @@ namespace ImageSharp /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Sequential)] public partial struct Rgba32 : IPixel, IPackedVector { /// /// Gets or sets the red component. /// - [FieldOffset(0)] public byte R; /// /// Gets or sets the green component. /// - [FieldOffset(1)] public byte G; /// /// Gets or sets the blue component. /// - [FieldOffset(2)] public byte B; /// /// Gets or sets the alpha component. /// - [FieldOffset(3)] public byte A; - /// - /// The packed representation of the value. - /// - [FieldOffset(0)] - public uint Rgba; - /// /// The shift count for the red component /// @@ -86,6 +76,21 @@ namespace ImageSharp /// private static readonly Vector4 Half = new Vector4(0.5F); + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + this.A = 255; + } + /// /// Initializes a new instance of the struct. /// @@ -94,8 +99,7 @@ namespace ImageSharp /// The blue component. /// The alpha component. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32(byte r, byte g, byte b, byte a = 255) - : this() + public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; this.G = g; @@ -156,8 +160,68 @@ namespace ImageSharp this.Rgba = packed; } + /// + /// Gets or sets the packed representation of the Rgba32 struct. + /// + public uint Rgba + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + Unsafe.As(ref this) = value; + } + } + + /// + /// Gets or sets the RGB components of this struct as + /// + public Rgb24 Rgb + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + Unsafe.As(ref this) = value; + } + } + + /// + /// Gets or sets the RGB components of this struct as reverting the component order. + /// + public Bgr24 Bgr + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return new Bgr24(this.R, this.G, this.B); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + this.R = value.R; + this.G = value.G; + this.B = value.B; + } + } + /// - public uint PackedValue { get => this.Rgba; set => this.Rgba = value; } + public uint PackedValue + { + get => this.Rgba; + set => this.Rgba = value; + } /// /// Compares two objects for equality. @@ -207,16 +271,13 @@ namespace ImageSharp } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.R = x; - this.G = y; - this.B = z; - this.A = w; + this = source; } /// @@ -229,42 +290,37 @@ namespace ImageSharp return hexOrder.ToString("X8"); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - bytes[startIndex] = this.R; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.B; + dest = Unsafe.As(ref this); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - bytes[startIndex] = this.R; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.B; - bytes[startIndex + 3] = this.A; + dest = this; } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - bytes[startIndex] = this.B; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.R; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - bytes[startIndex] = this.B; - bytes[startIndex + 1] = this.G; - bytes[startIndex + 2] = this.R; - bytes[startIndex + 3] = this.A; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } /// @@ -281,6 +337,17 @@ namespace ImageSharp return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; } + /// + /// Gets the value of this struct as . + /// Useful for changing the component order. + /// + /// A value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Bgra32 ToBgra32() + { + return new Bgra32(this.R, this.G, this.B, this.A); + } + /// public override bool Equals(object obj) { @@ -308,14 +375,24 @@ namespace ImageSharp { unchecked { - int hashCode = this.R.GetHashCode(); - hashCode = (hashCode * 397) ^ this.G.GetHashCode(); - hashCode = (hashCode * 397) ^ this.B.GetHashCode(); - hashCode = (hashCode * 397) ^ this.A.GetHashCode(); + int hashCode = this.R; + hashCode = (hashCode * 397) ^ this.G; + hashCode = (hashCode * 397) ^ this.B; + hashCode = (hashCode * 397) ^ this.A; return hashCode; } } + /// + /// Gets the representation without normalizing to [0, 1] + /// + /// A of values in [0, 255] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Vector4 ToUnscaledVector4() + { + return new Vector4(this.R, this.G, this.B, this.A); + } + /// /// Packs the four floats into a . /// diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 417828368..bdcf13763 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -78,7 +78,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -100,55 +100,51 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(source.ToVector4()); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { Vector4 vector = this.ToVector4() * 255F; - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs index ac25b7f14..00b746166 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs @@ -23,10 +23,9 @@ namespace ImageSharp.PixelFormats /// internal override unsafe void ToVector4(Span sourceColors, Span destVectors, int count) { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors)); + GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); - SpanHelper.Copy(sourceColors.AsBytes(), destVectors.AsBytes(), count * sizeof(Vector4)); + SpanHelper.Copy(sourceColors.NonPortableCast(), destVectors, count); } } } diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 5332f4a8e..c6eed1122 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -211,13 +211,13 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new RgbaVector.PixelOperations(); + public PixelOperations CreatePixelOperations() => new RgbaVector.PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - this.backingVector = new Vector4(x, y, z, w) / MaxBytes; + this.backingVector = source.ToVector4(); } /// @@ -233,50 +233,46 @@ namespace ImageSharp.PixelFormats return hexOrder.ToString("X8"); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; - vector += Half; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; - vector += Half; - bytes[startIndex] = (byte)vector.X; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.Z; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; - vector += Half; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; - vector += Half; - bytes[startIndex] = (byte)vector.Z; - bytes[startIndex + 1] = (byte)vector.Y; - bytes[startIndex + 2] = (byte)vector.X; - bytes[startIndex + 3] = (byte)vector.W; + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// @@ -320,5 +316,8 @@ namespace ImageSharp.PixelFormats { return this.backingVector.GetHashCode(); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index b848b5505..0b3f4be93 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -91,7 +91,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -109,9 +109,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector2 vector = new Vector2(x, y) / 255; + Vector2 vector = new Vector2(source.R, source.G) / 255; vector *= 65534; vector -= new Vector2(32767); this.PackedValue = Pack(vector.X, vector.Y); @@ -119,68 +119,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector2 vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = 0; + Vector2 vector = this.ToScaledVector2(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector2 vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = 0; - bytes[startIndex + 3] = 255; + Vector2 vector = this.ToScaledVector2(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; + dest.A = 255; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector2 vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + Vector2 vector = this.ToScaledVector2(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector2 vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - - bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = 255; + Vector2 vector = this.ToScaledVector2(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = 0; + dest.A = 255; } /// @@ -239,5 +215,17 @@ namespace ImageSharp.PixelFormats return word2 | word1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector2 ToScaledVector2() + { + Vector2 vector = this.ToVector2(); + vector /= 65534; + vector *= 255; + vector += Half; + vector += Round; + vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 763de19bc..958300929 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -93,7 +93,7 @@ namespace ImageSharp.PixelFormats } /// - public PixelOperations CreateBulkOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -115,9 +115,9 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBytes(byte x, byte y, byte z, byte w) + public void PackFromRgba32(Rgba32 source) { - Vector4 vector = new Vector4(x, y, z, w) / 255; + Vector4 vector = source.ToVector4(); vector *= 65534; vector -= new Vector4(32767); this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); @@ -125,68 +125,44 @@ namespace ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzBytes(Span bytes, int startIndex) + public void ToRgb24(ref Rgb24 dest) { - Vector4 vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToXyzwBytes(Span bytes, int startIndex) + public void ToRgba32(ref Rgba32 dest) { - Vector4 vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.X); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxBytes(Span bytes, int startIndex) + public void ToBgr24(ref Bgr24 dest) { - Vector4 vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToZyxwBytes(Span bytes, int startIndex) + public void ToBgra32(ref Bgra32 dest) { - Vector4 vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - bytes[startIndex] = (byte)MathF.Round(vector.Z); - bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); - bytes[startIndex + 2] = (byte)MathF.Round(vector.X); - bytes[startIndex + 3] = (byte)MathF.Round(vector.W); + Vector4 vector = this.ToScaledVector4(); + dest.R = (byte)MathF.Round(vector.X); + dest.G = (byte)MathF.Round(vector.Y); + dest.B = (byte)MathF.Round(vector.Z); + dest.A = (byte)MathF.Round(vector.W); } /// @@ -246,5 +222,17 @@ namespace ImageSharp.PixelFormats return word4 | word3 | word2 | word1; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Vector4 ToScaledVector4() + { + Vector4 vector = this.ToVector4(); + vector /= 65534; + vector *= 255; + vector += Half; + vector += Round; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + return vector; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs index e19df4cfa..8ebea8533 100644 --- a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs @@ -499,7 +499,7 @@ namespace ImageSharp.Quantizers // And set the color of the palette entry var pixel = default(TPixel); - pixel.PackFromBytes(r, g, b, 255); + pixel.PackFromRgba32(new Rgba32(r, g, b, 255)); palette[index] = pixel; // Consume the next palette index diff --git a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs index cf3ff94ee..d121dc6ae 100644 --- a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs @@ -18,11 +18,6 @@ namespace ImageSharp.Quantizers public sealed class PaletteQuantizer : Quantizer where TPixel : struct, IPixel { - /// - /// The pixel buffer, used to reduce allocations. - /// - private readonly byte[] pixelBuffer = new byte[4]; - /// /// A lookup table for colors /// @@ -48,14 +43,9 @@ namespace ImageSharp.Quantizers Rgba32[] constants = ColorConstants.WebSafeColors; TPixel[] safe = new TPixel[constants.Length + 1]; - for (int i = 0; i < constants.Length; i++) - { - constants[i].ToXyzwBytes(this.pixelBuffer, 0); - var packed = default(TPixel); - packed.PackFromBytes(this.pixelBuffer[0], this.pixelBuffer[1], this.pixelBuffer[2], this.pixelBuffer[3]); - safe[i] = packed; - } + Span constantsBytes = constants.AsSpan().NonPortableCast(); + PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); this.colors = safe; } else diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index 501ae7949..be94393a6 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -40,7 +40,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk { int i4 = i * 4; TPixel c = default(TPixel); - c.PackFromBytes(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3]); + c.PackFromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); d[i] = c; } } @@ -48,13 +48,13 @@ namespace ImageSharp.Benchmarks.Color.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().PackFromXyzwBytes(this.source, this.destination, this.Count); + new PixelOperations().PackFromRgba32Bytes(this.source, this.destination, this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.PackFromXyzwBytes(this.source, this.destination, this.Count); + PixelOperations.Instance.PackFromRgba32Bytes(this.source, this.destination, this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index 3c75fc2d1..57fc8bddf 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -46,13 +46,13 @@ namespace ImageSharp.Benchmarks.Color.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().ToXyzBytes(this.source, this.destination, this.Count); + new PixelOperations().ToRgb24Bytes(this.source, this.destination, this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.ToXyzBytes(this.source, this.destination, this.Count); + PixelOperations.Instance.ToRgb24Bytes(this.source, this.destination, this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index f64bf561b..a702e8385 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -51,13 +51,13 @@ namespace ImageSharp.Benchmarks.Color.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().ToXyzwBytes(this.source, this.destination, this.Count); + new PixelOperations().ToRgba32Bytes(this.source, this.destination, this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.ToXyzwBytes(this.source, this.destination, this.Count); + PixelOperations.Instance.ToRgba32Bytes(this.source, this.destination, this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs new file mode 100644 index 000000000..e096fd828 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs @@ -0,0 +1,206 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.General +{ + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + public class PixelConversion_ConvertFromRgba32 + { + interface ITestPixel + where T : struct, ITestPixel + { + void FromRgba32(Rgba32 source); + + void FromRgba32(ref Rgba32 source); + + void FromBytes(byte r, byte g, byte b, byte a); + } + + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + private byte r, g, b, a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + } + + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] dest; + + private Rgba32[] source; + + public ConversionRunner(int count) + { + this.dest = new T[count]; + this.source = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByRefConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromRgba32(ref Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByValConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromRgba32(Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunFromBytesConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sourceBaseRef, i); + Unsafe.Add(ref destBaseRef, i).FromBytes(s.R, s.G, s.B, s.A); + } + } + } + + private ConversionRunner compatibleMemLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(32)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleByRef() + { + this.compatibleMemLayoutRunner.RunByRefConversion(); + } + + [Benchmark] + public void CompatibleByVal() + { + this.compatibleMemLayoutRunner.RunByValConversion(); + } + + [Benchmark] + public void CompatibleFromBytes() + { + this.compatibleMemLayoutRunner.RunFromBytesConversion(); + } + + + [Benchmark] + public void PermutedByRef() + { + this.permutedRunner.RunByRefConversion(); + } + + [Benchmark] + public void PermutedByVal() + { + this.permutedRunner.RunByValConversion(); + } + + [Benchmark] + public void PermutedFromBytes() + { + this.permutedRunner.RunFromBytesConversion(); + } + } + + /* + * Results: + * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | + * ------------------ |------ |----------- |---------- |------- |-------------- | + * CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | + * CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | + * CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | + * PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | + * PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | + * PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | + * + * !!! Conclusion !!! + * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. + * In memory compatible cases we should use the optimized Bulk-copying variant anyways, + * so there is no benefit introducing non-bulk API-s other than PackFromBytes() OR PackFromRgba32(). + */ +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs new file mode 100644 index 000000000..721ac121a --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs @@ -0,0 +1,156 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.General +{ + using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + public class PixelConversion_ConvertFromVector4 + { + interface ITestPixel + where T : struct, ITestPixel + { + void FromVector4(Vector4 source); + + void FromVector4(ref Vector4 source); + } + + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TestRgbaVector : ITestPixel + { + private Vector4 v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.v = p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.v = p; + } + } + + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] dest; + + private Vector4[] source; + + public ConversionRunner(int count) + { + this.dest = new T[count]; + this.source = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByRefConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Vector4 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromVector4(ref Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByValConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Vector4 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromVector4(Unsafe.Add(ref sourceBaseRef, i)); + } + } + } + + private ConversionRunner nonVectorRunner; + + private ConversionRunner vectorRunner; + + [Params(32)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.nonVectorRunner = new ConversionRunner(this.Count); + this.vectorRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void VectorByRef() + { + this.vectorRunner.RunByRefConversion(); + } + + [Benchmark] + public void VectorByVal() + { + this.vectorRunner.RunByValConversion(); + } + + [Benchmark] + public void NonVectorByRef() + { + this.nonVectorRunner.RunByRefConversion(); + } + + [Benchmark] + public void NonVectorByVal() + { + this.nonVectorRunner.RunByValConversion(); + } + + } + + /* + * Results: + * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | + * --------------- |------ |----------- |---------- |------- |-------------- | + * VectorByRef | 32 | 23.6678 ns | 0.1141 ns | 1.00 | 0.00 | + * VectorByVal | 32 | 24.5347 ns | 0.0771 ns | 1.04 | 0.01 | + * NonVectorByRef | 32 | 59.0187 ns | 0.2114 ns | 2.49 | 0.01 | + * NonVectorByVal | 32 | 58.7529 ns | 0.2545 ns | 2.48 | 0.02 | + * + * !!! Conclusion !!! + * We do not need by-ref version of ConvertFromVector4() stuff + */ +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs new file mode 100644 index 000000000..0c9a8af3f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs @@ -0,0 +1,156 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.General +{ + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + /// + /// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer? + /// 1. Rgba32 ToRgba32(); + /// OR + /// 2. void CopyToRgba32(ref Rgba32 dest); + /// ? + /// + public class PixelConversion_ConvertToRgba32 + { + interface ITestPixel + where T : struct, ITestPixel + { + Rgba32 ToRgba32(); + + void CopyToRgba32(ref Rgba32 dest); + } + + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return new Rgba32(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest.R = this.r; + dest.G = this.g; + dest.B = this.b; + dest.A = this.a; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + private byte r, g, b, a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest = Unsafe.As(ref this); + } + } + + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Rgba32[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref Unsafe.Add(ref destBaseRef, i)); + } + } + } + + private ConversionRunner compatibleMemoryLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(128)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.compatibleMemoryLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleRetval() + { + this.compatibleMemoryLayoutRunner.RunRetvalConversion(); + } + + [Benchmark] + public void CompatibleCopyTo() + { + this.compatibleMemoryLayoutRunner.RunCopyToConversion(); + } + + [Benchmark] + public void PermutedRetval() + { + this.permutedRunner.RunRetvalConversion(); + } + + [Benchmark] + public void PermutedCopyTo() + { + this.permutedRunner.RunCopyToConversion(); + } + } + + /* + * Results: + * + * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | + * --------------- |------ |------------ |---------- |------- |-------------- | + * CompatibleRetval | 128 | 89.7358 ns | 2.2389 ns | 1.00 | 0.00 | + * CompatibleCopyTo | 128 | 89.4112 ns | 2.2901 ns | 1.00 | 0.03 | + * PermutedRetval | 128 | 845.4038 ns | 5.6154 ns | 9.43 | 0.23 | + * PermutedCopyTo | 128 | 155.6004 ns | 3.8870 ns | 1.73 | 0.06 | + */ +} \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 53cdffaea..ae17f3698 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -17,8 +17,8 @@ - + diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index b882de0cc..6f93df16e 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Sandbox46 using ImageSharp.Tests; using ImageSharp.Tests.Colors; + using ImageSharp.Tests.PixelFormats; using ImageSharp.Tests.Processing.Transforms; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations.cs b/tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs similarity index 96% rename from tests/ImageSharp.Tests/PixelFormats/PixelOperations.cs rename to tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs index a9108692e..7efd3a6fc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations.cs +++ b/tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Tests.PixelFormats public class PixelOperations { - public static TheoryData blenderMappings = new TheoryData() + public static TheoryData BlenderMappings = new TheoryData() { { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, @@ -39,7 +39,7 @@ namespace ImageSharp.Tests.PixelFormats }; [Theory] - [MemberData(nameof(blenderMappings))] + [MemberData(nameof(BlenderMappings))] public void ReturnsCorrectBlender(TestPixel pixel, Type type, PixelBlenderMode mode) where TPixel : struct, IPixel { diff --git a/tests/ImageSharp.Tests/Common/BufferTests.cs b/tests/ImageSharp.Tests/Common/BufferTests.cs index 010bf40b3..25ef173d4 100644 --- a/tests/ImageSharp.Tests/Common/BufferTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferTests.cs @@ -163,7 +163,7 @@ namespace ImageSharp.Tests.Common // Assert.Equal(buffer.Array, span.ToArray()); // Assert.Equal(0, span.Start); Assert.SpanPointsTo(span, buffer); - Assert.Equal(span.Length, 42); + Assert.Equal(42, span.Length); } } diff --git a/tests/ImageSharp.Tests/Common/ConstantsTests.cs b/tests/ImageSharp.Tests/Common/ConstantsTests.cs index 0adda0c0f..be4addf91 100644 --- a/tests/ImageSharp.Tests/Common/ConstantsTests.cs +++ b/tests/ImageSharp.Tests/Common/ConstantsTests.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Tests.Common [Fact] public void Epsilon() { - Assert.Equal(Constants.Epsilon, 0.001f); + Assert.Equal(0.001f, Constants.Epsilon); } } } diff --git a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs index a291a7d18..1a26bcfed 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/TextGraphicsOptionsTests.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Tests.Drawing.Text TextGraphicsOptions textOptions = opt; - Assert.Equal(false, textOptions.Antialias); + Assert.False(textOptions.Antialias); Assert.Equal(99, textOptions.AntialiasSubpixelDepth); } @@ -36,7 +36,7 @@ namespace ImageSharp.Tests.Drawing.Text GraphicsOptions opt = (GraphicsOptions)textOptions; - Assert.Equal(false, opt.Antialias); + Assert.False(opt.Antialias); Assert.Equal(99, opt.AntialiasSubpixelDepth); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index aac3f4611..f3412e45e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -34,7 +34,7 @@ namespace ImageSharp.Tests }; // [Theory] // Benchmark, enable manually - [MemberData(nameof(DecodeJpegData))] + // [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { const int ExecutionCount = 30; @@ -60,10 +60,10 @@ namespace ImageSharp.Tests // Benchmark, enable manually! // [Theory] - [InlineData(1, 75, JpegSubsample.Ratio420)] - [InlineData(30, 75, JpegSubsample.Ratio420)] - [InlineData(30, 75, JpegSubsample.Ratio444)] - [InlineData(30, 100, JpegSubsample.Ratio444)] + // [InlineData(1, 75, JpegSubsample.Ratio420)] + // [InlineData(30, 75, JpegSubsample.Ratio420)] + // [InlineData(30, 75, JpegSubsample.Ratio444)] + // [InlineData(30, 100, JpegSubsample.Ratio444)] public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { string[] testFiles = TestImages.Bmp.All diff --git a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs index ba55665ca..b7cd281cd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs @@ -19,11 +19,6 @@ namespace ImageSharp.Tests private ITestOutputHelper Output { get; } - private void PrintChannel(string name, JpegPixelArea channel) - { - this.Output.WriteLine($"{name}: Stride={channel.Stride}"); - } - [Theory] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio410, 4, 2)] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio411, 4, 1)] @@ -31,7 +26,10 @@ namespace ImageSharp.Tests [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio422, 2, 1)] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio440, 1, 2)] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio444, 1, 1)] - public void CalculateChrominanceSize(int ratioValue, int expectedDivX, int expectedDivY) + internal void CalculateChrominanceSize( + YCbCrImage.YCbCrSubsampleRatio ratioValue, + int expectedDivX, + int expectedDivY) { YCbCrImage.YCbCrSubsampleRatio ratio = (YCbCrImage.YCbCrSubsampleRatio)ratioValue; @@ -39,7 +37,7 @@ namespace ImageSharp.Tests Size size = YCbCrImage.CalculateChrominanceSize(400, 400, ratio); //this.Output.WriteLine($"Ch Size: {size}"); - Assert.Equal(new Size(400/expectedDivX, 400/expectedDivY), size); + Assert.Equal(new Size(400 / expectedDivX, 400 / expectedDivY), size); } [Theory] @@ -49,7 +47,7 @@ namespace ImageSharp.Tests [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio422, 2)] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio440, 1)] [InlineData(YCbCrImage.YCbCrSubsampleRatio.YCbCrSubsampleRatio444, 1)] - public void Create(int ratioValue, int expectedCStrideDiv) + internal void Create(YCbCrImage.YCbCrSubsampleRatio ratioValue, int expectedCStrideDiv) { YCbCrImage.YCbCrSubsampleRatio ratio = (YCbCrImage.YCbCrSubsampleRatio)ratioValue; @@ -61,10 +59,14 @@ namespace ImageSharp.Tests //this.PrintChannel("Cb", img.CbChannel); //this.PrintChannel("Cr", img.CrChannel); - Assert.Equal(img.YChannel.Width, 400); + Assert.Equal(400, img.YChannel.Width); Assert.Equal(img.CbChannel.Width, 400 / expectedCStrideDiv); Assert.Equal(img.CrChannel.Width, 400 / expectedCStrideDiv); } + private void PrintChannel(string name, JpegPixelArea channel) + { + this.Output.WriteLine($"{name}: Stride={channel.Stride}"); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs index 50a86d3cc..a69727d45 100644 --- a/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs +++ b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs @@ -56,13 +56,13 @@ namespace ImageSharp.Tests.IO [Fact] public void ToBoolean() { - Assert.Equal(false, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0 }, 0)); - Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1 }, 0)); - Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 42 }, 0)); + Assert.False(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0 }, 0)); + Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1 }, 0)); + Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 42 }, 0)); - Assert.Equal(false, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); - Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); - Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 42 }, 1)); + Assert.False(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); + Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); + Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 42 }, 1)); } /// diff --git a/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs index fa8b2a1a2..c46c011a1 100644 --- a/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs +++ b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs @@ -56,11 +56,11 @@ namespace ImageSharp.Tests.IO [Fact] public void ToBoolean() { - Assert.Equal(false, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0 }, 0)); - Assert.Equal(true, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1 }, 0)); + Assert.False(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0 }, 0)); + Assert.True(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1 }, 0)); - Assert.Equal(false, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); - Assert.Equal(true, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); + Assert.False(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); + Assert.True(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); } /// diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index fbfacee32..9f3beb9e8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -7,12 +7,12 @@ True - + - + diff --git a/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs b/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs index 8b4c6ea10..3b224014d 100644 --- a/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs @@ -25,7 +25,7 @@ namespace ImageSharp.Tests Assert.Equal(property1, property2); Assert.True(property1 == property2); - Assert.Equal(property3, null); + Assert.Null(property3); } /// @@ -41,7 +41,7 @@ namespace ImageSharp.Tests Assert.False(property1.Equals("Foo")); - Assert.NotEqual(property1, null); + Assert.NotNull(property1); Assert.NotEqual(property1, property2); Assert.True(property1 != property2); @@ -69,7 +69,7 @@ namespace ImageSharp.Tests { ImageProperty property = new ImageProperty("Foo", null); Assert.Equal("Foo", property.Name); - Assert.Equal(null, property.Value); + Assert.Null(property.Value); property = new ImageProperty("Foo", string.Empty); Assert.Equal(string.Empty, property.Value); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs index a91eb310d..473af7712 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs @@ -44,7 +44,7 @@ namespace ImageSharp.Tests Assert.Equal(ExifDataType.Ascii, value.DataType); Assert.Equal(ExifTag.GPSDOP, value.Tag); - Assert.Equal(false, value.IsArray); + Assert.False(value.IsArray); Assert.Equal("Windows Photo Editor 10.0.10011.16384", value.ToString()); Assert.Equal("Windows Photo Editor 10.0.10011.16384", value.Value); } diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs index 9a2455f0e..6f003cc4d 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs @@ -10,10 +10,12 @@ namespace ImageSharp.Tests.Icc public class IccDataReaderTagDataEntryTests { [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UnknownTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UnknownTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUnknownTagDataEntry(byte[] data, IccUnknownTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUnknownTagDataEntry output = reader.ReadUnknownTagDataEntry(size); @@ -21,10 +23,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ChromaticityTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ChromaticityTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadChromaticityTagDataEntry(byte[] data, IccChromaticityTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccChromaticityTagDataEntry output = reader.ReadChromaticityTagDataEntry(); @@ -32,10 +36,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ColorantOrderTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ColorantOrderTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadColorantOrderTagDataEntry(byte[] data, IccColorantOrderTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccColorantOrderTagDataEntry output = reader.ReadColorantOrderTagDataEntry(); @@ -43,10 +49,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ColorantTableTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ColorantTableTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadColorantTableTagDataEntry(byte[] data, IccColorantTableTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccColorantTableTagDataEntry output = reader.ReadColorantTableTagDataEntry(); @@ -54,10 +62,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.CurveTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.CurveTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadCurveTagDataEntry(byte[] data, IccCurveTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccCurveTagDataEntry output = reader.ReadCurveTagDataEntry(); @@ -65,10 +75,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.DataTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.DataTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadDataTagDataEntry(byte[] data, IccDataTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccDataTagDataEntry output = reader.ReadDataTagDataEntry(size); @@ -76,10 +88,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.DateTimeTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.DateTimeTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadDateTimeTagDataEntry(byte[] data, IccDateTimeTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccDateTimeTagDataEntry output = reader.ReadDateTimeTagDataEntry(); @@ -87,10 +101,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.Lut16TagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.Lut16TagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadLut16TagDataEntry(byte[] data, IccLut16TagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccLut16TagDataEntry output = reader.ReadLut16TagDataEntry(); @@ -98,10 +114,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.Lut8TagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.Lut8TagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadLut8TagDataEntry(byte[] data, IccLut8TagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccLut8TagDataEntry output = reader.ReadLut8TagDataEntry(); @@ -109,10 +127,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.LutAToBTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.LutAToBTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadLutAToBTagDataEntry(byte[] data, IccLutAToBTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccLutAToBTagDataEntry output = reader.ReadLutAtoBTagDataEntry(); @@ -120,10 +140,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.LutBToATagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.LutBToATagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadLutBToATagDataEntry(byte[] data, IccLutBToATagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccLutBToATagDataEntry output = reader.ReadLutBtoATagDataEntry(); @@ -131,10 +153,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.MeasurementTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.MeasurementTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadMeasurementTagDataEntry(byte[] data, IccMeasurementTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccMeasurementTagDataEntry output = reader.ReadMeasurementTagDataEntry(); @@ -142,10 +166,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadMultiLocalizedUnicodeTagDataEntry(byte[] data, IccMultiLocalizedUnicodeTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccMultiLocalizedUnicodeTagDataEntry output = reader.ReadMultiLocalizedUnicodeTagDataEntry(); @@ -153,10 +179,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.MultiProcessElementsTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.MultiProcessElementsTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadMultiProcessElementsTagDataEntry(byte[] data, IccMultiProcessElementsTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccMultiProcessElementsTagDataEntry output = reader.ReadMultiProcessElementsTagDataEntry(); @@ -164,10 +192,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.NamedColor2TagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.NamedColor2TagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadNamedColor2TagDataEntry(byte[] data, IccNamedColor2TagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccNamedColor2TagDataEntry output = reader.ReadNamedColor2TagDataEntry(); @@ -175,10 +205,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ParametricCurveTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ParametricCurveTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadParametricCurveTagDataEntry(byte[] data, IccParametricCurveTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccParametricCurveTagDataEntry output = reader.ReadParametricCurveTagDataEntry(); @@ -186,10 +218,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ProfileSequenceDescTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ProfileSequenceDescTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadProfileSequenceDescTagDataEntry(byte[] data, IccProfileSequenceDescTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccProfileSequenceDescTagDataEntry output = reader.ReadProfileSequenceDescTagDataEntry(); @@ -197,10 +231,14 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ProfileSequenceIdentifierTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] - internal void ReadProfileSequenceIdentifierTagDataEntry(byte[] data, IccProfileSequenceIdentifierTagDataEntry expected) + [MemberData( + nameof(IccTestDataTagDataEntry.ProfileSequenceIdentifierTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] + internal void ReadProfileSequenceIdentifierTagDataEntry( + byte[] data, + IccProfileSequenceIdentifierTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccProfileSequenceIdentifierTagDataEntry output = reader.ReadProfileSequenceIdentifierTagDataEntry(); @@ -208,10 +246,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ResponseCurveSet16TagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ResponseCurveSet16TagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadResponseCurveSet16TagDataEntry(byte[] data, IccResponseCurveSet16TagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccResponseCurveSet16TagDataEntry output = reader.ReadResponseCurveSet16TagDataEntry(); @@ -219,10 +259,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.Fix16ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.Fix16ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadFix16ArrayTagDataEntry(byte[] data, IccFix16ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccFix16ArrayTagDataEntry output = reader.ReadFix16ArrayTagDataEntry(size); @@ -230,10 +272,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.SignatureTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.SignatureTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadSignatureTagDataEntry(byte[] data, IccSignatureTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccSignatureTagDataEntry output = reader.ReadSignatureTagDataEntry(); @@ -241,10 +285,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.TextTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.TextTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadTextTagDataEntry(byte[] data, IccTextTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccTextTagDataEntry output = reader.ReadTextTagDataEntry(size); @@ -252,10 +298,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UFix16ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UFix16ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUFix16ArrayTagDataEntry(byte[] data, IccUFix16ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUFix16ArrayTagDataEntry output = reader.ReadUFix16ArrayTagDataEntry(size); @@ -263,10 +311,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UInt16ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UInt16ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUInt16ArrayTagDataEntry(byte[] data, IccUInt16ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUInt16ArrayTagDataEntry output = reader.ReadUInt16ArrayTagDataEntry(size); @@ -274,10 +324,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UInt32ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UInt32ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUInt32ArrayTagDataEntry(byte[] data, IccUInt32ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUInt32ArrayTagDataEntry output = reader.ReadUInt32ArrayTagDataEntry(size); @@ -285,10 +337,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UInt64ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UInt64ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUInt64ArrayTagDataEntry(byte[] data, IccUInt64ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUInt64ArrayTagDataEntry output = reader.ReadUInt64ArrayTagDataEntry(size); @@ -296,10 +350,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UInt8ArrayTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UInt8ArrayTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUInt8ArrayTagDataEntry(byte[] data, IccUInt8ArrayTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUInt8ArrayTagDataEntry output = reader.ReadUInt8ArrayTagDataEntry(size); @@ -307,10 +363,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ViewingConditionsTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ViewingConditionsTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadViewingConditionsTagDataEntry(byte[] data, IccViewingConditionsTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccViewingConditionsTagDataEntry output = reader.ReadViewingConditionsTagDataEntry(); @@ -318,10 +376,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.XYZTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.XYZTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadXyzTagDataEntry(byte[] data, IccXyzTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccXyzTagDataEntry output = reader.ReadXyzTagDataEntry(size); @@ -329,10 +389,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.TextDescriptionTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.TextDescriptionTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadTextDescriptionTagDataEntry(byte[] data, IccTextDescriptionTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccTextDescriptionTagDataEntry output = reader.ReadTextDescriptionTagDataEntry(); @@ -340,10 +402,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.CrdInfoTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.CrdInfoTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadCrdInfoTagDataEntry(byte[] data, IccCrdInfoTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccCrdInfoTagDataEntry output = reader.ReadCrdInfoTagDataEntry(); @@ -351,10 +415,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.ScreeningTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.ScreeningTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadScreeningTagDataEntry(byte[] data, IccScreeningTagDataEntry expected) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccScreeningTagDataEntry output = reader.ReadScreeningTagDataEntry(); @@ -362,10 +428,12 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.UcrBgTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData( + nameof(IccTestDataTagDataEntry.UcrBgTagDataEntryTestData), + MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadUcrBgTagDataEntry(byte[] data, IccUcrBgTagDataEntry expected, uint size) { - IccDataReader reader = CreateReader(data); + IccDataReader reader = this.CreateReader(data); IccUcrBgTagDataEntry output = reader.ReadUcrBgTagDataEntry(size); diff --git a/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs b/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs index b20b660dd..78fbc68f6 100644 --- a/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs @@ -256,6 +256,7 @@ namespace ImageSharp.Tests Assert.Equal(string.Format(CultureInfo.CurrentCulture, "RectangleF [ X={0}, Y={1}, Width={2}, Height={3} ]", r.X, r.Y, r.Width, r.Height), r.ToString()); } + [Theory] [InlineData(0, 0, 0, 0)] [InlineData(5, -5, 0.2, -1.3)] public void ToStringTestEmpty(float x, float y, float width, float height) diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs new file mode 100644 index 000000000..76001ed3a --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -0,0 +1,143 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Tests +{ + using System.Numerics; + + using ImageSharp.PixelFormats; + + using Xunit; + + public class Bgr24Tests + { + public static readonly TheoryData ColorData = + new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte r, byte g, byte b) + { + var p = new Rgb24(r, g, b); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialBgr() + { + var color = new Bgr24(1, 2, 3); + byte* ptr = (byte*)&color; + + Assert.Equal(3, ptr[0]); + Assert.Equal(2, ptr[1]); + Assert.Equal(1, ptr[2]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equals_WhenTrue(byte r, byte g, byte b) + { + var x = new Bgr24(r, g, b); + var y = new Bgr24(r, g, b); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 1, 2, 4)] + [InlineData(0, 255, 0, 0, 244, 0)] + [InlineData(1, 255, 0, 0, 255, 0)] + public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) + { + var a = new Bgr24(r1, g1, b1); + var b = new Bgr24(r2, g2, b2); + + Assert.False(a.Equals(b)); + Assert.False(a.Equals((object)b)); + } + + + [Fact] + public void PackFromRgba32() + { + var rgb = default(Bgr24); + rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void PackFromVector4() + { + var rgb = default(Bgr24); + rgb.PackFromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + [Fact] + public void ToVector4() + { + var rgb = new Bgr24(1, 2, 3); + + Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); + } + + [Fact] + public void ToRgb24() + { + var rgb = new Bgr24(1, 2, 3); + var dest = default(Rgb24); + + rgb.ToRgb24(ref dest); + + Assert.Equal(new Rgb24(1, 2, 3), dest); + } + + [Fact] + public void ToRgba32() + { + var rgb = new Bgr24(1, 2, 3); + var rgba = default(Rgba32); + + rgb.ToRgba32(ref rgba); + + Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + } + + [Fact] + public void ToBgr24() + { + var rgb = new Bgr24(1, 2, 3); + var bgr = default(Bgr24); + + rgb.ToBgr24(ref bgr); + + Assert.Equal(new Bgr24(1, 2, 3), bgr); + } + + [Fact] + public void ToBgra32() + { + var rgb = new Bgr24(1, 2, 3); + var bgra = default(Bgra32); + + rgb.ToBgra32(ref bgra); + + Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs new file mode 100644 index 000000000..1928d51f6 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -0,0 +1,150 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Tests +{ + using System.Numerics; + + using ImageSharp.PixelFormats; + + using Xunit; + + public class Bgra32Tests + { + public static readonly TheoryData ColorData = + new TheoryData() + { + { 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } + }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte b, byte g, byte r, byte a) + { + var p = new Bgra32(r, g, b, a); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + Assert.Equal(a, p.A); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialBgra() + { + var color = new Bgra32(1, 2, 3, 4); + byte* ptr = (byte*)&color; + + Assert.Equal(3, ptr[0]); + Assert.Equal(2, ptr[1]); + Assert.Equal(1, ptr[2]); + Assert.Equal(4, ptr[3]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equality_WhenTrue(byte b, byte g, byte r, byte a) + { + var x = new Bgra32(r, g, b, a); + var y = new Bgra32(r, g, b, a); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 4, 1, 2, 3, 5)] + [InlineData(0, 0, 255, 0, 0, 0, 244, 0)] + [InlineData(0, 255, 0, 0, 0, 244, 0, 0)] + [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] + public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) + { + var x = new Bgra32(r1, g1, b1, a1); + var y = new Bgra32(r2, g2, b2, a2); + + Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + } + + + [Fact] + public void PackFromRgba32() + { + var rgb = default(Rgb24); + rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void PackFromVector4() + { + var c = default(Bgra32); + c.PackFromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, c.R); + Assert.Equal(2, c.G); + Assert.Equal(3, c.B); + Assert.Equal(4, c.A); + } + + [Fact] + public void ToVector4() + { + var rgb = new Bgra32(1, 2, 3, 4); + + Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); + } + + [Fact] + public void ToRgb24() + { + var c = new Bgra32(1, 2, 3, 4); + var dest = default(Rgb24); + + c.ToRgb24(ref dest); + + Assert.Equal(new Rgb24(1, 2, 3), dest); + } + + [Fact] + public void ToRgba32() + { + var c = new Bgra32(1, 2, 3, 4); + var rgba = default(Rgba32); + + c.ToRgba32(ref rgba); + + Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); + } + + [Fact] + public void ToBgr24() + { + var rgb = new Bgra32(1, 2, 3, 4); + var bgr = default(Bgr24); + + rgb.ToBgr24(ref bgr); + + Assert.Equal(new Bgr24(1, 2, 3), bgr); + } + + [Fact] + public void ToBgra32() + { + var rgb = new Bgra32(1, 2, 3, 4); + var bgra = default(Bgra32); + + rgb.ToBgra32(ref bgra); + + Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/ColorConstructorTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/ColorConstructorTests.cs rename to tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs diff --git a/tests/ImageSharp.Tests/Colors/ColorDefinitionTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorDefinitionTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/ColorDefinitionTests.cs rename to tests/ImageSharp.Tests/PixelFormats/ColorDefinitionTests.cs diff --git a/tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs rename to tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs diff --git a/tests/ImageSharp.Tests/Colors/ColorPackingTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/ColorPackingTests.cs rename to tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs diff --git a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Colors/PackedPixelTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs index 5ec7c21bb..773bfa513 100644 --- a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs @@ -40,10 +40,10 @@ namespace ImageSharp.Tests.Colors // Test ordering Vector4 vector = new Alpha8(.5F).ToVector4(); - Assert.Equal(vector.X, 0); - Assert.Equal(vector.Y, 0); - Assert.Equal(vector.Z, 0); - Assert.Equal(vector.W, .5F, 2); + Assert.Equal(0, vector.X); + Assert.Equal(0, vector.Y); + Assert.Equal(0, vector.Z); + Assert.Equal(.5F, vector.W, 2); byte[] rgb = new byte[3]; byte[] rgba = new byte[4]; @@ -302,7 +302,7 @@ namespace ImageSharp.Tests.Colors Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 }); Byte4 r = new Byte4(); - r.PackFromBytes(20, 38, 0, 255); + r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); } @@ -448,7 +448,7 @@ namespace ImageSharp.Tests.Colors float y = -0.3f; Assert.Equal(0xda0d, new NormalizedByte2(x, y).PackedValue); NormalizedByte2 n = new NormalizedByte2(); - n.PackFromBytes(141, 90, 0, 0); + n.PackFromRgba32(new Rgba32(141, 90, 0, 0)); Assert.Equal(0xda0d, n.PackedValue); byte[] rgb = new byte[3]; @@ -491,7 +491,7 @@ namespace ImageSharp.Tests.Colors float w = -0.7f; Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); NormalizedByte4 n = new NormalizedByte4(); - n.PackFromBytes(141, 90, 192, 39); + n.PackFromRgba32(new Rgba32(141, 90, 192, 39)); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); @@ -515,7 +515,7 @@ namespace ImageSharp.Tests.Colors // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 NormalizedByte4 r = new NormalizedByte4(); - r.PackFromBytes(9, 115, 202, 127); + r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); @@ -554,7 +554,7 @@ namespace ImageSharp.Tests.Colors byte[] bgra = new byte[4]; NormalizedShort2 n = new NormalizedShort2(); - n.PackFromBytes(141, 90, 0, 0); + n.PackFromRgba32(new Rgba32(141, 90, 0, 0)); n.ToXyzBytes(rgb, 0); Assert.Equal(rgb, new byte[] { 141, 90, 0 }); @@ -615,7 +615,7 @@ namespace ImageSharp.Tests.Colors Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 }); NormalizedShort4 r = new NormalizedShort4(); - r.PackFromBytes(9, 115, 202, 127); + r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); } @@ -708,7 +708,7 @@ namespace ImageSharp.Tests.Colors // Alpha component accuracy will be awful. Rgba1010102 r = new Rgba1010102(); - r.PackFromBytes(25, 0, 128, 0); + r.PackFromRgba32(new Rgba32(25, 0, 128, 0)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); } @@ -801,7 +801,7 @@ namespace ImageSharp.Tests.Colors Assert.Equal(bgra, new byte[] { 76, 38, 20, 115 }); Rgba64 r = new Rgba64(); - r.PackFromBytes(20, 38, 76, 115); + r.PackFromRgba32(new Rgba32(20, 38, 76, 115)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 }); } @@ -856,7 +856,7 @@ namespace ImageSharp.Tests.Colors Assert.Equal(bgra, new byte[] { 0, 127, 128, 255 }); Short2 r = new Short2(); - r.PackFromBytes(20, 38, 0, 255); + r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); } @@ -913,7 +913,7 @@ namespace ImageSharp.Tests.Colors Assert.Equal(bgra, new byte[] { 243, 177, 172, 128 }); Short4 r = new Short4(); - r.PackFromBytes(20, 38, 0, 255); + r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); r.ToXyzwBytes(rgba, 0); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs new file mode 100644 index 000000000..ce81499ed --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -0,0 +1,50 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.PixelFormats +{ + using System; + using System.Collections.Generic; + using System.Text; + using ImageSharp.PixelFormats; + using ImageSharp.PixelFormats.PixelBlenders; + using ImageSharp.Tests.TestUtilities; + using Xunit; + + public partial class PixelOperationsTests + { + public static TheoryData BlenderMappings = new TheoryData() + { + { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, + { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, + + { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, + { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, + }; + + [Theory] + [MemberData(nameof(BlenderMappings))] + public void ReturnsCorrectBlender(TestPixel pixel, Type type, PixelBlenderMode mode) + where TPixel : struct, IPixel + { + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode); + Assert.IsType(type, blender); + } + } +} diff --git a/tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs similarity index 90% rename from tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index c91218ccc..0a121cfce 100644 --- a/tests/ImageSharp.Tests/Colors/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -1,6 +1,6 @@ // ReSharper disable InconsistentNaming // ReSharper disable AccessToDisposedClosure -namespace ImageSharp.Tests.Colors +namespace ImageSharp.Tests.PixelFormats { using System; using System.Numerics; @@ -11,8 +11,9 @@ namespace ImageSharp.Tests.Colors using Xunit; using Xunit.Abstractions; - public class PixelOperationsTests + public partial class PixelOperationsTests { + public class Color32 : PixelOperationsTests { public Color32(ITestOutputHelper output) @@ -42,8 +43,11 @@ namespace ImageSharp.Tests.Colors ); } + // [Fact] // Profiling benchmark - enable manually! +#pragma warning disable xUnit1013 // Public method should be marked as test public void Benchmark_ToVector4() +#pragma warning restore xUnit1013 // Public method should be marked as test { int times = 200000; int count = 1024; @@ -155,13 +159,13 @@ namespace ImageSharp.Tests.Colors { int i3 = i * 3; - expected[i].PackFromBytes(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255); + expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); } TestOperation( source, expected, - (s, d) => Operations.PackFromXyzBytes(s, d, count) + (s, d) => Operations.PackFromRgb24Bytes(s, d, count) ); } @@ -181,7 +185,7 @@ namespace ImageSharp.Tests.Colors TestOperation( source, expected, - (s, d) => Operations.ToXyzBytes(s, d, count) + (s, d) => Operations.ToRgb24Bytes(s, d, count) ); } @@ -196,13 +200,13 @@ namespace ImageSharp.Tests.Colors { int i4 = i * 4; - expected[i].PackFromBytes(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3]); + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromXyzwBytes(s, d, count) + (s, d) => Operations.PackFromRgba32Bytes(s, d, count) ); } @@ -222,7 +226,7 @@ namespace ImageSharp.Tests.Colors TestOperation( source, expected, - (s, d) => Operations.ToXyzwBytes(s, d, count) + (s, d) => Operations.ToRgba32Bytes(s, d, count) ); } @@ -237,13 +241,13 @@ namespace ImageSharp.Tests.Colors { int i3 = i * 3; - expected[i].PackFromBytes(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255); + expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); } TestOperation( source, expected, - (s, d) => Operations.PackFromZyxBytes(s, d, count) + (s, d) => Operations.PackFromBgr24Bytes(s, d, count) ); } @@ -263,7 +267,7 @@ namespace ImageSharp.Tests.Colors TestOperation( source, expected, - (s, d) => Operations.ToZyxBytes(s, d, count) + (s, d) => Operations.ToBgr24Bytes(s, d, count) ); } @@ -278,13 +282,13 @@ namespace ImageSharp.Tests.Colors { int i4 = i * 4; - expected[i].PackFromBytes(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3]); + expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromZyxwBytes(s, d, count) + (s, d) => Operations.PackFromBgra32Bytes(s, d, count) ); } @@ -304,7 +308,7 @@ namespace ImageSharp.Tests.Colors TestOperation( source, expected, - (s, d) => Operations.ToZyxwBytes(s, d, count) + (s, d) => Operations.ToBgra32Bytes(s, d, count) ); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs new file mode 100644 index 000000000..1d0d024fb --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -0,0 +1,143 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Tests +{ + using System; + using System.Numerics; + + using ImageSharp.PixelFormats; + + using Xunit; + + public class Rgb24Tests + { + public static readonly TheoryData ColorData = + new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte r, byte g, byte b) + { + var p = new Rgb24(r, g, b); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialRgb() + { + var color = new Rgb24(1, 2, 3); + byte* ptr = (byte*)&color; + + Assert.Equal(1, ptr[0]); + Assert.Equal(2, ptr[1]); + Assert.Equal(3, ptr[2]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equals_WhenTrue(byte r, byte g, byte b) + { + var x = new Rgb24(r, g, b); + var y = new Rgb24(r, g, b); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 1, 2, 4)] + [InlineData(0, 255, 0, 0, 244, 0)] + [InlineData(1, 255, 0, 0, 255, 0)] + public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) + { + var a = new Rgb24(r1, g1, b1); + var b = new Rgb24(r2, g2, b2); + + Assert.False(a.Equals(b)); + Assert.False(a.Equals((object)b)); + } + + [Fact] + public void PackFromRgba32() + { + var rgb = default(Rgb24); + rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void PackFromVector4() + { + var rgb = default(Rgb24); + rgb.PackFromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + [Fact] + public void ToVector4() + { + var rgb = new Rgb24(1, 2, 3); + + Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); + } + + [Fact] + public void ToRgb24() + { + var rgb = new Rgb24(1, 2, 3); + var dest = default(Rgb24); + + rgb.ToRgb24(ref dest); + + Assert.Equal(rgb, dest); + } + + [Fact] + public void ToRgba32() + { + var rgb = new Rgb24(1, 2, 3); + var rgba = default(Rgba32); + + rgb.ToRgba32(ref rgba); + + Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + } + + [Fact] + public void ToBgr24() + { + var rgb = new Rgb24(1, 2, 3); + var bgr = default(Bgr24); + + rgb.ToBgr24(ref bgr); + + Assert.Equal(new Bgr24(1, 2, 3), bgr); + } + + [Fact] + public void ToBgra32() + { + var rgb = new Rgb24(1, 2, 3); + var bgra = default(Bgra32); + + rgb.ToBgra32(ref bgra); + + Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/Rgba32Tests.cs rename to tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs diff --git a/tests/ImageSharp.Tests/Colors/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/RgbaVectorTests.cs rename to tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs diff --git a/tests/ImageSharp.Tests/Colors/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Colors/UnPackedPixelTests.cs rename to tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs diff --git a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs index 666f3df78..7caa1e7c0 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs @@ -26,7 +26,7 @@ namespace ImageSharp.Tests.Processing.Transforms { for (int x = 0; x < 25; x++) { - Assert.Equal(image[x, y], default(TPixel)); + Assert.Equal(default(TPixel), image[x, y]); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeProfilingBenchmarks.cs index 8b57586f4..a300672e8 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeProfilingBenchmarks.cs @@ -25,8 +25,8 @@ namespace ImageSharp.Tests.Processing.Transforms public int ExecutionCount { get; set; } = 50; // [Theory] // Benchmark, enable manually! - [InlineData(100, 100)] - [InlineData(2000, 2000)] + // [InlineData(100, 100)] + // [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) { this.Measure(this.ExecutionCount, diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 65d55da55..0caded420 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -53,11 +53,11 @@ namespace ImageSharp.Tests { Image image = base.GetImage(); TPixel color = default(TPixel); - color.PackFromBytes(this.r, this.g, this.b, this.a); + color.PackFromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); return image.Fill(color); } - + public override void Serialize(IXunitSerializationInfo info) { info.AddValue("red", this.r); diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index 5c676d07c..645a4dc59 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -52,6 +52,12 @@ namespace ImageSharp.Tests Short4 = 1 << 17, + Rgb24 = 18, + + Bgr24 = 19, + + Bgra32 = 20, + // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 6bd5b392d..c01babb63 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -103,8 +103,8 @@ namespace ImageSharp.Tests where TPixel : struct, IPixel { Image img = provider.GetImage(); - Assert.Equal(img.Width, 10); - Assert.Equal(img.Height, 20); + Assert.Equal(10, img.Width); + Assert.Equal(20, img.Height); byte[] colors = new byte[4]; @@ -116,10 +116,10 @@ namespace ImageSharp.Tests { pixels[x, y].ToXyzwBytes(colors, 0); - Assert.Equal(colors[0], 255); - Assert.Equal(colors[1], 100); - Assert.Equal(colors[2], 50); - Assert.Equal(colors[3], 200); + Assert.Equal(255, colors[0]); + Assert.Equal(100, colors[1]); + Assert.Equal(50, colors[2]); + Assert.Equal(200, colors[3]); } } } @@ -143,7 +143,7 @@ namespace ImageSharp.Tests where TPixel : struct, IPixel { Image img = provider.GetImage(); - Assert.Equal(img.Width, 3); + Assert.Equal(3, img.Width); if (provider.PixelType == PixelTypes.Rgba32) { Assert.IsType>(img); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index a35c73aef..437c295b9 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -118,7 +118,7 @@ namespace ImageSharp.Tests IEnumerable> expanded = pixelTypes.ExpandAllTypes(); - Assert.Equal(expanded.Count(), 4); + Assert.Equal(4, expanded.Count()); AssertContainsPixelType(PixelTypes.Alpha8, expanded); AssertContainsPixelType(PixelTypes.Bgr565, expanded);