[Pitch] Adjustments to image attachments in Swift Testing

(Didn't we just do this one?)

This pitch is for a set of adjustments to the API we proposed in ST-0014 and ST-0015 for image attachments on Apple platforms and on Windows, respectively. The goal here is to harmonize the interfaces between the two platforms and correct a couple of small defects we missed during these reviews.

Read the full proposal here.

Trying it out

To try this feature out, add a dependency to the jgrynspan/image-attachment-adjustments branch of swift-testing to your project:

...
dependencies: [
  ...
  .package(
    url: "https://github.com/swiftlang/swift-testing.git",
    branch: "jgrynspan/image-attachment-adjustments"
  ),
]

Then, add a target dependency to your test target:

.testTarget(
  ...
  dependencies: [
    ...
    .product(name: "Testing", package: "swift-testing"),
  ]
)

Finally, import Swift Testing using @_spi(Experimental) import Testing.

1 Like

This seems reasonable and makes this much more approachable & scalable for other platforms.

Do we know of any platforms like Android that has native formats we could conceivably support - even if we won’t explicitly do it yet?

Just want to see some proving out that this would scale for new platform support

We're tracking support for additional platforms here:

I discussed Android specifically in the alternatives considered section of ST-0014. :slight_smile:

I'd love to add support for Android's corresponding API, but that API is way up in Java land and will require much more work on the swift-java and Android toolchain side before we can consider it.

I remember that, I just meant that a section saying something like “in theory, if you were to build out support for Android, you could conform it to this protocol like this…” to prove out that the protocol will be fine for those additional platforms

That being said I think it’s reasonably fine as-is now that I revisit it, given the fact we’re going so low with asking for a raw bytes view for conformers

Happy to do that right here. Let's pretend for the moment that swift-java is available to us and there are Swift projections of most/all of the Android SDK, in particular android.graphics.Bitmap. I suspect we'd write something like:

public import android

extension AttachableImageFormat {
  public var bitmapCompressFormat: android.graphics.Bitmap.CompressFormat {
    switch self /* see [1] */ {
    case .png:
      return .PNG
    case .jpeg(withEncodingQuality: encodingQuality):
      return .JPEG
    default:
      fatalError("Unreachable")
    }
  }
}

extension android.graphics.Bitmap: AttachableAsImage {
  public func withUnsafeBytes<R>(
    as imageFormat: AttachableImageFormat,
    _ body: (UnsafeRawBufferPointer) throws -> R
  ) throws -> R {
    let stream = ByteArrayOutputStream()
    let result = self.compress(
      imageFormat.bitmapCompressFormat,
      jint(100 * imageFormat.encodingQuality),
      stream
    )
    guard result else {
      throw SomeError()
    }
    return try body(stream.toByteArray())
  }
}

There's a bit more glue code we could write in Swift Testing if we wanted, but this is the bulk of the work required as far as I know!

[1]: It occurs to me that we need AttachableImageFormat to conform to Equatable for external code to compare instances, so I've added that to the proposal text. Thanks for the reminder!


  1. 1 ↩︎

2 Likes

Could the new requirement use RawSpan instead of UnsafeRawBufferPointer?

Unfortunately no, because the underlying buffer is transient and so the span could not escape the function call. (Also functions cannot return non-escapable values yet.)