[ImageIO] Update bindings for Xcode11 (#8376)

* initial imagio bindings + test project

* remove sample files, update xtro

* clean up

* add new line at eof

* even more cleanup...

* update based on PR feedback

* reformat according to coding standards

* fix all feedback except monotouch tests

* add monotouch-test files

* fix test feedback

* fix PR feedback

* fix timeout in tests, add asserts for status, update return value for APi to CGImageAnimationStatus enum

* fix == asserts

* respond to more pr feedback

* add StrongDictionary, remove Partial

* NSNumber -> nuint for NSUInteger

* add smaller gif

* remove hack.gif from project

* add gif to csproj
This commit is contained in:
Whitney Schmidt 2020-04-28 17:02:36 -04:00 коммит произвёл GitHub
Родитель 95d71c8ee1
Коммит ecf295f4db
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 352 добавлений и 39 удалений

Просмотреть файл

@ -0,0 +1,141 @@
//
// ImageIO - CGImageAnimation.cs
//
// Authors:
// Whitney Schmidt <whschm@microsoft.com>
//
// Copyright 2020, Microsoft Corp.
//
using System;
using System.Runtime.InteropServices;
using CoreFoundation;
using CoreGraphics;
using Foundation;
using ObjCRuntime;
namespace ImageIO
{
public static class CGImageAnimation
{
public delegate void CGImageSourceAnimationHandler (nint index, CGImage image, out bool stop);
[Introduced (PlatformName.MacOSX, 10, 15, PlatformArchitecture.All)]
[Introduced (PlatformName.iOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.TvOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.WatchOS, 6, 0, PlatformArchitecture.All)]
[DllImport (Constants.ImageIOLibrary)]
static extern /* OSStatus */ CGImageAnimationStatus CGAnimateImageAtURLWithBlock ( /* CFURLRef */ IntPtr url, /* CFDictionaryRef _iio_Nullable */ IntPtr options, /* CGImageSourceAnimationHandler */ ref BlockLiteral block);
[Introduced (PlatformName.MacOSX, 10, 15, PlatformArchitecture.All)]
[Introduced (PlatformName.iOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.TvOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.WatchOS, 6, 0, PlatformArchitecture.All)]
[DllImport (Constants.ImageIOLibrary)]
static extern /* OSStatus */ CGImageAnimationStatus CGAnimateImageDataWithBlock ( /* CFDataRef _Nonnull */ IntPtr data, /* CFDictionaryRef _Nullable */ IntPtr options, /* CGImageSourceAnimationHandler _Nonnull */ ref BlockLiteral block);
[Introduced (PlatformName.MacOSX, 10, 15, PlatformArchitecture.All)]
[Introduced (PlatformName.iOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.TvOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.WatchOS, 6, 0, PlatformArchitecture.All)]
[BindingImpl (BindingImplOptions.Optimizable)]
public static CGImageAnimationStatus AnimateImage (NSUrl url, CGImageAnimationOptions options, [BlockProxy (typeof (NIDCGImageSourceAnimationBlock))] CGImageSourceAnimationHandler handler)
{
#if IOS && ARCH_32
throw new PlatformNotSupportedException ("This API is not supported on this version of iOS");
#else
if (url == null)
throw new ArgumentNullException (nameof (url));
if (handler == null)
throw new ArgumentNullException (nameof (handler));
var block = new BlockLiteral ();
block.SetupBlockUnsafe (SDCGImageSourceAnimationBlock.Handler, handler);
try {
return CGAnimateImageAtURLWithBlock (url.Handle, options.GetHandle (), ref block);
} finally {
block.CleanupBlock ();
}
#endif
}
[Introduced (PlatformName.MacOSX, 10, 15, PlatformArchitecture.All)]
[Introduced (PlatformName.iOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.TvOS, 13, 0, PlatformArchitecture.All)]
[Introduced (PlatformName.WatchOS, 6, 0, PlatformArchitecture.All)]
[BindingImpl (BindingImplOptions.Optimizable)]
public static CGImageAnimationStatus AnimateImage (NSData data, CGImageAnimationOptions options, [BlockProxy (typeof (NIDCGImageSourceAnimationBlock))] CGImageSourceAnimationHandler handler)
{
#if IOS && ARCH_32
throw new PlatformNotSupportedException ("This API is not supported on this version of iOS");
#else
if (data == null)
throw new ArgumentNullException (nameof (data));
if (handler == null)
throw new ArgumentNullException (nameof (handler));
var block = new BlockLiteral ();
block.SetupBlockUnsafe (SDCGImageSourceAnimationBlock.Handler, handler);
try {
return CGAnimateImageDataWithBlock (data.Handle, options.GetHandle (), ref block);
} finally {
block.CleanupBlock ();
}
#endif
}
//
// This class bridges native block invocations that call into C#
//
static internal class SDCGImageSourceAnimationBlock
{
static internal readonly DCGImageSourceAnimationBlock Handler = Invoke;
[MonoPInvokeCallback (typeof (DCGImageSourceAnimationBlock))]
static void Invoke (IntPtr block, nint index, IntPtr image, [MarshalAs (UnmanagedType.I1)] out bool stop)
{
var del = BlockLiteral.GetTarget<CGImageSourceAnimationHandler> (block);
if (del != null)
del (index, new CoreGraphics.CGImage (image), out stop);
else
stop = false;
}
} /* class SDCGImageSourceAnimationBlock */
internal sealed class NIDCGImageSourceAnimationBlock : TrampolineBlockBase
{
DCGImageSourceAnimationBlock invoker;
[BindingImpl (BindingImplOptions.Optimizable)]
public unsafe NIDCGImageSourceAnimationBlock (BlockLiteral * block) : base (block)
{
invoker = block->GetDelegateForBlock<DCGImageSourceAnimationBlock> ();
}
[Preserve (Conditional = true)]
[BindingImpl (BindingImplOptions.Optimizable)]
public unsafe static CGImageSourceAnimationHandler Create (IntPtr block)
{
if (block == IntPtr.Zero)
return null;
var del = (CGImageSourceAnimationHandler) GetExistingManagedDelegate (block);
return del ?? new NIDCGImageSourceAnimationBlock ( (BlockLiteral *) block).Invoke;
}
[BindingImpl (BindingImplOptions.Optimizable)]
void Invoke (nint index, CGImage image, out bool stop)
{
invoker (BlockPointer, index, image.GetHandle (), out stop);
}
} /* class NIDCGImageSourceAnimationBlock */
[UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)]
[UserDelegateType (typeof (CGImageSourceAnimationHandler))]
internal delegate void DCGImageSourceAnimationBlock (IntPtr block, nint index, IntPtr imageHandle, [MarshalAs (UnmanagedType.I1)] out bool stop);
}
}

Просмотреть файл

@ -5,6 +5,7 @@
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2013-2016, Xamarin Inc.
// Copyright 2020, Microsoft Corp.
//
using System;
@ -60,4 +61,15 @@ namespace ImageIO {
Average = 0x40,
Paeth = 0x80
}
[Mac (10, 15), iOS (13, 0), TV (13, 0), Watch (6, 0)]
public enum CGImageAnimationStatus
{
Ok = 0,
ParameterError = -22140,
CorruptInputImage = -22141,
UnsupportedFormat = -22142,
IncompleteInputImage = -22143,
AllocationFailure = -22144,
}
}

Просмотреть файл

@ -927,6 +927,7 @@ IMAGEIO_CORE_SOURCES = \
ImageIO/CGImageSource.cs \
IMAGEIO_SOURCES = \
ImageIO/CGImageAnimation.cs \
ImageIO/CGImageDestination.cs \
ImageIO/CGImageMetadata.cs \
ImageIO/CGImageMetadataTag.cs \

Просмотреть файл

@ -250,6 +250,18 @@ namespace ImageIO {
[Field ("kCGImagePropertyExifGamma")]
NSString ExifGamma { get; }
[Mac (10, 15, 1), iOS (13, 1), TV (13, 1), Watch (6, 1)]
[Field ("kCGImagePropertyExifCompositeImage")]
NSString ExifCompositeImage { get; }
[Mac (10, 15, 1), iOS (13, 1), TV (13, 1), Watch (6, 1)]
[Field ("kCGImagePropertyExifSourceImageNumberOfCompositeImage")]
NSString ExifSourceImageNumberOfCompositeImage { get; }
[Mac (10, 15, 1), iOS (13, 1), TV (13, 1), Watch (6, 1)]
[Field ("kCGImagePropertyExifSourceExposureTimesOfCompositeImage")]
NSString ExifSourceExposureTimesOfCompositeImage { get; }
// misdocumented (first 4.3, then 5.0) but the constants were not present until 6.x
[Field ("kCGImagePropertyExifCameraOwnerName")]
@ -2356,4 +2368,28 @@ namespace ImageIO {
NSData Data { get; set; }
NSDictionary DataDescription { get; set; }
}
[Mac (10, 15), iOS (13, 0), TV (13, 0), Watch (6, 0)]
[Static]
[Internal]
interface CGImageAnimationOptionsKeys {
[Field ("kCGImageAnimationDelayTime")]
NSString DelayTimeKey { get; }
[Field ("kCGImageAnimationLoopCount")]
NSString LoopCountKey { get; }
[Field ("kCGImageAnimationStartIndex")]
NSString StartIndexKey { get; }
}
[Mac (10, 15), iOS (13, 0), TV (13, 0), Watch (6, 0)]
[StrongDictionary ("CGImageAnimationOptionsKeys")]
interface CGImageAnimationOptions {
double DelayTime { get; set; }
nuint LoopCount { get; set; }
nuint StartIndex { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,161 @@
//
// Unit tests for CGImageAnimation
//
// Authors:
// Whitney Schmidt <whschm@microsoft.com>
//
// Copyright 2020 Microsoft Corp. All rights reserved.
//
using System;
using System.IO;
using Foundation;
using System.Threading.Tasks;
#if MONOMAC
using AppKit;
#else
using UIKit;
#endif
using CoreGraphics;
using ImageIO;
using NUnit.Framework;
namespace MonoTouchFixtures.ImageIO {
[TestFixture]
[Preserve (AllMembers = true)]
public class CGImageAnimationTest {
NSUrl imageUrl;
NSData imageData;
TaskCompletionSource<bool> tcs;
int testValue;
CGImageAnimationStatus status;
void MyHandlerSetValueZero (nint index, CGImage image, out bool stop)
{
stop = true;
testValue = 0;
tcs.TrySetResult (true);
}
void MyHandlerSetValueOne (nint index, CGImage image, out bool stop)
{
stop = true;
testValue = 1;
tcs.TrySetResult (true);
}
[TestFixtureSetUp]
public void Init ()
{
TestRuntime.AssertXcodeVersion (11, 4);
imageUrl = NSBundle.MainBundle.GetUrlForResource ("square", "gif");
imageData = NSData.FromUrl (imageUrl);
}
[TestFixtureTearDown]
public void Cleanup ()
{
imageUrl?.Dispose ();
imageData?.Dispose ();
}
[SetUp]
public void InitPerTest ()
{
testValue = -1;
}
[TearDown]
public void Dispose ()
{
testValue = -1;
}
void CallAnimateImage (bool useUrl, CGImageAnimation.CGImageSourceAnimationHandler handler)
{
tcs = new TaskCompletionSource<bool> ();
status = (CGImageAnimationStatus) 1; /* CGImageAnimationStatus.Ok == 0 */
bool done = false;
TestRuntime.RunAsync (TimeSpan.FromSeconds (30), async () => {
if (useUrl) {
status = CGImageAnimation.AnimateImage (imageUrl, null, handler);
} else {
status = CGImageAnimation.AnimateImage (imageData, null, handler);
}
await tcs.Task;
done = true;
},
() => done);
tcs = null;
}
[Test]
public void AnimateImageWithUrl ()
{
CallAnimateImage ( /* useUrl */ true, MyHandlerSetValueZero);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: handler called with url");
Assert.AreEqual (0, testValue, "handler called with url");
}
[Test]
public void AnimateImageWithData ()
{
CallAnimateImage ( /* useUrl */ false, MyHandlerSetValueZero);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: handler called with data");
Assert.AreEqual (0, testValue, "handler called with data");
}
[Test]
public void AnimateImageWithUrlChangeHandler ()
{
CallAnimateImage ( /* useUrl */ true, MyHandlerSetValueZero);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: first handler called with url");
Assert.AreEqual (0, testValue, "first handler called with url" );
CallAnimateImage ( /* useUrl */ true, MyHandlerSetValueOne);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: second handler called with url");
Assert.AreEqual (1, testValue, "second handler called with url");
}
[Test]
public void AnimateImageWithDataChangeHandler ()
{
CallAnimateImage ( /* useUrl */ false, MyHandlerSetValueZero);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: first handler called with data");
Assert.AreEqual (0, testValue, "first handler called with data");
CallAnimateImage ( /* useUrl */ false, MyHandlerSetValueOne);
Assert.AreEqual (CGImageAnimationStatus.Ok, status, "status ok: second handler called with data");
Assert.AreEqual (1, testValue, "second handler called with data");
}
[Test]
public void AnimateImageWithUrlNullUrl ()
{
Assert.Throws<ArgumentNullException> (() => CGImageAnimation.AnimateImage ( (NSUrl) null, null, MyHandlerSetValueZero), "null url");
}
[Test]
public void AnimateImageWithUrlNullHandler ()
{
Assert.Throws<ArgumentNullException> (() => CGImageAnimation.AnimateImage (imageUrl, null, /* CGImageSourceAnimationHandler */ null), "null handler called with url");
}
[Test]
public void AnimateImageWithDataNullData ()
{
Assert.Throws<ArgumentNullException> (() => CGImageAnimation.AnimateImage ( (NSData) null, null, MyHandlerSetValueZero), "null data");
}
[Test]
public void AnimateImageWithDataNullHandler ()
{
Assert.Throws<ArgumentNullException> (() => CGImageAnimation.AnimateImage (imageData, null, /* CGImageSourceAnimationHandler */ null), "null handler called with data");
}
}
}

Двоичные данные
tests/monotouch-test/Resources/square.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Просмотреть файл

@ -331,6 +331,7 @@
<BundleResource Include="compressed_lzma" />
<BundleResource Include="compressed_zip" />
<BundleResource Include="example.pac" />
<BundleResource Include="Resources\square.gif" />
</ItemGroup>
<ItemGroup>
<Metal Include="Resources\metal-sample.metal" Condition="'$(Platform)' != 'iPhoneSimulator' " />

Просмотреть файл

@ -1,10 +0,0 @@
!missing-enum! CGImageAnimationStatus not bound
!missing-field! kCGImageAnimationDelayTime not bound
!missing-field! kCGImageAnimationLoopCount not bound
!missing-field! kCGImageAnimationStartIndex not bound
!missing-pinvoke! CGAnimateImageAtURLWithBlock is not bound
!missing-pinvoke! CGAnimateImageDataWithBlock is not bound
## appended from unclassified file
!missing-field! kCGImagePropertyExifCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceExposureTimesOfCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceImageNumberOfCompositeImage not bound

Просмотреть файл

@ -1,9 +0,0 @@
!missing-enum! CGImageAnimationStatus not bound
!missing-field! kCGImageAnimationDelayTime not bound
!missing-field! kCGImageAnimationLoopCount not bound
!missing-field! kCGImageAnimationStartIndex not bound
!missing-field! kCGImagePropertyExifCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceExposureTimesOfCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceImageNumberOfCompositeImage not bound
!missing-pinvoke! CGAnimateImageAtURLWithBlock is not bound
!missing-pinvoke! CGAnimateImageDataWithBlock is not bound

Просмотреть файл

@ -1,10 +0,0 @@
!missing-enum! CGImageAnimationStatus not bound
!missing-field! kCGImageAnimationDelayTime not bound
!missing-field! kCGImageAnimationLoopCount not bound
!missing-field! kCGImageAnimationStartIndex not bound
!missing-pinvoke! CGAnimateImageAtURLWithBlock is not bound
!missing-pinvoke! CGAnimateImageDataWithBlock is not bound
## appended from unclassified file
!missing-field! kCGImagePropertyExifCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceExposureTimesOfCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceImageNumberOfCompositeImage not bound

Просмотреть файл

@ -1,10 +0,0 @@
!missing-enum! CGImageAnimationStatus not bound
!missing-field! kCGImageAnimationDelayTime not bound
!missing-field! kCGImageAnimationLoopCount not bound
!missing-field! kCGImageAnimationStartIndex not bound
!missing-pinvoke! CGAnimateImageAtURLWithBlock is not bound
!missing-pinvoke! CGAnimateImageDataWithBlock is not bound
## appended from unclassified file
!missing-field! kCGImagePropertyExifCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceExposureTimesOfCompositeImage not bound
!missing-field! kCGImagePropertyExifSourceImageNumberOfCompositeImage not bound