99//
1010
1111#if SWT_TARGET_OS_APPLE && canImport(CoreGraphics)
12- public import CoreGraphics
13- private import ImageIO
12+ package import CoreGraphics
13+ package import ImageIO
14+ private import UniformTypeIdentifiers
1415
1516/// A protocol describing images that can be converted to instances of
16- /// [`Attachment`](https://developer.apple.com/documentation/testing/attachment).
17+ /// [`Attachment`](https://developer.apple.com/documentation/testing/attachment)
18+ /// and which can be represented as instances of [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage).
1719///
18- /// Instances of types conforming to this protocol do not themselves conform to
19- /// [`Attachable`](https://developer.apple.com/documentation/testing/attachable).
20- /// Instead, the testing library provides additional initializers on [`Attachment`](https://developer.apple.com/documentation/testing/attachment)
21- /// that take instances of such types and handle converting them to image data when needed.
22- ///
23- /// You can attach instances of the following system-provided image types to a
24- /// test:
25- ///
26- /// | Platform | Supported Types |
27- /// |-|-|
28- /// | macOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`NSImage`](https://developer.apple.com/documentation/appkit/nsimage) |
29- /// | iOS, watchOS, tvOS, and visionOS | [`CGImage`](https://developer.apple.com/documentation/coregraphics/cgimage), [`CIImage`](https://developer.apple.com/documentation/coreimage/ciimage), [`UIImage`](https://developer.apple.com/documentation/uikit/uiimage) |
30- /// | Windows | [`HBITMAP`](https://learn.microsoft.com/en-us/windows/win32/gdi/bitmaps), [`HICON`](https://learn.microsoft.com/en-us/windows/win32/menurc/icons), [`IWICBitmapSource`](https://learn.microsoft.com/en-us/windows/win32/api/wincodec/nn-wincodec-iwicbitmapsource) (including its subclasses declared by Windows Imaging Component) |
31- ///
32- /// You do not generally need to add your own conformances to this protocol. If
33- /// you have an image in another format that needs to be attached to a test,
34- /// first convert it to an instance of one of the types above.
35- ///
36- /// @Metadata {
37- /// @Available(Swift, introduced: 6.3)
38- /// }
20+ /// This protocol is not part of the public interface of the testing library. It
21+ /// encapsulates Apple-specific logic for image attachments.
3922@available ( _uttypesAPI, * )
40- public protocol AttachableAsCGImage : _AttachableAsImage , SendableMetatype {
23+ package protocol AttachableAsCGImage : AttachableAsImage , SendableMetatype {
4124 /// An instance of `CGImage` representing this image.
4225 ///
4326 /// - Throws: Any error that prevents the creation of an image.
44- ///
45- /// @Metadata {
46- /// @Available(Swift, introduced: 6.3)
47- /// }
4827 var attachableCGImage : CGImage { get throws }
4928
5029 /// The orientation of the image.
@@ -53,38 +32,64 @@ public protocol AttachableAsCGImage: _AttachableAsImage, SendableMetatype {
5332 /// `CGImagePropertyOrientation`. The default value of this property is
5433 /// `.up`.
5534 ///
56- /// This property is not part of the public interface of the testing
57- /// library. It may be removed in a future update.
58- var _attachmentOrientation : UInt32 { get }
35+ /// This property is not part of the public interface of the testing library.
36+ /// It may be removed in a future update.
37+ var attachmentOrientation : CGImagePropertyOrientation { get }
5938
6039 /// The scale factor of the image.
6140 ///
6241 /// The value of this property is typically greater than `1.0` when an image
6342 /// originates from a Retina Display screenshot or similar. The default value
6443 /// of this property is `1.0`.
6544 ///
66- /// This property is not part of the public interface of the testing
67- /// library. It may be removed in a future update.
68- var _attachmentScaleFactor : CGFloat { get }
45+ /// This property is not part of the public interface of the testing library.
46+ /// It may be removed in a future update.
47+ var attachmentScaleFactor : CGFloat { get }
6948}
7049
7150@available ( _uttypesAPI, * )
7251extension AttachableAsCGImage {
73- public var _attachmentOrientation : UInt32 {
74- CGImagePropertyOrientation . up. rawValue
52+ package var attachmentOrientation : CGImagePropertyOrientation {
53+ . up
7554 }
7655
77- public var _attachmentScaleFactor : CGFloat {
56+ package var attachmentScaleFactor : CGFloat {
7857 1.0
7958 }
8059
81- public func _deinitializeAttachableValue ( ) { }
82- }
60+ public func withUnsafeBytes < R > ( as imageFormat : AttachableImageFormat , _ body : ( UnsafeRawBufferPointer ) throws -> R ) throws -> R {
61+ let data = NSMutableData ( )
8362
84- @available ( _uttypesAPI, * )
85- extension AttachableAsCGImage where Self: Sendable {
86- public func _copyAttachableValue( ) -> Self {
87- self
63+ // Convert the image to a CGImage.
64+ let attachableCGImage = try attachableCGImage
65+
66+ // Create the image destination.
67+ guard let dest = CGImageDestinationCreateWithData ( data as CFMutableData , imageFormat. contentType. identifier as CFString , 1 , nil ) else {
68+ throw ImageAttachmentError . couldNotCreateImageDestination
69+ }
70+
71+ // Configure the properties of the image conversion operation.
72+ let orientation = attachmentOrientation
73+ let scaleFactor = attachmentScaleFactor
74+ let properties : [ CFString : Any ] = [
75+ kCGImageDestinationLossyCompressionQuality: CGFloat ( imageFormat. encodingQuality) ,
76+ kCGImagePropertyOrientation: orientation,
77+ kCGImagePropertyDPIWidth: 72.0 * scaleFactor,
78+ kCGImagePropertyDPIHeight: 72.0 * scaleFactor,
79+ ]
80+
81+ // Perform the image conversion.
82+ CGImageDestinationAddImage ( dest, attachableCGImage, properties as CFDictionary )
83+ guard CGImageDestinationFinalize ( dest) else {
84+ throw ImageAttachmentError . couldNotConvertImage
85+ }
86+
87+ // Pass the bits of the image out to the body. Note that we have an
88+ // NSMutableData here so we have to use slightly different API than we would
89+ // with an instance of Data.
90+ return try withExtendedLifetime ( data) {
91+ try body ( UnsafeRawBufferPointer ( start: data. bytes, count: data. length) )
92+ }
8893 }
8994}
9095#endif
0 commit comments