Skip to content

Commit a708dc1

Browse files
authored
Merge pull request #47 from EricAtomic/add-rgba-support
Add support for RGBA values
2 parents 67d6bb3 + b5a1ba7 commit a708dc1

File tree

11 files changed

+115
-35
lines changed

11 files changed

+115
-35
lines changed

Examples/Sources/ViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class ViewController: UIViewController {
6565

6666
override func loadView() {
6767
let imageView = UIImageView(frame: UIScreen.main.bounds)
68-
imageView.image = SVG(named: "units-cm.svg", in: .samples)?.rasterize()
68+
imageView.image = SVG(named: "rgba.svg", in: .samples)?.rasterize()
6969
imageView.contentMode = .scaleAspectFit
7070
imageView.backgroundColor = .white
7171
self.view = imageView

Samples.bundle/rgba.svg

Lines changed: 5 additions & 0 deletions
Loading

SwiftDraw/DOM.Color.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ extension DOM {
3535
case none
3636
case currentColor
3737
case keyword(Keyword)
38-
case rgbi(UInt8, UInt8, UInt8)
39-
case rgbf(DOM.Float, DOM.Float, DOM.Float)
38+
case rgbi(UInt8, UInt8, UInt8, DOM.Float)
39+
case rgbf(DOM.Float, DOM.Float, DOM.Float, DOM.Float)
4040
case p3(DOM.Float, DOM.Float, DOM.Float)
4141
case hex(UInt8, UInt8, UInt8)
4242

SwiftDraw/LayerTree.Color.swift

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ extension LayerTree.Color {
5858
case let .keyword(c):
5959
let rgbi = c.rgbi
6060
return LayerTree.Color(rgbi.0, rgbi.1, rgbi.2)
61-
case let .rgbi(r, g, b):
62-
return LayerTree.Color(r, g, b)
61+
case let .rgbi(r, g, b, a):
62+
return LayerTree.Color(r, g, b, Float(a))
6363
case let .hex(r, g, b):
6464
return LayerTree.Color(r, g, b)
65-
case let .rgbf(r, g, b):
65+
case let .rgbf(r, g, b, a):
6666
return .rgba(r: Float(r),
6767
g: Float(g),
6868
b: Float(b),
69-
a: 1.0,
69+
a: Float(a),
7070
space: .srgb)
7171
case let .p3(r, g, b):
7272
return .rgba(r: Float(r),
@@ -84,6 +84,14 @@ extension LayerTree.Color {
8484
a: 1.0,
8585
space: .srgb)
8686
}
87+
88+
init(_ r: UInt8, _ g: UInt8, _ b: UInt8, _ a: DOM.Float) {
89+
self = .rgba(r: Float(r)/255.0,
90+
g: Float(g)/255.0,
91+
b: Float(b)/255.0,
92+
a: a,
93+
space: .srgb)
94+
}
8795

8896
var isOpaque: Bool {
8997
switch self {
@@ -100,14 +108,14 @@ extension LayerTree.Color {
100108
switch self {
101109
case .none:
102110
return .none
103-
case let .rgba(r: r, g: g, b: b, a: _, space):
111+
case let .rgba(r: r, g: g, b: b, a: a, space):
104112
return .rgba(r: r,
105113
g: g,
106114
b: b,
107-
a: alpha,
115+
a: alpha * a,
108116
space: space)
109-
case .gray(white: let w, a: _):
110-
return .gray(white: w, a: alpha)
117+
case .gray(white: let w, a: let a):
118+
return .gray(white: w, a: alpha * a)
111119
}
112120
}
113121

SwiftDraw/Parser.XML.Color.swift

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ extension XMLParser {
4949
return .color(c)
5050
} else if let url = try parseURLSelector(data: data) {
5151
return .url(url)
52+
} else if let c = try parseColorRGBA(data: data) {
53+
return .color(c)
5254
}
5355

5456
throw Error.invalid
@@ -89,6 +91,17 @@ extension XMLParser {
8991
return try parseColorRGBi(data: data)
9092
}
9193

94+
private func parseColorRGBA(data: String) throws -> DOM.Color? {
95+
var scanner = XMLParser.Scanner(text: data)
96+
guard scanner.scanStringIfPossible("rgba(") else { return nil }
97+
98+
if let c = try? parseColorRGBAf(data: data) {
99+
return c
100+
}
101+
102+
return try parseColorRGBAi(data: data)
103+
}
104+
92105
private func parseURLSelector(data: String) throws -> DOM.URL? {
93106
var scanner = XMLParser.Scanner(text: data)
94107
guard (try? scanner.scanString("url(")) == true else {
@@ -107,33 +120,64 @@ extension XMLParser {
107120
return url
108121
}
109122

110-
private func parseColorRGBi(data: String) throws -> DOM.Color {
123+
private func parseIntColor(data: String, withAlpha: Bool) throws -> DOM.Color {
111124
var scanner = XMLParser.Scanner(text: data)
112-
try scanner.scanString("rgb(")
125+
try scanner.scanString(withAlpha ? "rgba(" : "rgb(")
113126

114127
let r = try scanner.scanUInt8()
115128
scanner.scanStringIfPossible(",")
116129
let g = try scanner.scanUInt8()
117130
scanner.scanStringIfPossible(",")
118131
let b = try scanner.scanUInt8()
132+
var a: Float = 1.0
133+
134+
if withAlpha {
135+
scanner.scanStringIfPossible(",")
136+
a = try scanner.scanFloat() // Opacity
137+
}
138+
119139
try scanner.scanString(")")
120-
return .rgbi(r, g, b)
140+
return .rgbi(r, g, b, a)
121141
}
122142

123-
private func parseColorRGBf(data: String) throws -> DOM.Color {
143+
private func parseColorRGBi(data: String) throws -> DOM.Color {
144+
return try parseIntColor(data: data, withAlpha: false)
145+
}
146+
147+
private func parseColorRGBAi(data: String) throws -> DOM.Color {
148+
return try parseIntColor(data: data, withAlpha: true)
149+
}
150+
151+
private func parsePercentageColor(data: String, withAlpha: Bool) throws -> DOM.Color {
124152
var scanner = XMLParser.Scanner(text: data)
125-
try scanner.scanString("rgb(")
153+
try scanner.scanString(withAlpha ? "rgba(" : "rgb(")
126154

127155
let r = try scanner.scanPercentage()
128156
scanner.scanStringIfPossible(",")
129157
let g = try scanner.scanPercentage()
130158
scanner.scanStringIfPossible(",")
131159
let b = try scanner.scanPercentage()
160+
161+
var a: Float = 1.0
162+
if withAlpha {
163+
scanner.scanStringIfPossible(",")
164+
a = try scanner.scanFloat() // Opacity
165+
}
166+
132167
try scanner.scanString(")")
133168

134-
return .rgbf(r, g, b)
169+
return .rgbf(r, g, b, a)
135170
}
136171

172+
private func parseColorRGBf(data: String) throws -> DOM.Color {
173+
return try parsePercentageColor(data: data, withAlpha: false)
174+
}
175+
176+
private func parseColorRGBAf(data: String) throws -> DOM.Color {
177+
return try parsePercentageColor(data: data, withAlpha: true)
178+
}
179+
180+
137181
private func parseColorP3(data: String) throws -> DOM.Color? {
138182
var scanner = XMLParser.Scanner(text: data)
139183
guard scanner.scanStringIfPossible("color(display-p3") else { return nil }

SwiftDraw/XML.Formatter.SVG.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,23 @@ extension XML.Formatter {
295295
return "currentColor"
296296
case let .keyword(k):
297297
return k.rawValue
298-
case let .rgbi(r, g, b):
299-
return "rgb(\(r), \(g), \(b))"
300-
case let .rgbf(r, g, b):
298+
case let .rgbi(r, g, b, a):
299+
if a == 1.0 {
300+
return "rgb(\(r), \(g), \(b))"
301+
} else {
302+
let aa = String(format: "%.2f", a)
303+
return "rgba(\(r), \(g), \(b), \(aa))"
304+
}
305+
case let .rgbf(r, g, b, a):
301306
let rr = String(format: "%.0f", r * 100)
302307
let gg = String(format: "%.0f", g * 100)
303308
let bb = String(format: "%.0f", b * 100)
304-
return "rgb(\(rr)%, \(gg)%, \(bb)%)"
309+
if a == 1.0 {
310+
return "rgb(\(rr)%, \(gg)%, \(bb)%)"
311+
} else {
312+
let aa = String(format: "%.2f", a)
313+
return "rgba(\(rr)%, \(gg)%, \(bb)%, \(aa))"
314+
}
305315
case let .p3(r, g, b):
306316
return "color(display-p3 \(r), \(g), \(b))"
307317
case let .hex(r, g, b):

SwiftDrawTests/LayerTree.BuilderTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ final class LayerTreeBuilderTests: XCTestCase {
106106

107107
func testStrokeAttributes() {
108108
var state = LayerTree.Builder.State()
109-
state.stroke = .color(.rgbf(1.0, 0.0, 0.0))
109+
state.stroke = .color(.rgbf(1.0, 0.0, 0.0, 1.0))
110110
state.strokeOpacity = 0.5
111111
state.strokeWidth = 5.0
112112
state.strokeLineCap = .square

SwiftDrawTests/LayerTree.ColorTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ final class LayerTreeColorTests: XCTestCase {
119119
let none = DOM.Color.none
120120
let black = DOM.Color.keyword(.black)
121121
let white = DOM.Color.keyword(.white)
122-
let red = DOM.Color.rgbi(255, 0, 0)
123-
let green = DOM.Color.rgbi(0, 255, 0)
124-
let blue = DOM.Color.rgbi(0, 0, 255)
122+
let red = DOM.Color.rgbi(255, 0, 0, 1.0)
123+
let green = DOM.Color.rgbi(0, 255, 0, 1.0)
124+
let blue = DOM.Color.rgbi(0, 0, 255, 1.0)
125125

126126
XCTAssertEqual(Color(none), .none)
127127
XCTAssertEqual(Color(black), .srgb(r: 0.0, g: 0.0, b: 0.0, a: 1.0))

SwiftDrawTests/NSImage+ImageTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ private extension SVG {
7272
let svg = DOM.SVG(width: 2, height: 2)
7373
svg.childElements.append(DOM.Rect(x: 0, y: 0, width: 1, height: 1))
7474
svg.childElements.append(DOM.Rect(x: 1, y: 1, width: 1, height: 1))
75-
svg.childElements[0].attributes.fill = .color(DOM.Color.rgbi(255, 0, 0))
76-
svg.childElements[1].attributes.fill = .color(DOM.Color.rgbi(0, 0, 255))
75+
svg.childElements[0].attributes.fill = .color(DOM.Color.rgbi(255, 0, 0, 1.0))
76+
svg.childElements[1].attributes.fill = .color(DOM.Color.rgbi(0, 0, 255, 1.0))
7777
return SVG(dom: svg, options: .default)
7878
}
7979
}

SwiftDrawTests/Parser.XML.ColorTests.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,27 @@ final class ParserColorTests: XCTestCase {
6363

6464
func testColorRGBi() {
6565
// integer 0-255
66-
XCTAssertEqual(try XMLParser().parseColor("rgb(0,1,2)"), .rgbi(0, 1, 2))
67-
XCTAssertEqual(try XMLParser().parseColor(" rgb( 0 , 1 , 2) "), .rgbi(0, 1, 2))
68-
XCTAssertEqual(try XMLParser().parseColor("rgb(255,100,78)"), .rgbi(255, 100, 78))
66+
XCTAssertEqual(try XMLParser().parseColor("rgb(0,1,2)"), .rgbi(0, 1, 2, 1.0))
67+
XCTAssertEqual(try XMLParser().parseColor(" rgb( 0 , 1 , 2) "), .rgbi(0, 1, 2, 1.0))
68+
XCTAssertEqual(try XMLParser().parseColor("rgb(255,100,78)"), .rgbi(255, 100, 78, 1.0))
6969
}
7070

7171
func testColorRGBf() {
7272
// percentage 0-100%
73-
XCTAssertEqual(try XMLParser().parseColor("rgb(0,1%,99%)"), .rgbf(0.0, 0.01, 0.99))
74-
XCTAssertEqual(try XMLParser().parseColor("rgb( 0%, 52% , 100%) "), .rgbf(0.0, 0.52, 1.0))
75-
XCTAssertEqual(try XMLParser().parseColor("rgb(75%,25%,7%)"), .rgbf(0.75, 0.25, 0.07))
73+
XCTAssertEqual(try XMLParser().parseColor("rgb(0,1%,99%)"), .rgbf(0.0, 0.01, 0.99, 1.0))
74+
XCTAssertEqual(try XMLParser().parseColor("rgb( 0%, 52% , 100%) "), .rgbf(0.0, 0.52, 1.0, 1.0))
75+
XCTAssertEqual(try XMLParser().parseColor("rgb(75%,25%,7%)"), .rgbf(0.75, 0.25, 0.07, 1.0))
76+
}
77+
78+
func testColorRGBA() {
79+
// integer 0-255
80+
XCTAssertEqual(try XMLParser().parseColor("rgba(0,1,2,0.5)"), .rgbi(0, 1, 2, 0.5))
81+
XCTAssertEqual(try XMLParser().parseColor(" rgba( 0 , 1 , 2, 0.6) "), .rgbi(0, 1, 2, 0.6))
82+
XCTAssertEqual(try XMLParser().parseColor("rgba(255,100,78,0.7)"), .rgbi(255, 100, 78, 0.7))
83+
// percentage 0-100%
84+
XCTAssertEqual(try XMLParser().parseColor("rgba(0,1%,99%,0.5)"), .rgbf(0.0, 0.01, 0.99, 0.5))
85+
XCTAssertEqual(try XMLParser().parseColor("rgba( 0%, 52% , 100%, 0.6) "), .rgbf(0.0, 0.52, 1.0, 0.6))
86+
XCTAssertEqual(try XMLParser().parseColor("rgba(75%,25%,7%,0.7)"), .rgbf(0.75, 0.25, 0.07, 0.7))
7687
}
7788

7889
func testColorHex() {

0 commit comments

Comments
 (0)