|  | 
|  | 1 | +# Adjustments to image attachments in Swift Testing | 
|  | 2 | + | 
|  | 3 | +* Proposal: [ST-NNNN](NNNN-image-attachment-adjustments.md) | 
|  | 4 | +* Authors: [Jonathan Grynspan](https://github.com/grynspan) | 
|  | 5 | +* Review Manager: TBD | 
|  | 6 | +* Status: **Awaiting review** | 
|  | 7 | +* Implementation: [swiftlang/swift-testing#1359](https://github.com/swiftlang/swift-testing/pull/1359) | 
|  | 8 | +* Review: ([pitch](https://forums.swift.org/...)) | 
|  | 9 | + | 
|  | 10 | +## Introduction | 
|  | 11 | + | 
|  | 12 | +This proposal includes a small number of adjustments to the API surface of Swift | 
|  | 13 | +Testing's image attachments feature introduced in [ST-0014](0014-image-attachments-in-swift-testing-apple-platforms.md) | 
|  | 14 | +and [ST-0015](0015-image-attachments-in-swift-testing-windows.md). | 
|  | 15 | + | 
|  | 16 | +## Motivation | 
|  | 17 | + | 
|  | 18 | +These changes will help to align the platform-specific interfaces of the feature | 
|  | 19 | +more closely. | 
|  | 20 | + | 
|  | 21 | +## Proposed solution | 
|  | 22 | + | 
|  | 23 | +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are | 
|  | 24 | +combined into a single protocol, `AttachableAsImage` with adjusted protocol | 
|  | 25 | +requirements; a change is made to `AttachableImageFormat` to more closely | 
|  | 26 | +align its interface between Darwin and Windows; and an additional property is | 
|  | 27 | +added to `Attachment` to query its image format. | 
|  | 28 | + | 
|  | 29 | +## Detailed design | 
|  | 30 | + | 
|  | 31 | +The following changes are proposed: | 
|  | 32 | + | 
|  | 33 | +### Combining AttachableAsCGImage and AttachableAsIWICBitmapSource | 
|  | 34 | + | 
|  | 35 | +The `AttachableAsCGImage` and `AttachableAsIWICBitmapSource` protocols are | 
|  | 36 | +combined into a single protocol, `AttachableAsImage`. | 
|  | 37 | + | 
|  | 38 | +These platform-specific requirements are removed: | 
|  | 39 | + | 
|  | 40 | +```diff | 
|  | 41 | +- var attachableCGImage: CGImage { get throws } | 
|  | 42 | +- func copyAttachableIWICBitmapSource() throws -> UnsafeMutablePointer<IWICBitmapSource> | 
|  | 43 | +``` | 
|  | 44 | + | 
|  | 45 | +They are replaced with a new requirement that encapsulates the image encoding | 
|  | 46 | +operation. This requirement is implemented by the CoreGraphics and WinSDK | 
|  | 47 | +overlays and is made publicly available for test authors who wish to declare | 
|  | 48 | +additional conformances to this protocol for types that are not based on | 
|  | 49 | +`CGImage` or `IWICBitmapSource`: | 
|  | 50 | + | 
|  | 51 | +```swift | 
|  | 52 | +public protocol AttachableAsImage { | 
|  | 53 | +  // ... | 
|  | 54 | +   | 
|  | 55 | +  /// Encode a representation of this image in a given image format. | 
|  | 56 | +  /// | 
|  | 57 | +  /// - Parameters: | 
|  | 58 | +  ///   - imageFormat: The image format to use when encoding this image. | 
|  | 59 | +  ///   - body: A function to call. A temporary buffer containing a data | 
|  | 60 | +  ///     representation of this instance is passed to it. | 
|  | 61 | +  /// | 
|  | 62 | +  /// - Returns: Whatever is returned by `body`. | 
|  | 63 | +  /// | 
|  | 64 | +  /// - Throws: Whatever is thrown by `body`, or any error that prevented the | 
|  | 65 | +  ///   creation of the buffer. | 
|  | 66 | +  /// | 
|  | 67 | +  /// The testing library uses this function when saving an image as an | 
|  | 68 | +  /// attachment. The implementation should use `imageFormat` to determine what | 
|  | 69 | +  /// encoder to use. | 
|  | 70 | +  borrowing func withUnsafeBytes<R>(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R | 
|  | 71 | +} | 
|  | 72 | +``` | 
|  | 73 | + | 
|  | 74 | +If a developer has an image type that should conform to `AttachableAsImage` and | 
|  | 75 | +wraps an instance of `CGImage` or `IWICBitmapSource`, it is straightforward for | 
|  | 76 | +them to delegate to that object. For example: | 
|  | 77 | + | 
|  | 78 | +```swift | 
|  | 79 | +import Testing | 
|  | 80 | +import CoreGraphics | 
|  | 81 | + | 
|  | 82 | +struct MyImage { | 
|  | 83 | +  var cgImage: CGImage | 
|  | 84 | +  // ... | 
|  | 85 | +} | 
|  | 86 | + | 
|  | 87 | +extension MyImage: AttachableAsImage { | 
|  | 88 | +  func withUnsafeBytes<R>(as imageFormat: AttachableImageFormat, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { | 
|  | 89 | +    try cgImage.withUnsafeBytes(as: imageFormat, body) | 
|  | 90 | +  } | 
|  | 91 | +} | 
|  | 92 | +``` | 
|  | 93 | + | 
|  | 94 | +### Adjusting AttachableImageFormat | 
|  | 95 | + | 
|  | 96 | +The following Apple-specific `AttachableImageFormat` initializer is renamed so | 
|  | 97 | +that its first argument has an explicit label: | 
|  | 98 | + | 
|  | 99 | +```diff | 
|  | 100 | + public struct AttachableImageFormat { | 
|  | 101 | +   // ... | 
|  | 102 | +-  public init(_ contentType: UTType, encodingQuality: Float = 1.0) | 
|  | 103 | ++  public init(contentType: UTType, encodingQuality: Float = 1.0) | 
|  | 104 | + } | 
|  | 105 | +``` | 
|  | 106 | + | 
|  | 107 | +This change makes the type's interface more consistent between Darwin and | 
|  | 108 | +Windows (where it has an `init(encoderCLSID:encodingQuality:)` initializer.) | 
|  | 109 | + | 
|  | 110 | +### Adding an imageFormat property to Attachment | 
|  | 111 | + | 
|  | 112 | +The following property is added to `Attachment` when the attachable value is an | 
|  | 113 | +image: | 
|  | 114 | + | 
|  | 115 | +```swift | 
|  | 116 | +extension Attachment where AttachableValue: AttachableWrapper, | 
|  | 117 | +                           AttachableValue.Wrapped: AttachableAsImage { | 
|  | 118 | +  /// The image format to use when encoding the represented image. | 
|  | 119 | +  public var imageFormat: AttachableImageFormat? { get } | 
|  | 120 | +} | 
|  | 121 | +``` | 
|  | 122 | + | 
|  | 123 | +## Source compatibility | 
|  | 124 | + | 
|  | 125 | +These changes are breaking for anyone who has created a type that conforms to | 
|  | 126 | +either `AttachableAsCGImage` or `AttachableAsIWICBitmapSource`, or anyone who | 
|  | 127 | +has adopted `AttachableImageFormat.init(_:encodingQuality:)`. | 
|  | 128 | + | 
|  | 129 | +This feature is new in Swift 6.3 and has not shipped to developers outside of | 
|  | 130 | +nightly toolchain builds. As such, we feel confident that any real-world impact | 
|  | 131 | +to developers will be both minimal and manageable. | 
|  | 132 | + | 
|  | 133 | +## Integration with supporting tools | 
|  | 134 | + | 
|  | 135 | +No changes. | 
|  | 136 | + | 
|  | 137 | +## Future directions | 
|  | 138 | + | 
|  | 139 | +N/A | 
|  | 140 | + | 
|  | 141 | +## Alternatives considered | 
|  | 142 | + | 
|  | 143 | +- Leaving the two protocols separate. Combining them allows us to lower more | 
|  | 144 | +  code into the main Swift Testing library and improves our ability to generate | 
|  | 145 | +  DocC documentation, while also simplifying the story for developers who want | 
|  | 146 | +  to use this feature across platforms. | 
|  | 147 | + | 
|  | 148 | +## Acknowledgments | 
|  | 149 | + | 
|  | 150 | +Thanks to my colleagues for their feedback on the image attachments feature and | 
|  | 151 | +to the Swift community for putting up with the churn! | 
0 commit comments