<PackageReference Include="System.Drawing.Common" Version="9.0.1" />

Matrix

public sealed class Matrix : MarshalByRefObject, IDisposable
Encapsulates a 3-by-3 affine matrix that represents a geometric transform. This class cannot be inherited.
using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.CompilerServices; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.GdiPlus; namespace System.Drawing.Drawing2D { public sealed class Matrix : MarshalByRefObject, IDisposable { internal unsafe global::Windows.Win32.Graphics.GdiPlus.Matrix* NativeMatrix { get; set; } [Nullable(1)] public float[] Elements { [NullableContext(1)] get { float[] array = new float[6]; GetElements(array); return array; } } public unsafe Matrix3x2 MatrixElements { get { Matrix3x2 result = default(Matrix3x2); PInvoke.GdipGetMatrixElements(NativeMatrix, (float*)(&result)).ThrowIfFailed(); GC.KeepAlive(this); return result; } set { PInvoke.GdipSetMatrixElements(NativeMatrix, value.M11, value.M12, value.M21, value.M22, value.M31, value.M32).ThrowIfFailed(); GC.KeepAlive(this); } } public float OffsetX => Offset.X; public float OffsetY => Offset.Y; internal unsafe PointF Offset { get { Span<float> elements = new Span<float>(stackalloc byte[24], 6); GetElements(elements); return new PointF(elements[4], elements[5]); } } public unsafe bool IsInvertible { get { BOOL value = default(BOOL); PInvoke.GdipIsMatrixInvertible(NativeMatrix, &value).ThrowIfFailed(); GC.KeepAlive(this); return value; } } public unsafe bool IsIdentity { get { BOOL value = default(BOOL); PInvoke.GdipIsMatrixIdentity(NativeMatrix, &value).ThrowIfFailed(); GC.KeepAlive(this); return value; } } public unsafe Matrix() { global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCreateMatrix(&nativeMatrix).ThrowIfFailed(); NativeMatrix = nativeMatrix; } public unsafe Matrix(float m11, float m12, float m21, float m22, float dx, float dy) { global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCreateMatrix2(m11, m12, m21, m22, dx, dy, &nativeMatrix).ThrowIfFailed(); NativeMatrix = nativeMatrix; } public unsafe Matrix(Matrix3x2 matrix) : this(CreateNativeHandle(matrix)) { } private unsafe Matrix(global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix) { NativeMatrix = nativeMatrix; } internal unsafe static global::Windows.Win32.Graphics.GdiPlus.Matrix* CreateNativeHandle(Matrix3x2 matrix) { global::Windows.Win32.Graphics.GdiPlus.Matrix* result = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCreateMatrix2(matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32, &result).ThrowIfFailed(); return result; } [NullableContext(1)] public unsafe Matrix(RectangleF rect, params PointF[] plgpts) { ArgumentNullException.ThrowIfNull(plgpts, "plgpts"); if (plgpts.Length != 3) throw Status.InvalidParameter.GetException(); fixed (PointF* dstplg = plgpts) { global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCreateMatrix3((RectF*)(&rect), (global::Windows.Win32.Graphics.GdiPlus.PointF*)dstplg, &nativeMatrix).ThrowIfFailed(); NativeMatrix = nativeMatrix; } } [NullableContext(1)] public unsafe Matrix(Rectangle rect, params Point[] plgpts) { ArgumentNullException.ThrowIfNull(plgpts, "plgpts"); if (plgpts.Length != 3) throw Status.InvalidParameter.GetException(); fixed (Point* dstplg = plgpts) { global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCreateMatrix3I((Rect*)(&rect), (global::Windows.Win32.Graphics.GdiPlus.Point*)dstplg, &nativeMatrix).ThrowIfFailed(); NativeMatrix = nativeMatrix; } } public void Dispose() { DisposeInternal(); GC.SuppressFinalize(this); } private unsafe void DisposeInternal() { if (NativeMatrix != null) { if (Gdip.Initialized) PInvoke.GdipDeleteMatrix(NativeMatrix); NativeMatrix = null; } } ~Matrix() { DisposeInternal(); } [NullableContext(1)] public unsafe Matrix Clone() { global::Windows.Win32.Graphics.GdiPlus.Matrix* nativeMatrix = default(global::Windows.Win32.Graphics.GdiPlus.Matrix*); PInvoke.GdipCloneMatrix(NativeMatrix, &nativeMatrix).ThrowIfFailed(); GC.KeepAlive(this); return new Matrix(nativeMatrix); } internal unsafe void GetElements(Span<float> elements) { fixed (float* matrixOut = &elements.GetPinnableReference()) { PInvoke.GdipGetMatrixElements(NativeMatrix, matrixOut).ThrowIfFailed(); GC.KeepAlive(this); } } public unsafe void Reset() { PInvoke.GdipSetMatrixElements(NativeMatrix, 1, 0, 0, 1, 0, 0).ThrowIfFailed(); GC.KeepAlive(this); } [NullableContext(1)] public void Multiply(Matrix matrix) { Multiply(matrix, MatrixOrder.Prepend); } [NullableContext(1)] public unsafe void Multiply(Matrix matrix, MatrixOrder order) { ArgumentNullException.ThrowIfNull(matrix, "matrix"); if (matrix.NativeMatrix == NativeMatrix) throw new InvalidOperationException(System.SR.GdiplusObjectBusy); PInvoke.GdipMultiplyMatrix(NativeMatrix, matrix.NativeMatrix, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order).ThrowIfFailed(); GC.KeepAlive(this); GC.KeepAlive(matrix); } public void Translate(float offsetX, float offsetY) { Translate(offsetX, offsetY, MatrixOrder.Prepend); } public unsafe void Translate(float offsetX, float offsetY, MatrixOrder order) { PInvoke.GdipTranslateMatrix(NativeMatrix, offsetX, offsetY, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order).ThrowIfFailed(); GC.KeepAlive(this); } public void Scale(float scaleX, float scaleY) { Scale(scaleX, scaleY, MatrixOrder.Prepend); } public unsafe void Scale(float scaleX, float scaleY, MatrixOrder order) { PInvoke.GdipScaleMatrix(NativeMatrix, scaleX, scaleY, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order).ThrowIfFailed(); GC.KeepAlive(this); } public void Rotate(float angle) { Rotate(angle, MatrixOrder.Prepend); } public unsafe void Rotate(float angle, MatrixOrder order) { PInvoke.GdipRotateMatrix(NativeMatrix, angle, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order).ThrowIfFailed(); GC.KeepAlive(this); } public void RotateAt(float angle, PointF point) { RotateAt(angle, point, MatrixOrder.Prepend); } public unsafe void RotateAt(float angle, PointF point, MatrixOrder order) { Status status; if (order == MatrixOrder.Prepend) { status = PInvoke.GdipTranslateMatrix(NativeMatrix, point.X, point.Y, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); status |= PInvoke.GdipRotateMatrix(NativeMatrix, angle, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); status |= PInvoke.GdipTranslateMatrix(NativeMatrix, 0 - point.X, 0 - point.Y, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); } else { status = PInvoke.GdipTranslateMatrix(NativeMatrix, 0 - point.X, 0 - point.Y, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); status |= PInvoke.GdipRotateMatrix(NativeMatrix, angle, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); status |= PInvoke.GdipTranslateMatrix(NativeMatrix, point.X, point.Y, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order); } status.ThrowIfFailed(); GC.KeepAlive(this); } public unsafe void Shear(float shearX, float shearY) { PInvoke.GdipShearMatrix(NativeMatrix, shearX, shearY, global::Windows.Win32.Graphics.GdiPlus.MatrixOrder.MatrixOrderPrepend).ThrowIfFailed(); GC.KeepAlive(this); } public unsafe void Shear(float shearX, float shearY, MatrixOrder order) { PInvoke.GdipShearMatrix(NativeMatrix, shearX, shearY, (global::Windows.Win32.Graphics.GdiPlus.MatrixOrder)order).ThrowIfFailed(); GC.KeepAlive(this); } public unsafe void Invert() { PInvoke.GdipInvertMatrix(NativeMatrix).ThrowIfFailed(); GC.KeepAlive(this); } [NullableContext(1)] public void TransformPoints(params PointF[] pts) { ArgumentNullException.ThrowIfNull(pts, "pts"); TransformPoints(pts.AsSpan()); } private unsafe void TransformPoints([System.Runtime.CompilerServices.ParamCollection] [ScopedRef] ReadOnlySpan<PointF> pts) { fixed (PointF* pts2 = &pts.GetPinnableReference()) { PInvoke.GdipTransformMatrixPoints(NativeMatrix, (global::Windows.Win32.Graphics.GdiPlus.PointF*)pts2, pts.Length).ThrowIfFailed(); } GC.KeepAlive(this); } [NullableContext(1)] public void TransformPoints(params Point[] pts) { ArgumentNullException.ThrowIfNull(pts, "pts"); TransformPoints(pts.AsSpan()); } private unsafe void TransformPoints([System.Runtime.CompilerServices.ParamCollection] [ScopedRef] ReadOnlySpan<Point> pts) { fixed (Point* pts2 = &pts.GetPinnableReference()) { PInvoke.GdipTransformMatrixPointsI(NativeMatrix, (global::Windows.Win32.Graphics.GdiPlus.Point*)pts2, pts.Length).ThrowIfFailed(); } GC.KeepAlive(this); } [NullableContext(1)] public void TransformVectors(params PointF[] pts) { ArgumentNullException.ThrowIfNull(pts, "pts"); TransformVectors(pts.AsSpan()); } private unsafe void TransformVectors([System.Runtime.CompilerServices.ParamCollection] [ScopedRef] ReadOnlySpan<PointF> pts) { fixed (PointF* pts2 = &pts.GetPinnableReference()) { PInvoke.GdipVectorTransformMatrixPoints(NativeMatrix, (global::Windows.Win32.Graphics.GdiPlus.PointF*)pts2, pts.Length).ThrowIfFailed(); } GC.KeepAlive(this); } [NullableContext(1)] public void VectorTransformPoints(params Point[] pts) { TransformVectors(pts); } [NullableContext(1)] public void TransformVectors(params Point[] pts) { ArgumentNullException.ThrowIfNull(pts, "pts"); TransformVectors(pts.AsSpan()); } private unsafe void TransformVectors([System.Runtime.CompilerServices.ParamCollection] [ScopedRef] ReadOnlySpan<Point> pts) { fixed (Point* pts2 = &pts.GetPinnableReference()) { PInvoke.GdipVectorTransformMatrixPointsI(NativeMatrix, (global::Windows.Win32.Graphics.GdiPlus.Point*)pts2, pts.Length).ThrowIfFailed(); } GC.KeepAlive(this); } [NullableContext(2)] public unsafe override bool Equals([NotNullWhen(true)] object obj) { Matrix matrix = obj as Matrix; if (matrix == null) return false; BOOL value = default(BOOL); PInvoke.GdipIsMatrixEqual(NativeMatrix, matrix.NativeMatrix, &value).ThrowIfFailed(); GC.KeepAlive(this); GC.KeepAlive(matrix); return value; } public override int GetHashCode() { return base.GetHashCode(); } } }