Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote PixelTypeInfo to Pixel #2601

Merged
merged 20 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ImageSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3
src\Directory.Build.props = src\Directory.Build.props
src\Directory.Build.targets = src\Directory.Build.targets
src\README.md = src\README.md
src\ImageSharp.ruleset = src\ImageSharp.ruleset
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}"
Expand Down
1 change: 1 addition & 0 deletions src/ImageSharp.ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<Include Path="..\shared-infrastructure\sixlabors.ruleset" Action="Default" />
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1011" Action="None" />
<Rule Id="SA1648" Action="None" /> <!--https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3595-->
</Rules>
</RuleSet>
7 changes: 5 additions & 2 deletions src/ImageSharp/Color/Color.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp;
Expand Down Expand Up @@ -107,7 +108,7 @@ private Color(IPixel pixel)
public static Color FromPixel<TPixel>(TPixel pixel)
where TPixel : unmanaged, IPixel<TPixel>
{
// Avoid boxing in case we can convert to Rgba64 safely and efficently
// Avoid boxing in case we can convert to Rgba64 safely and efficiently
if (typeof(TPixel) == typeof(Rgba64))
{
return new((Rgba64)(object)pixel);
Expand All @@ -124,7 +125,9 @@ public static Color FromPixel<TPixel>(TPixel pixel)
{
return new((L16)(object)pixel);
}
else if (Unsafe.SizeOf<TPixel>() <= Unsafe.SizeOf<Rgba32>())

Copy link
Member

@antonfirsov antonfirsov Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not critical, I would prefer an abstraction that can get rid of the Rgba64-L16 special cases above this line - by moving them to IPixel<T> / PixelOperations code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me also. In this case I think we should ditch the specialisation and box anything greater than byte. ColorFromPixel is not area for high performance operations.

On IPixel I would, if we can, drop all the various FromXX specialisation there also and ensure a good optimised bulk operations for all Rgba32 compatible pixel formats. That may not be possible though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ColorFromPixel is not area for high performance operations.

Color.ToPixel already has a bulk variant, and I remember that we have found a use case for the inverse bulk operation: #2485 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well remembered, but those are really short loops (max 256) in real terms. I'd hate to limit our flexibility and extensibility based on introducing a requirement there.

Ideally, I want to introduce as much agnostity as possible in our APIs.

Copy link
Member

@antonfirsov antonfirsov Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boxing is very ugly, even if done <=256x typically, I would try to avoid it if there are alternatives.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we just back Color with Vector4? it already takes up the same amount of space and means we would be able to use bulk operations.

Copy link
Member

@antonfirsov antonfirsov Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason we introduced the ability to define (higher than Vector4) arbitrary-precison pixel types was this feature request: SixLabors/ImageSharp.Drawing#165

I like the fact that ImageSharp supports such "images". (At least for some use-cases)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then use Vector4 as the default and box anything bigger. People expected double precision are in for a rough time with the library since almost everything is converted to use single precision at some point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated Color to use Vector4 to avoid boxing. I've also removed the implicit casting for random pixel formats in favour of explicit methods.

PixelTypeInfo info = TPixel.GetPixelTypeInfo();
if (info.ComponentPrecision <= PixelComponentPrecision.Byte)
{
Rgba32 p = default;
pixel.ToRgba32(ref p);
Expand Down
47 changes: 24 additions & 23 deletions src/ImageSharp/Formats/PixelTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,51 @@
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;

// TODO: Review this class as it's used to represent 2 different things.
// TODO: Review this type as it's used to represent 2 different things.
// 1.The encoded image pixel format.
// 2. The pixel format of the decoded image.
namespace SixLabors.ImageSharp.Formats;

/// <summary>
/// Contains information about the pixels that make up an images visual data.
/// </summary>
public class PixelTypeInfo
/// <remarks>
/// Initializes a new instance of the <see cref="PixelTypeInfo"/> struct.
/// </remarks>
/// <param name="bitsPerPixel">Color depth, in number of bits per pixel.</param>
public readonly struct PixelTypeInfo(int bitsPerPixel)
{
/// <summary>
/// Initializes a new instance of the <see cref="PixelTypeInfo"/> class.
/// Gets color depth, in number of bits per pixel.
/// </summary>
/// <param name="bitsPerPixel">Color depth, in number of bits per pixel.</param>
public PixelTypeInfo(int bitsPerPixel)
=> this.BitsPerPixel = bitsPerPixel;
public int BitsPerPixel { get; init; } = bitsPerPixel;

/// <summary>
/// Initializes a new instance of the <see cref="PixelTypeInfo"/> class.
/// Gets the count of the color components
/// </summary>
/// <param name="bitsPerPixel">Color depth, in number of bits per pixel.</param>
/// <param name="alpha">The pixel alpha transparency behavior.</param>
public PixelTypeInfo(int bitsPerPixel, PixelAlphaRepresentation alpha)
{
this.BitsPerPixel = bitsPerPixel;
this.AlphaRepresentation = alpha;
}
public byte ComponentCount { get; init; }
Copy link
Member

@antonfirsov antonfirsov Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider changing this to int.

Suggested change
public byte ComponentCount { get; init; }
public int ComponentCount { get; init; }

Unless there is a reason to compress data for optimization (=the type is expected to be instantiated very frequently), it is generally recommended to prefer int over other integral types in .NET APIs. For example, IPEndPoint.Port is an int, while technically it could be an ushort. The reason is that this removes the need for conversion which is both expensive and complicated.

On the other hand, I noticed that we use non-int integrals in other descriptor types, eg. PngMetadata. I wish I noticed this earlier.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve often wondered if there was a rule. For v4 we can definitely fix this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it's not codified in the Framework Design Guidelines, but it exists for BCL APIs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good. I've fixed the property for this PR, we can look at others.


/// <summary>
/// Gets color depth, in number of bits per pixel.
/// Gets the pixel component precision.
/// </summary>
public int BitsPerPixel { get; }
public PixelComponentPrecision? ComponentPrecision { get; init; }
Copy link
Member

@antonfirsov antonfirsov Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK there might be pixel types with asymmetric component precision. (I remember briefly touching this topic in an old discussion with Clinton.)

How would this model handle such pixel types?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It represents the maximum component precision. It’s in the description but perhaps including it in the type name or property name is better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the usages of the property, and the only way we use it is the info.ComponentPrecision <= PixelComponentPrecision.Byte comparison, meaning that the only thing we need this for is to determine if the precision is below or above a certain treshold, and the exact precision information is practically unused. Unless we think there are use cases (proven by actual user user need) to observe the precision of the highest precision component, IMO we should try to avoid exposing such a property and explore alternative options to solve this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought process is that users can implement custom performance optimized processors based upon this implementation. If they know the precision, they could operate over byte vs Vector4.

The use case that I've currently implemented fixes a bug we had also.

Rgba1010102 uses a uint as its packed value which is the same size as Rgba32 but we lose precision for the RGB components if we convert to it as we were since they require 10 bit precision.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that ComponentCount is a similar informative property. I didn't notice this fact in the #2534 discussion. The way I view this now is that we are attempting to add a Rich Pixel Type Descriptor feature. IMO there are a couple of important points we should consider before fully committing to it:

  • To really get this right, it might be better to expose a struct/class ComponentInfo and a property in PixelTypeInfo that enumerates the ComponentInfos, so each component can tell its precision separately instead of telling the maximum (for which I'm not sure if there is a use-case except the conversion implementation this PR is proposing). As far as I can recall that old discussion with Clinton, WIC has such a model but I may be wrong.
  • Note that this feature idea doesn't necessarily overlap with the Pixel <=> Color conversion. I don't see how can we implement efficient bulk conversion using these descriptor information only. In fact, if our goal is to solve the Pixel <=> Color conversion thing, it might be better to promote the conversion (& bulk conversion) methods to PixelOperations<T>.
  • Considering that this isn't super trivial to get right, I'm really curious if we have enough evidence (=enough users) proving that the Rich Pixel Type Descriptor feature is worth the headache.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's neat! I think you might have to be able to account for padding bits, so I'm not sure you can get away with not having a mask per channel. I'm trying to think of tricky examples... I've seen some BMPs that have gaps in the channel masks, but those were of the stress-test variety, not real world. You'll have real-world formats like B10G10R10, which is 32-bit with 2 bits padding, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that's required for our use cases which is what precision can I safly store this pixel in.

We can tell the actual size of the pixel format from the info since the types themselves must handle padding. Unsafe.Sizeof<B10G10R10>() should be the same size Unsafe.Sizeof<Rgba1010102>() which is 4.

Theoretically we could add padding to the info. I'm assuming though that world is not completely mad and padding is always at the end?

Copy link
Contributor

@saucecontrol saucecontrol Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I don't think you'll see a real-world case where BitsPerPixel - Sum(ChannelPrecision) doesn't give you the padding bits, which should always be at the end. Just trying to come up with reasons explicit masks might be beneficial, and weirdo pixel formats with interior padding are at least a possibility.

The other thing I guess that's useful in an explicit channel mask is that it also communicates the channel order. I'm not sure if WIC actually uses that information in that way, but I suppose it might. They don't expose channel order in any other way in their format definitions. It's just in the name and in the mask.

Edit: Never mind, there's no channel order conveyed in the mask. BGR and RGB have the same masks, so you can only know how to interpret them by knowing the name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll go with real world for now. If someone wants something really weird, they can find a really weird library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type has been introduced as PixelComponentInfo


/// <summary>
/// Gets the pixel alpha transparency behavior.
/// <see langword="null"/> means unknown, unspecified.
/// </summary>
public PixelAlphaRepresentation? AlphaRepresentation { get; }

internal static PixelTypeInfo Create<TPixel>()
where TPixel : unmanaged, IPixel<TPixel>
=> new(Unsafe.SizeOf<TPixel>() * 8);
public PixelAlphaRepresentation? AlphaRepresentation { get; init; }

internal static PixelTypeInfo Create<TPixel>(PixelAlphaRepresentation alpha)
internal static PixelTypeInfo Create<TPixel>(
byte componentCount,
PixelComponentPrecision componentPrecision,
PixelAlphaRepresentation pixelAlphaRepresentation)
where TPixel : unmanaged, IPixel<TPixel>
=> new(Unsafe.SizeOf<TPixel>() * 8, alpha);
=> new()
{
BitsPerPixel = Unsafe.SizeOf<TPixel>() * 8,
ComponentCount = componentCount,
ComponentPrecision = componentPrecision,
AlphaRepresentation = pixelAlphaRepresentation
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels,
Span<byte> a = data[1].GetSpan();
Span<byte> b = data[2].GetSpan();

var color = default(TPixel);
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
for (int x = 0; x < pixelRow.Length; x++)
{
var lab = new CieLab((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]);
var rgb = ColorSpaceConverter.ToRgb(lab);
CieLab lab = new((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]);
Rgb rgb = ColorSpaceConverter.ToRgb(lab);

color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;

offset++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]);
Rgb rgb = ColorSpaceConverter.ToRgb(lab);

color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;

offset += 3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, in
Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255);
Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk);

color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;

offset += 4;
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Image{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public Image(int width, int height)
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata ?? new(), width, height)
: base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height)
=> this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));

/// <summary>
Expand Down Expand Up @@ -111,7 +111,7 @@ internal Image(
int width,
int height,
ImageMetadata metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
: base(configuration, TPixel.GetPixelTypeInfo(), metadata, width, height)
=> this.frames = new ImageFrameCollection<TPixel>(this, width, height, memoryGroup);

/// <summary>
Expand All @@ -129,7 +129,7 @@ internal Image(
int height,
TPixel backgroundColor,
ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata ?? new(), width, height)
: base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height)
=> this.frames = new ImageFrameCollection<TPixel>(this, width, height, backgroundColor);

/// <summary>
Expand All @@ -140,7 +140,7 @@ internal Image(
/// <param name="metadata">The images metadata.</param>
/// <param name="frames">The frames that will be owned by this image instance.</param>
internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable<ImageFrame<TPixel>> frames)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, ValidateFramesAndGetSize(frames))
: base(configuration, TPixel.GetPixelTypeInfo(), metadata, ValidateFramesAndGetSize(frames))
=> this.frames = new ImageFrameCollection<TPixel>(this, frames);

/// <inheritdoc />
Expand Down
9 changes: 9 additions & 0 deletions src/ImageSharp/PixelFormats/IPixel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.

using System.Numerics;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand All @@ -14,6 +15,14 @@ namespace SixLabors.ImageSharp.PixelFormats;
public interface IPixel<TSelf> : IPixel, IEquatable<TSelf>
where TSelf : unmanaged, IPixel<TSelf>
{
/// <summary>
/// Gets the pixel type information.
/// </summary>
/// <returns>The <see cref="PixelTypeInfo"/>.</returns>
#pragma warning disable CA1000
static abstract PixelTypeInfo GetPixelTypeInfo();
#pragma warning restore CA1000

/// <summary>
/// Creates a <see cref="PixelOperations{TPixel}"/> instance for this pixel type.
/// This method is not intended to be consumed directly. Use <see cref="PixelOperations{TPixel}.Instance"/> instead.
Expand Down
50 changes: 50 additions & 0 deletions src/ImageSharp/PixelFormats/PixelComponentPrecision.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.PixelFormats;

/// <summary>
/// Provides enumeration of the maximum precision of individual components within a pixel format.
/// </summary>
public enum PixelComponentPrecision
{
/// <summary>
/// 8-bit signed integer.
/// </summary>
SByte,

/// <summary>
/// 8-bit unsigned integer.
/// </summary>
Byte,

/// <summary>
/// 16-bit signed integer.
/// </summary>
Short,

/// <summary>
/// 16-bit unsigned integer.
/// </summary>
UShort,

/// <summary>
/// 32-bit signed integer.
/// </summary>
Int,

/// <summary>
/// 32-bit unsigned integer.
/// </summary>
UInt,

/// <summary>
/// 16-bit floating point.
/// </summary>
Half,

/// <summary>
/// 32-bit floating point.
/// </summary>
Float
}
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -55,6 +56,9 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(A8 left, A8 right) => !left.Equals(right);

/// <inheritdoc/>
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<A8>(1, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated);

/// <inheritdoc />
public readonly PixelOperations<A8> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -183,6 +184,9 @@ public uint PackedValue
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Abgr32>(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated);

/// <inheritdoc />
public readonly PixelOperations<Abgr32> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -183,6 +184,9 @@ public uint PackedValue
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Argb32>(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated);

/// <inheritdoc />
public readonly PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -87,6 +88,9 @@ public Bgr24(byte r, byte g, byte b)
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Bgr24>(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None);

/// <inheritdoc/>
public readonly PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -59,6 +60,9 @@ public Bgr565(float x, float y, float z)
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Bgr565>(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None);

/// <inheritdoc />
public readonly PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -136,6 +137,9 @@ public uint PackedValue
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Bgra32>(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated);

/// <inheritdoc/>
public readonly PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations();

Expand Down
4 changes: 4 additions & 0 deletions src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;

namespace SixLabors.ImageSharp.PixelFormats;

Expand Down Expand Up @@ -57,6 +58,9 @@ public Bgra4444(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right);

/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create<Bgra4444>(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated);

/// <inheritdoc />
public readonly PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations();

Expand Down
Loading
Loading