Skip to content

Commit eece8ed

Browse files
authored
Update Image API (#718)
1 parent 9108d33 commit eece8ed

File tree

7 files changed

+431
-9
lines changed

7 files changed

+431
-9
lines changed

Package.resolved

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// CGImageProvider.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for 6.5.4
6+
// Status: Blocked by Image.Resolved
7+
// ID: BB7900A03A030BC988C08113497314C3 (SwiftUICore?)
8+
9+
public import OpenCoreGraphicsShims
10+
11+
@available(OpenSwiftUI_v1_0, *)
12+
extension Image {
13+
14+
/// Creates a labeled image based on a Core Graphics image instance, usable
15+
/// as content for controls.
16+
///
17+
/// - Parameters:
18+
/// - cgImage: The base graphical image.
19+
/// - scale: The scale factor for the image,
20+
/// with a value like `1.0`, `2.0`, or `3.0`.
21+
/// - orientation: The orientation of the image. The default is
22+
/// ``Image/Orientation/up``.
23+
/// - label: The label associated with the image. OpenSwiftUI uses the label
24+
/// for accessibility.
25+
public init(
26+
_ cgImage: CGImage,
27+
scale: CGFloat,
28+
orientation: Image.Orientation = .up,
29+
label: Text
30+
) {
31+
self.init(
32+
CGImageProvider(
33+
image: cgImage,
34+
scale: scale,
35+
orientation: orientation,
36+
label: label,
37+
decorative: false
38+
)
39+
)
40+
}
41+
42+
/// Creates an unlabeled, decorative image based on a Core Graphics image
43+
/// instance.
44+
///
45+
/// OpenSwiftUI ignores this image for accessibility purposes.
46+
///
47+
/// - Parameters:
48+
/// - cgImage: The base graphical image.
49+
/// - scale: The scale factor for the image,
50+
/// with a value like `1.0`, `2.0`, or `3.0`.
51+
/// - orientation: The orientation of the image. The default is
52+
/// ``Image/Orientation/up``.
53+
public init(
54+
decorative cgImage: CGImage,
55+
scale: CGFloat,
56+
orientation: Image.Orientation = .up
57+
) {
58+
self.init(
59+
CGImageProvider(
60+
image: cgImage,
61+
scale: scale,
62+
orientation: orientation,
63+
label: nil,
64+
decorative: true
65+
)
66+
)
67+
}
68+
}
69+
70+
private struct CGImageProvider: ImageProvider {
71+
var image: CGImage
72+
var scale: CGFloat
73+
var orientation: Image.Orientation
74+
var label: Text?
75+
var decorative: Bool
76+
77+
func resolve(in context: ImageResolutionContext) -> Image.Resolved {
78+
_openSwiftUIUnimplementedFailure()
79+
}
80+
81+
func resolveNamedImage(in context: ImageResolutionContext) -> Image.NamedResolved? {
82+
nil
83+
}
84+
}
85+
86+
extension CGImage {
87+
package var size: CGSize {
88+
#if canImport(CoreGraphics)
89+
CGSize(width: CGFloat(width), height: CGFloat(height))
90+
#else
91+
_openSwiftUIPlatformUnimplementedFailure()
92+
#endif
93+
}
94+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//
2+
// Image+PlatformRepresentation.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for 6.5.4
6+
// Status: Complete
7+
// ID: 9FE4F19E3F2D6B2A0FD05C040386BBC3 (SwiftUICore)
8+
9+
package import OpenAttributeGraphShims
10+
11+
// MARK: - PlatformImageRepresentable
12+
13+
package protocol PlatformImageRepresentable {
14+
static func shouldMakeRepresentation(inputs: _ViewInputs) -> Bool
15+
16+
static func makeRepresentation(inputs: _ViewInputs, context: Attribute<Context>, outputs: inout _ViewOutputs)
17+
18+
typealias Context = PlatformImageRepresentableContext
19+
}
20+
21+
package struct PlatformImageRepresentableContext {
22+
package var image: Image.Resolved
23+
24+
package var tintColor: Color?
25+
26+
package var foregroundStyle: AnyShapeStyle?
27+
}
28+
29+
extension _ViewInputs {
30+
package var requestedImageRepresentation: (any PlatformImageRepresentable.Type)? {
31+
get { base.requestedImageRepresentation }
32+
set { base.requestedImageRepresentation = newValue }
33+
}
34+
}
35+
36+
extension _GraphInputs {
37+
private struct ImageRepresentationKey: GraphInput {
38+
static var defaultValue: (any PlatformImageRepresentable.Type)? { nil }
39+
}
40+
41+
package var requestedImageRepresentation: (any PlatformImageRepresentable.Type)? {
42+
get { self[ImageRepresentationKey.self] }
43+
set { self[ImageRepresentationKey.self] = newValue }
44+
}
45+
}
46+
47+
// MARK: - PlatformNamedImageRepresentable
48+
49+
package protocol PlatformNamedImageRepresentable {
50+
static func shouldMakeRepresentation(inputs: _ViewInputs) -> Bool
51+
52+
static func makeRepresentation(inputs: _ViewInputs, context: Attribute<Context>, outputs: inout _ViewOutputs)
53+
54+
typealias Context = PlatformNamedImageRepresentableContext
55+
}
56+
57+
package struct PlatformNamedImageRepresentableContext {
58+
package var image: Image
59+
60+
package var environment: EnvironmentValues
61+
}
62+
63+
extension _ViewInputs {
64+
package var requestedNamedImageRepresentation: (any PlatformNamedImageRepresentable.Type)? {
65+
get { base.requestedNamedImageRepresentation }
66+
set { base.requestedNamedImageRepresentation = newValue }
67+
}
68+
}
69+
70+
extension _GraphInputs {
71+
private struct NamedImageRepresentationKey: GraphInput {
72+
static var defaultValue: (any PlatformNamedImageRepresentable.Type)? { nil }
73+
}
74+
75+
package var requestedNamedImageRepresentation: (any PlatformNamedImageRepresentable.Type)? {
76+
get { self[NamedImageRepresentationKey.self] }
77+
set { self[NamedImageRepresentationKey.self] = newValue }
78+
}
79+
}

Sources/OpenSwiftUICore/View/Image/Image.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public struct Image: Equatable, Sendable {
7474
}
7575

7676
package func resolveNamedImage(in context: ImageResolutionContext) -> Image.NamedResolved? {
77-
provider.resolve(in: context)
77+
provider.resolveNamedImage(in: context)
7878
}
7979

8080
public static func == (lhs: Image, rhs: Image) -> Bool {
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// ImageInterpolation.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for 6.5.4
6+
// Status: Blocked by Image.Resolved
7+
// ID: B65D626E77C8D6CB107EB45FECFC60F0 (SwiftUICore?)
8+
9+
// MARK: - Image.Interpolation
10+
11+
@available(OpenSwiftUI_v1_0, *)
12+
extension Image {
13+
14+
/// The level of quality for rendering an image that requires interpolation,
15+
/// such as a scaled image.
16+
///
17+
/// The ``Image/interpolation(_:)`` modifier specifies the interpolation
18+
/// behavior when using the ``Image/resizable(capInsets:resizingMode:)``
19+
/// modifier on an ``Image``. Use this behavior to prioritize rendering
20+
/// performance or image quality.
21+
public enum Interpolation: Sendable {
22+
23+
/// A value that indicates OpenSwiftUI doesn't interpolate image data.
24+
case none
25+
26+
/// A value that indicates a low level of interpolation quality, which may
27+
/// speed up image rendering.
28+
case low
29+
30+
/// A value that indicates a medium level of interpolation quality,
31+
/// between the low- and high-quality values.
32+
case medium
33+
34+
/// A value that indicates a high level of interpolation quality, which
35+
/// may slow down image rendering.
36+
case high
37+
}
38+
}
39+
40+
// MARK: - InterpolatedProvider & AntialiasedProvider [WIP]
41+
42+
private struct InterpolatedProvider: ImageProvider {
43+
var base: Image
44+
45+
var interpolation: Image.Interpolation
46+
47+
func resolve(in context: ImageResolutionContext) -> Image.Resolved {
48+
var resolved = base.resolve(in: context)
49+
// TODO
50+
return resolved
51+
}
52+
53+
func resolveNamedImage(in context: ImageResolutionContext) -> Image.NamedResolved? {
54+
base.resolveNamedImage(in: context)
55+
}
56+
}
57+
58+
private struct AntialiasedProvider: ImageProvider {
59+
var base: Image
60+
61+
var isAntialiased: Bool
62+
63+
func resolve(in context: ImageResolutionContext) -> Image.Resolved {
64+
var resolved = base.resolve(in: context)
65+
// TODO
66+
return resolved
67+
}
68+
69+
func resolveNamedImage(in context: ImageResolutionContext) -> Image.NamedResolved? {
70+
base.resolveNamedImage(in: context)
71+
}
72+
}
73+
74+
@available(OpenSwiftUI_v1_0, *)
75+
extension Image {
76+
77+
/// Specifies the current level of quality for rendering an
78+
/// image that requires interpolation.
79+
///
80+
/// See the article <doc:Fitting-Images-into-Available-Space> for examples
81+
/// of using `interpolation(_:)` when scaling an ``Image``.
82+
/// - Parameter interpolation: The quality level, expressed as a value of
83+
/// the `Interpolation` type, that OpenSwiftUI applies when interpolating
84+
/// an image.
85+
/// - Returns: An image with the given interpolation value set.
86+
public func interpolation(_ interpolation: Image.Interpolation) -> Image {
87+
Image(
88+
InterpolatedProvider(
89+
base: self,
90+
interpolation: interpolation
91+
)
92+
)
93+
}
94+
95+
/// Specifies whether OpenSwiftUI applies antialiasing when rendering
96+
/// the image.
97+
/// - Parameter isAntialiased: A Boolean value that specifies whether to
98+
/// allow antialiasing. Pass `true` to allow antialising, `false` otherwise.
99+
/// - Returns: An image with the antialiasing behavior set.
100+
public func antialiased(_ isAntialiased: Bool) -> Image {
101+
Image(
102+
AntialiasedProvider(
103+
base: self,
104+
isAntialiased: isAntialiased
105+
)
106+
)
107+
}
108+
}
109+
110+
// MARK: - Image.Interpolation + ProtobufEnum
111+
112+
extension Image.Interpolation: ProtobufEnum {
113+
package var protobufValue: UInt {
114+
switch self {
115+
case .none: 0
116+
case .low: 1
117+
case .medium: 2
118+
case .high: 3
119+
}
120+
}
121+
122+
package init?(protobufValue value: UInt) {
123+
switch value {
124+
case 0: self = .none
125+
case 1: self = .low
126+
case 2: self = .medium
127+
case 3: self = .high
128+
default: return nil
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)