Skip to content

Commit a6fd721

Browse files
authored
[Vertex AI] Add SourceImage enum to ImageConversionError (#13575)
1 parent 52b9c4b commit a6fd721

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

FirebaseVertexAI/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
asynchronous and must be called with `try await`. (#13545, #13573)
77
- [changed] **Breaking Change**: Creating a chat instance (`startChat`) is now
88
asynchronous and must be called with `await`. (#13545)
9+
- [changed] **Breaking Change**: The source image in the
10+
`ImageConversionError.couldNotConvertToJPEG` error case is now an enum value
11+
instead of the `Any` type. (#13575)
912

1013
# 10.29.0
1114
- [feature] Added community support for watchOS. (#13215)

FirebaseVertexAI/Sources/PartsRepresentable+Image.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,28 @@ private let imageCompressionQuality: CGFloat = 0.8
2525
/// For some image types like `CIImage`, creating valid model content requires creating a JPEG
2626
/// representation of the image that may not yet exist, which may be computationally expensive.
2727
public enum ImageConversionError: Error {
28+
/// The image that could not be converted.
29+
public enum SourceImage {
30+
#if canImport(UIKit)
31+
case uiImage(UIImage)
32+
#elseif canImport(AppKit)
33+
case nsImage(NSImage)
34+
#endif // canImport(UIKit)
35+
case cgImage(CGImage)
36+
#if canImport(CoreImage)
37+
case ciImage(CIImage)
38+
#endif // canImport(CoreImage)
39+
}
40+
2841
/// The image (the receiver of the call `toModelContentParts()`) was invalid.
2942
case invalidUnderlyingImage
3043

3144
/// A valid image destination could not be allocated.
3245
case couldNotAllocateDestination
3346

3447
/// JPEG image data conversion failed, accompanied by the original image, which may be an
35-
/// instance of `NSImageRep`, `UIImage`, `CGImage`, or `CIImage`.
36-
case couldNotConvertToJPEG(Any)
48+
/// instance of `NSImage`, `UIImage`, `CGImage`, or `CIImage`.
49+
case couldNotConvertToJPEG(SourceImage)
3750
}
3851

3952
#if canImport(UIKit)
@@ -42,7 +55,7 @@ public enum ImageConversionError: Error {
4255
extension UIImage: ThrowingPartsRepresentable {
4356
public func tryPartsValue() throws -> [ModelContent.Part] {
4457
guard let data = jpegData(compressionQuality: imageCompressionQuality) else {
45-
throw ImageConversionError.couldNotConvertToJPEG(self)
58+
throw ImageConversionError.couldNotConvertToJPEG(.uiImage(self))
4659
}
4760
return [ModelContent.Part.data(mimetype: "image/jpeg", data)]
4861
}
@@ -59,7 +72,7 @@ public enum ImageConversionError: Error {
5972
let bmp = NSBitmapImageRep(cgImage: cgImage)
6073
guard let data = bmp.representation(using: .jpeg, properties: [.compressionFactor: 0.8])
6174
else {
62-
throw ImageConversionError.couldNotConvertToJPEG(bmp)
75+
throw ImageConversionError.couldNotConvertToJPEG(.nsImage(self))
6376
}
6477
return [ModelContent.Part.data(mimetype: "image/jpeg", data)]
6578
}
@@ -84,7 +97,7 @@ public enum ImageConversionError: Error {
8497
if CGImageDestinationFinalize(imageDestination) {
8598
return [.data(mimetype: "image/jpeg", output as Data)]
8699
}
87-
throw ImageConversionError.couldNotConvertToJPEG(self)
100+
throw ImageConversionError.couldNotConvertToJPEG(.cgImage(self))
88101
}
89102
}
90103
#endif // !os(watchOS)
@@ -105,7 +118,7 @@ public enum ImageConversionError: Error {
105118
if let jpegData = jpegData {
106119
return [.data(mimetype: "image/jpeg", jpegData)]
107120
}
108-
throw ImageConversionError.couldNotConvertToJPEG(self)
121+
throw ImageConversionError.couldNotConvertToJPEG(.ciImage(self))
109122
}
110123
}
111124
#endif // canImport(CoreImage)

FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,24 @@ final class PartsRepresentableTests: XCTestCase {
6060
let image = CIImage.empty()
6161
do {
6262
_ = try image.tryPartsValue()
63+
XCTFail("Expected model content from invalid image to error")
6364
} catch {
6465
guard let imageError = (error as? ImageConversionError) else {
6566
XCTFail("Got unexpected error type: \(error)")
6667
return
6768
}
6869
switch imageError {
6970
case let .couldNotConvertToJPEG(source):
70-
// String(describing:) works around a type error.
71-
XCTAssertEqual(String(describing: source), String(describing: image))
72-
return
73-
case _:
71+
guard case let .ciImage(ciImage) = source else {
72+
XCTFail("Unexpected image source: \(source)")
73+
return
74+
}
75+
XCTAssertEqual(ciImage, image)
76+
default:
7477
XCTFail("Expected image conversion error, got \(imageError) instead")
7578
return
7679
}
7780
}
78-
XCTFail("Expected model content from invalid image to error")
7981
}
8082
#endif // canImport(CoreImage)
8183

@@ -84,22 +86,24 @@ final class PartsRepresentableTests: XCTestCase {
8486
let image = UIImage()
8587
do {
8688
_ = try image.tryPartsValue()
89+
XCTFail("Expected model content from invalid image to error")
8790
} catch {
8891
guard let imageError = (error as? ImageConversionError) else {
8992
XCTFail("Got unexpected error type: \(error)")
9093
return
9194
}
9295
switch imageError {
9396
case let .couldNotConvertToJPEG(source):
94-
// String(describing:) works around a type error.
95-
XCTAssertEqual(String(describing: source), String(describing: image))
96-
return
97-
case _:
97+
guard case let .uiImage(uiImage) = source else {
98+
XCTFail("Unexpected image source: \(source)")
99+
return
100+
}
101+
XCTAssertEqual(uiImage, image)
102+
default:
98103
XCTFail("Expected image conversion error, got \(imageError) instead")
99104
return
100105
}
101106
}
102-
XCTFail("Expected model content from invalid image to error")
103107
}
104108

105109
func testModelContentFromUIImageIsNotEmpty() throws {

0 commit comments

Comments
 (0)