Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
170 changes: 170 additions & 0 deletions src/CoreGraphics/CGBitmapContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

Expand Down Expand Up @@ -225,6 +226,175 @@ public CGBitmapFlags BitmapInfo {
// do not return an invalid instance (null handle) if something went wrong
return h == IntPtr.Zero ? null : new CGImage (h, true);
}

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern unsafe IntPtr /* CGContextRef */ CGBitmapContextCreateAdaptive (
nuint /* size_t */ width,
nuint /* size_t */ height,
IntPtr /* CFDictionaryRef __nullable */ auxiliaryInfo,
BlockLiteral* /* (^__nullable onResolve)(const CGContentInfo* __nonnull, CGBitmapParameters* __nonnull) */ onResolve,
BlockLiteral* /* (^__nullable onAllocate)(const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onAllocate,
BlockLiteral* /* (^__nullable onFree)(CGRenderingBufferProviderRef __nonnull, const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onFree,
BlockLiteral* /* (^__nullable onError)(CFErrorRef __nonnull, const CGContentInfo* __nonnull, const CGBitmapParameters* __nonnull) */ onError
);

/// <summary>Create a bitmap context designed to choose the optimal bit depth, colorspace and EDR target headroom.</summary>
/// <param name="width">The width of the new <see cref="CGBitmapContext" />.</param>
/// <param name="height">The height of the new <see cref="CGBitmapContext" />.</param>
/// <param name="auxiliaryInfo">Any additional information for the creation of the new <see cref="CGBitmapContext" />.</param>
/// <param name="onResolve">A callback to modify the <see cref="CGBitmapParameters" /> used to create the new <see cref="CGBitmapContext" />.</param>
/// <param name="onAllocate">A callback to allocate memory for the new <see cref="CGBitmapContext" />.</param>
/// <param name="onFree">A callback to free any allocated memory for the new <see cref="CGBitmapContext" />.</param>
/// <param name="onError">A callback that is called in case of any errors.</param>
/// <returns> A new <see cref="CGBitmapContext" /> if successful, <see langword="null" /> otherwise.</returns>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[BindingImpl (BindingImplOptions.Optimizable)]
public unsafe static CGBitmapContext? Create (nuint width, nuint height, NSDictionary? auxiliaryInfo, OnResolveCallback? onResolve, OnAllocateCallback? onAllocate, OnFreeCallback? onFree, OnErrorCallback? onError)
{
delegate* unmanaged<IntPtr, CGContentInfo*, CGBitmapParameters*, byte> onResolveTrampoline = &CGBitmapContextCreateAdaptive_OnResolve;
using var onResolveBlock = onResolve is null ? default (BlockLiteral) : new BlockLiteral (onResolveTrampoline, onResolve, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnResolve));

delegate* unmanaged<IntPtr, CGContentInfo*, CGBitmapParameters*, IntPtr> onAllocateTrampoline = &CGBitmapContextCreateAdaptive_OnAllocate;
using var onAllocateBlock = onAllocate is null ? default (BlockLiteral) : new BlockLiteral (onAllocateTrampoline, onAllocate, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnAllocate));

delegate* unmanaged<IntPtr, IntPtr, CGContentInfo*, CGBitmapParameters*, void> onFreeTrampoline = &CGBitmapContextCreateAdaptive_OnFree;
using var onFreeBlock = onFree is null ? default (BlockLiteral) : new BlockLiteral (onFreeTrampoline, onFree, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnFree));

delegate* unmanaged<IntPtr, IntPtr, CGContentInfo*, CGBitmapParameters*, void> onErrorTrampoline = &CGBitmapContextCreateAdaptive_OnError;
using var onErrorBlock = onError is null ? default (BlockLiteral) : new BlockLiteral (onErrorTrampoline, onError, typeof (CGBitmapContext), nameof (CGBitmapContextCreateAdaptive_OnError));

var rv = CGBitmapContextCreateAdaptive (
width, height,
auxiliaryInfo.GetHandle (),
onResolve is null ? null : &onResolveBlock,
onAllocate is null ? null : &onAllocateBlock,
onFree is null ? null : &onFreeBlock,
onError is null ? null : &onErrorBlock
);

GC.KeepAlive (auxiliaryInfo);

if (rv == IntPtr.Zero)
return null;

return new CGBitmapContext (rv, true);
}

/// <summary>Create a bitmap context designed to choose the optimal bit depth, colorspace and EDR target headroom.</summary>
/// <param name="width">The width of the new <see cref="CGBitmapContext" />.</param>
/// <param name="height">The height of the new <see cref="CGBitmapContext" />.</param>
/// <param name="auxiliaryInfo">Any additional information for the creation of the new <see cref="CGBitmapContext" />.</param>
/// <param name="onResolve">A callback to modify the <see cref="CGBitmapParameters" /> used to create the new <see cref="CGBitmapContext" />.</param>
/// <param name="onAllocate">A callback to allocate memory for the new <see cref="CGBitmapContext" />.</param>
/// <param name="onFree">A callback to free any allocated memory for the new <see cref="CGBitmapContext" />.</param>
/// <param name="onError">A callback that is called in case of any errors.</param>
/// <returns> A new <see cref="CGBitmapContext" /> if successful, <see langword="null" /> otherwise.</returns>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
public unsafe static CGBitmapContext? Create (nuint width, nuint height, CGAdaptiveOptions? auxiliaryInfo, OnResolveCallback? onResolve, OnAllocateCallback? onAllocate, OnFreeCallback? onFree, OnErrorCallback? onError)
{
return Create (width, height, auxiliaryInfo?.Dictionary, onResolve, onAllocate, onFree, onError);
}

public delegate bool OnResolveCallback (ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters);

[UnmanagedCallersOnly]
unsafe static byte CGBitmapContextCreateAdaptive_OnResolve (IntPtr block, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters)
{
var del = BlockLiteral.GetTarget<OnResolveCallback> (block);
if (del is not null) {
var rv = del (ref Unsafe.AsRef<CGContentInfo> (contentInfo), ref Unsafe.AsRef<CGBitmapParameters> (bitmapParameters));
return rv.AsByte ();
}
return 0;
}

public delegate CGRenderingBufferProvider /* CGRenderingBufferProviderRef */ OnAllocateCallback (ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters);

[UnmanagedCallersOnly]
unsafe static IntPtr CGBitmapContextCreateAdaptive_OnAllocate (IntPtr block, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters)
{
var del = BlockLiteral.GetTarget<OnAllocateCallback> (block);
if (del is not null) {
var rv = del (ref Unsafe.AsRef<CGContentInfo> (contentInfo), ref Unsafe.AsRef<CGBitmapParameters> (bitmapParameters));
return Runtime.RetainAndAutoreleaseHandle (rv);
}
return IntPtr.Zero;
}

public delegate void OnFreeCallback (CGRenderingBufferProvider /* CGRenderingBufferProviderRef */ renderingBufferProvider, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters);

[UnmanagedCallersOnly]
unsafe static void CGBitmapContextCreateAdaptive_OnFree (IntPtr block, IntPtr /* CGRenderingBufferProviderRef */ bufferingProviderRef, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters)
{
var del = BlockLiteral.GetTarget<OnFreeCallback> (block);
if (del is not null) {
using var renderingBufferProvider = new CGRenderingBufferProvider (bufferingProviderRef, false);
del (renderingBufferProvider, ref Unsafe.AsRef<CGContentInfo> (contentInfo), ref Unsafe.AsRef<CGBitmapParameters> (bitmapParameters));
}
}

public delegate void OnErrorCallback (NSError error, ref CGContentInfo contentInfo, ref CGBitmapParameters bitmapParameters);

[UnmanagedCallersOnly]
unsafe static void CGBitmapContextCreateAdaptive_OnError (IntPtr block, IntPtr errorHandle, CGContentInfo* contentInfo, CGBitmapParameters* bitmapParameters)
{
var del = BlockLiteral.GetTarget<OnErrorCallback> (block);
if (del is not null) {
var error = Runtime.GetNSObject<NSError> (errorHandle, false)!;
del (error, ref Unsafe.AsRef<CGContentInfo> (contentInfo), ref Unsafe.AsRef<CGBitmapParameters> (bitmapParameters));
}
}

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern CGContentToneMappingInfo CGContextGetContentToneMappingInfo (IntPtr /* CGContextRef __nonnull */ context);

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern void CGContextSetContentToneMappingInfo (IntPtr /* CGContextRef __nonnull */ context, CGContentToneMappingInfo info);

/// <summary>Get or set the content tone mapping info.</summary>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
public CGContentToneMappingInfo ContentToneMappingInfo {
get => CGContextGetContentToneMappingInfo (GetCheckedHandle ());
set => CGContextSetContentToneMappingInfo (GetCheckedHandle (), value);
}

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern void CGContextSynchronizeAttributes (IntPtr /* CGContextRef */ context);

/// <summary>Synchronize destination attributes.</summary>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
public void SynchronizeAttributes ()
{
CGContextSynchronizeAttributes (GetCheckedHandle ());
}
#endif // !COREBUILD
}
}
38 changes: 38 additions & 0 deletions src/CoreGraphics/CGBitmapInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace CoreGraphics {
public static class CGBitmapInfoExtensions {
/// <summary>Get the alpha info flags for this <see cref="CGBitmapInfo" /> value.</summary>
/// <param name="value">The <see cref="CGBitmapInfo" /> value with the flags to get.</param>
/// <returns>The alpha info flags for this <see cref="CGBitmapInfo" /> value.</returns>
public static CGImageAlphaInfo GetAlphaInfo (this CGBitmapInfo value)
{
return (CGImageAlphaInfo) (value & CGBitmapInfo.AlphaInfoMask);
}

/// <summary>Get the component info flags for this <see cref="CGBitmapInfo" /> value.</summary>
/// <param name="value">The <see cref="CGBitmapInfo" /> value with the flags to get.</param>
/// <returns>The component info flags for this <see cref="CGBitmapInfo" /> value.</returns>
public static CGImageComponentInfo GetComponentInfo (this CGBitmapInfo value)
{
return (CGImageComponentInfo) (value & CGBitmapInfo.ComponentInfoMask);
}

/// <summary>Get the byte order info flags for this <see cref="CGBitmapInfo" /> value.</summary>
/// <param name="value">The <see cref="CGBitmapInfo" /> value with the flags to get.</param>
/// <returns>The byte order info flags for this <see cref="CGBitmapInfo" /> value.</returns>
public static CGImageByteOrderInfo GetByteOrderInfo (this CGBitmapInfo value)
{
return (CGImageByteOrderInfo) (value & CGBitmapInfo.ByteOrderInfoMask);
}

/// <summary>Get the pixel format info flags for this <see cref="CGBitmapInfo" /> value.</summary>
/// <param name="value">The <see cref="CGBitmapInfo" /> value with the flags to get.</param>
/// <returns>The pixel formatinfo flags for this <see cref="CGBitmapInfo" /> value.</returns>
public static CGImagePixelFormatInfo GetPixelFormatInfo (this CGBitmapInfo value)
{
return (CGImagePixelFormatInfo) (value & CGBitmapInfo.PixelFormatInfoMask);
}
}
}
112 changes: 112 additions & 0 deletions src/CoreGraphics/CGBitmapParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#nullable enable

using CoreFoundation;

namespace CoreGraphics {
/// <summary>This struct contains values used when creating an adaptive bitmap context.</summary>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[SupportedOSPlatform ("tvos26.0")]
[StructLayout (LayoutKind.Sequential)]
public struct CGBitmapParameters {
nuint width;
nuint height;
nuint bytesPerPixel;
nuint alignedBytesPerRow; /* Rounded up to an appropriate value for bitmap data */
CGComponent component;
CGBitmapLayout layout;
CGImagePixelFormatInfo format;
IntPtr /* CGColorSpaceRef */ colorSpace;
byte /* bool */ hasPremultipliedAlpha;
nint /* CFByteOrder */ byteOrder;
float edrTargetHeadroom;

/// <summary>The width of the new <see cref="CGBitmapContext" />.</summary>
public nuint Width {
get => width;
set => width = value;
}

/// <summary>The height of the new <see cref="CGBitmapContext" />.</summary>
public nuint Height {
get => height;
set => height = value;
}

/// <summary>The number of bytes per pixel for the new <see cref="CGBitmapContext" />.</summary>
public nuint BytesPerPixel {
get => bytesPerPixel;
set => bytesPerPixel = value;
}

/// <summary>The number of aligned bytes per row for the new <see cref="CGBitmapContext" />.</summary>
public nuint AlignedBytesPerRow {
get => alignedBytesPerRow;
set => alignedBytesPerRow = value;
}

/// <summary>The <see cref="CGComponent" /> value for the new <see cref="CGBitmapContext" />.</summary>
public CGComponent Component {
get => component;
set => component = value;
}

/// <summary>The <see cref="CGBitmapLayout" /> value for the new <see cref="CGBitmapContext" />.</summary>
public CGBitmapLayout Layout {
get => layout;
set => layout = value;
}

/// <summary>The pixel format for the new <see cref="CGBitmapContext" />.</summary>
public CGImagePixelFormatInfo Format {
get => format;
set => format = value;
}

/// <summary>The handle for the colorspace of the new <see cref="CGBitmapContext" />.</summary>
public IntPtr ColorSpaceHandle {
get => colorSpace;
set => colorSpace = value;
}

/// <summary>The <see cref="CGColorSpace" /> for the new <see cref="CGBitmapContext" />.</summary>
/// <remarks>When setting this value, the calling code must keep a reference to the <see cref="CGColorSpace" /> instance, because this struct does not increment the retainCount of it to prevent the GC from collecting the instance.</remarks>
public CGColorSpace? ColorSpace {
get => Runtime.GetINativeObject<CGColorSpace> (colorSpace, false);
set {
// this is unsafe: the calling code must keep the managed CGColorSpace insatnce around somehow.
#pragma warning disable RBI0014
colorSpace = value!.GetNonNullHandle (nameof (value));
#pragma warning restore RBI0014
}
}

/// <summary>Whether the new <see cref="CGBitmapContext" /> has premultiplied alpha values.</summary>
public bool HasPremultipliedAlpha {
get => hasPremultipliedAlpha != 0;
set => hasPremultipliedAlpha = value.AsByte ();
}

/// <summary>The byte order for the new <see cref="CGBitmapContext" />.</summary>
public CFByteOrder ByteOrder {
get => (CFByteOrder) byteOrder;
set => byteOrder = (nint) (long) value;
}

/// <summary>The EDR target headroom for the new <see cref="CGBitmapContext" />.</summary>
public float EdrTargetHeadroom {
get => edrTargetHeadroom;
set => edrTargetHeadroom = value;
}

/// <summary>Returns a string representation of this <see cref="CGBitmapParameters" />.</summary>
public override string ToString ()
{
return $"CGBitmapParameters[Width={Width};Height={Height};BytesPerPixel={BytesPerPixel};AlignedBytesPerRow={AlignedBytesPerRow};Component={Component};Layout={Layout};Format={Format};ColorSpaceHandle={ColorSpaceHandle};ColorSpace={ColorSpace};HasPremultipliedAlpha={HasPremultipliedAlpha};ByteOrder={ByteOrder};EdrTargetHeadroom={EdrTargetHeadroom}]";
}
}
}
42 changes: 42 additions & 0 deletions src/CoreGraphics/CGColor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,48 @@ public CGPattern? Pattern {
[SupportedOSPlatform ("maccatalyst")]
public string? AXName => CFString.FromHandle (AXNameFromColor (Handle));

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern IntPtr /* CGColorRef gc_nullable */ CGColorCreateWithContentHeadroom (float headroom, IntPtr /* CGColorSpaceRef gc_nullable */ space, nfloat red, nfloat green, nfloat blue, nfloat alpha);

/// <summary>Create a <see cref="CGColor" /> with the specified content headroom, colorspace and color and alpha values.</summary>
/// <param name="headroom">The content headroom for the new <see cref="CGColor" />.</param>
/// <param name="colorSpace">The colorspace for the new <see cref="CGColor" />.</param>
/// <param name="red">The red color value for the new <see cref="CGColor" />.</param>
/// <param name="green">The green color value for the new <see cref="CGColor" />.</param>
/// <param name="blue">The blue color value for the new <see cref="CGColor" />.</param>
/// <param name="alpha">The alpha value for the new <see cref="CGColor" />.</param>
/// <returns>A new <see cref="CGColor" /> instance if successful, <see langword="null" /> otherwise.</returns>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
public static CGColor? CreateWithContentHeadroom (float headroom, CGColorSpace? colorSpace, nfloat red, nfloat green, nfloat blue, nfloat alpha)
{
var h = CGColorCreateWithContentHeadroom (headroom, colorSpace.GetHandle (), red, green, blue, alpha);
GC.KeepAlive (colorSpace);
return h == IntPtr.Zero ? null : new CGColor (h, owns: true);
}

[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
[DllImport (Constants.CoreGraphicsLibrary)]
static extern float CGColorGetContentHeadroom (IntPtr /* CGColorRef cg_nullable */ color);

/// <summary>Get the content headroom for the color.</summary>
[SupportedOSPlatform ("ios26.0")]
[SupportedOSPlatform ("tvos26.0")]
[SupportedOSPlatform ("maccatalyst26.0")]
[SupportedOSPlatform ("macos26.0")]
public float ContentHeadroom {
get => CGColorGetContentHeadroom (GetCheckedHandle ());
}


#endif // !COREBUILD
}
Expand Down
Loading
Loading