@@ -35,19 +35,33 @@ public struct ImagenMaskReference: ImagenReferenceImage, Encodable {
35
35
try container. encode ( data. base64EncodedString ( ) , forKey: . data)
36
36
}
37
37
38
+ /// Errors that can occur during outpainting.
39
+ public enum OutpaintingError : Error {
40
+ /// The provided image data could not be decoded.
41
+ case invalidImageData
42
+ /// The new dimensions are smaller than the original image.
43
+ case dimensionsTooSmall
44
+ /// The image context could not be created.
45
+ case contextCreationFailed
46
+ /// The image could not be created from the context.
47
+ case imageCreationFailed
48
+ /// The image data could not be created from the image.
49
+ case dataCreationFailed
50
+ }
51
+
38
52
static func generateMaskAndPadForOutpainting( image: ImagenInlineImage ,
39
53
newDimensions: Dimensions ,
40
54
newPosition: ImagenImagePlacement ) throws
41
55
-> [ ImagenReferenceImage ] {
42
56
guard let cgImage = CGImage . fromData ( image. data) else {
43
- throw NSError ( domain : " com.google.firebase.ai " , code : 0 , userInfo : [ NSLocalizedDescriptionKey : " Could not create image from data. " ] )
57
+ throw OutpaintingError . invalidImageData
44
58
}
45
59
46
60
let originalWidth = cgImage. width
47
61
let originalHeight = cgImage. height
48
62
49
63
guard newDimensions. width >= originalWidth, newDimensions. height >= originalHeight else {
50
- throw NSError ( domain : " com.google.firebase.ai " , code : 0 , userInfo : [ NSLocalizedDescriptionKey : " New dimensions must be larger than the original image. " ] )
64
+ throw OutpaintingError . dimensionsTooSmall
51
65
}
52
66
53
67
let offsetX : Int
@@ -90,41 +104,66 @@ public struct ImagenMaskReference: ImagenReferenceImage, Encodable {
90
104
let bitmapInfo = CGImageAlphaInfo . premultipliedLast. rawValue
91
105
92
106
// Create padded image
93
- guard let paddedContext = CGContext ( data: nil , width: newDimensions. width, height: newDimensions. height, bitsPerComponent: 8 , bytesPerRow: 0 , space: colorSpace, bitmapInfo: bitmapInfo) else {
94
- throw NSError ( domain: " com.google.firebase.ai " , code: 0 , userInfo: [ NSLocalizedDescriptionKey: " Could not create padded image context. " ] )
107
+ guard let paddedContext = CGContext (
108
+ data: nil ,
109
+ width: newDimensions. width,
110
+ height: newDimensions. height,
111
+ bitsPerComponent: 8 ,
112
+ bytesPerRow: 0 ,
113
+ space: colorSpace,
114
+ bitmapInfo: bitmapInfo
115
+ ) else {
116
+ throw OutpaintingError . contextCreationFailed
95
117
}
96
- paddedContext. draw ( cgImage, in: CGRect ( x: offsetX, y: offsetY, width: originalWidth, height: originalHeight) )
97
- guard let paddedCGImage = paddedContext. makeImage ( ) , let paddedImageData = paddedCGImage. toData ( ) else {
98
- throw NSError ( domain: " com.google.firebase.ai " , code: 0 , userInfo: [ NSLocalizedDescriptionKey: " Could not get padded image data. " ] )
118
+ paddedContext. draw (
119
+ cgImage,
120
+ in: CGRect ( x: offsetX, y: offsetY, width: originalWidth, height: originalHeight)
121
+ )
122
+ guard let paddedCGImage = paddedContext. makeImage ( ) ,
123
+ let paddedImageData = paddedCGImage. toData ( ) else {
124
+ throw OutpaintingError . imageCreationFailed
99
125
}
100
126
101
127
// Create mask
102
- guard let maskContext = CGContext ( data: nil , width: newDimensions. width, height: newDimensions. height, bitsPerComponent: 8 , bytesPerRow: 0 , space: CGColorSpaceCreateDeviceGray ( ) , bitmapInfo: CGImageAlphaInfo . none. rawValue) else {
103
- throw NSError ( domain: " com.google.firebase.ai " , code: 0 , userInfo: [ NSLocalizedDescriptionKey: " Could not create mask context. " ] )
128
+ guard let maskContext = CGContext (
129
+ data: nil ,
130
+ width: newDimensions. width,
131
+ height: newDimensions. height,
132
+ bitsPerComponent: 8 ,
133
+ bytesPerRow: 0 ,
134
+ space: CGColorSpaceCreateDeviceGray ( ) ,
135
+ bitmapInfo: CGImageAlphaInfo . none. rawValue
136
+ ) else {
137
+ throw OutpaintingError . contextCreationFailed
104
138
}
105
139
maskContext. setFillColor ( gray: 1.0 , alpha: 1.0 )
106
140
maskContext. fill ( CGRect ( x: 0 , y: 0 , width: newDimensions. width, height: newDimensions. height) )
107
141
maskContext. setFillColor ( gray: 0.0 , alpha: 1.0 )
108
142
maskContext. fill ( CGRect ( x: offsetX, y: offsetY, width: originalWidth, height: originalHeight) )
109
143
guard let maskCGImage = maskContext. makeImage ( ) , let maskData = maskCGImage. toData ( ) else {
110
- throw NSError ( domain : " com.google.firebase.ai " , code : 0 , userInfo : [ NSLocalizedDescriptionKey : " Could not get mask data. " ] )
144
+ throw OutpaintingError . dataCreationFailed
111
145
}
112
146
113
147
return [ ImagenRawImage ( data: paddedImageData) , ImagenMaskReference ( data: maskData) ]
114
148
}
115
149
}
116
150
117
151
extension CGImage {
118
- static func fromData( _ data: Data ) -> CGImage ? {
119
- guard let provider = CGDataProvider ( data: data as CFData ) else { return nil }
120
- return CGImage ( pngDataProviderSource : provider , decode : nil , shouldInterpolate : true , intent : . defaultIntent )
121
- }
152
+ static func fromData( _ data: Data ) -> CGImage ? {
153
+ guard let source = CGImageSourceCreateWithData ( data as CFData , nil ) else { return nil }
154
+ return CGImageSourceCreateImageAtIndex ( source , 0 , nil )
155
+ }
122
156
123
- func toData( ) -> Data ? {
124
- guard let mutableData = CFDataCreateMutable ( nil , 0 ) ,
125
- let destination = CGImageDestinationCreateWithData ( mutableData, " public.png " as CFString , 1 , nil ) else { return nil }
126
- CGImageDestinationAddImage ( destination, self , nil )
127
- guard CGImageDestinationFinalize ( destination) else { return nil }
128
- return mutableData as Data
129
- }
130
- }
157
+ func toData( ) -> Data ? {
158
+ guard let mutableData = CFDataCreateMutable ( nil , 0 ) ,
159
+ let destination = CGImageDestinationCreateWithData (
160
+ mutableData,
161
+ " public.png " as CFString ,
162
+ 1 ,
163
+ nil
164
+ ) else { return nil }
165
+ CGImageDestinationAddImage ( destination, self , nil )
166
+ guard CGImageDestinationFinalize ( destination) else { return nil }
167
+ return mutableData as Data
168
+ }
169
+ }
0 commit comments