Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// swift-tools-version:5.0
// swift-tools-version:5.3

import PackageDescription
import Foundation

let package = Package(
name: "SwiftSVG",
Expand All @@ -15,7 +16,10 @@ let package = Package(
.target(
name: "SwiftSVG",
dependencies: [],
path: "SwiftSVG"
path: "SwiftSVG",
resources: [
.process("cssColorNames.json")
]
),
.testTarget(
name: "SwiftSVGTests",
Expand Down
23 changes: 19 additions & 4 deletions SwiftSVG/SVG Extensions/SVGLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,25 @@ public extension SVGLayer {
Returns a copy of the given SVGLayer
*/
var svgLayerCopy: SVGLayer? {
let tmp = NSKeyedArchiver.archivedData(withRootObject: self)
let copiedLayer = NSKeyedUnarchiver.unarchiveObject(with: tmp) as? SVGLayer
copiedLayer?.boundingBox = self.boundingBox
return copiedLayer
/// new recommended method
if #available(iOS 11.0, *) {
do {
let tmp = try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
let copiedLayer = try? NSKeyedUnarchiver.unarchivedObject(ofClass: SVGLayer.self, from: tmp)
copiedLayer?.boundingBox = self.boundingBox
return copiedLayer
} catch let error {
print("SVGLayer error occured: " + error.localizedDescription)
return nil
}
}
/// old method
else {
let tmp = NSKeyedArchiver.archivedData(withRootObject: self)
let copiedLayer = NSKeyedUnarchiver.unarchiveObject(with: tmp) as? SVGLayer
copiedLayer?.boundingBox = self.boundingBox
return copiedLayer
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions SwiftSVG/SVG/Attributes/Fillable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ extension Fillable where Self : SVGShapeElement {
- SeeAlso: CAShapeLayer's [`fillColor`](https://developer.apple.com/documentation/quartzcore/cashapelayer/1522248-fillcolor)
*/
func fill(fillColor: String) {
guard let colorComponents = self.svgLayer.fillColor?.components else {
// force if color is none
if fillColor == "none" {
self.svgLayer.fillColor = UIColor.clear.cgColor
return
}
// continue with the another color
guard let colorComponents = self.svgLayer.fillColor?.components, colorComponents.count == 4 else {
return
}
guard let fillColor = UIColor(svgString: fillColor) else {
Expand All @@ -93,7 +99,7 @@ extension Fillable where Self : SVGShapeElement {
guard let opacity = CGFloat(opacity) else {
return
}
guard let colorComponents = self.svgLayer.fillColor?.components else {
guard let colorComponents = self.svgLayer.fillColor?.components, colorComponents.count == 4 else {
return
}
self.svgLayer.fillColor = UIColor(red: colorComponents[0], green: colorComponents[1], blue: colorComponents[2], alpha: opacity).cgColor
Expand Down
2 changes: 1 addition & 1 deletion SwiftSVG/SVG/Helpers/Dictionary+JSON.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import Foundation
extension Dictionary where Key: Decodable, Value: Decodable {

init?(jsonFile name: String?) {
guard let jsonPath = Bundle(for: NSXMLSVGParser.self).url(forResource: name, withExtension: "json") else {
guard let jsonPath = Bundle.module.url(forResource: "cssColorNames", withExtension: "json") else {
return nil
}
guard let jsonData = try? Data(contentsOf: jsonPath) else {
Expand Down
6 changes: 3 additions & 3 deletions SwiftSVG/SVG/Iterators/PathCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@
#endif


internal enum PathType {
public enum PathType {
case absolute, relative
}

/**
A protocol that describes an instance that can process an individual SVG Element
*/
internal protocol PathCommand: PreviousCommand {
public protocol PathCommand: PreviousCommand {

/**
An array that stores processed coordinates values
Expand Down Expand Up @@ -75,7 +75,7 @@ internal protocol PathCommand: PreviousCommand {
/**
A protocol that describes an instance that represents an SVGElement right before the current one
*/
internal protocol PreviousCommand {
public protocol PreviousCommand {

/**
An array that stores processed coordinates values
Expand Down
153 changes: 153 additions & 0 deletions SwiftSVG/cssColorNames.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
{
"aliceblue": "#f0f8ff",
"antiquewhite": "#faebd7",
"aqua": "#00ffff",
"aquamarine": "#7fffd4",
"azure": "#f0ffff",
"beige": "#f5f5dc",
"bisque": "#ffe4c4",
"black": "#000000",
"blanchedalmond": "#ffebcd",
"blue": "#0000ff",
"blueviolet": "#8a2be2",
"brown": "#a52a2a",
"burlywood": "#deb887",
"cadetblue": "#5f9ea0",
"chartreuse": "#7fff00",
"chocolate": "#d2691e",
"coral": "#ff7f50",
"cornflowerblue": "#6495ed",
"cornsilk": "#fff8dc",
"crimson": "#dc143c",
"cyan": "#00ffff",
"darkblue": "#00008b",
"darkcyan": "#008b8b",
"darkgoldenrod": "#b8860b",
"darkgray": "#a9a9a9",
"darkgreen": "#006400",
"darkgrey": "#a9a9a9",
"darkkhaki": "#bdb76b",
"darkmagenta": "#8b008b",
"darkolivegreen": "#556b2f",
"darkorange": "#ff8c00",
"darkorchid": "#9932cc",
"darkred": "#8b0000",
"darksalmon": "#e9967a",
"darkseagreen": "#8fbc8f",
"darkslateblue": "#483d8b",
"darkslategray": "#2f4f4f",
"darkslategrey": "#2f4f4f",
"darkturquoise": "#00ced1",
"darkviolet": "#9400d3",
"deeppink": "#ff1493",
"deepskyblue": "#00bfff",
"dimgray": "#696969",
"dimgrey": "#696969",
"dodgerblue": "#1e90ff",
"firebrick": "#b22222",
"floralwhite": "#fffaf0",
"forestgreen": "#228b22",
"fuchsia": "#ff00ff",
"gainsboro": "#dcdcdc",
"ghostwhite": "#f8f8ff",
"goldenrod": "#daa520",
"gold": "#ffd700",
"gray": "#808080",
"green": "#008000",
"greenyellow": "#adff2f",
"grey": "#808080",
"honeydew": "#f0fff0",
"hotpink": "#ff69b4",
"indianred": "#cd5c5c",
"indigo": "#4b0082",
"ivory": "#fffff0",
"khaki": "#f0e68c",
"lavenderblush": "#fff0f5",
"lavender": "#e6e6fa",
"lawngreen": "#7cfc00",
"lemonchiffon": "#fffacd",
"lightblue": "#add8e6",
"lightcoral": "#f08080",
"lightcyan": "#e0ffff",
"lightgoldenrodyellow": "#fafad2",
"lightgray": "#d3d3d3",
"lightgreen": "#90ee90",
"lightgrey": "#d3d3d3",
"lightpink": "#ffb6c1",
"lightsalmon": "#ffa07a",
"lightseagreen": "#20b2aa",
"lightskyblue": "#87cefa",
"lightslategray": "#778899",
"lightslategrey": "#778899",
"lightsteelblue": "#b0c4de",
"lightyellow": "#ffffe0",
"lime": "#00ff00",
"limegreen": "#32cd32",
"linen": "#faf0e6",
"magenta": "#ff00ff",
"maroon": "#800000",
"mediumaquamarine": "#66cdaa",
"mediumblue": "#0000cd",
"mediumorchid": "#ba55d3",
"mediumpurple": "#9370db",
"mediumseagreen": "#3cb371",
"mediumslateblue": "#7b68ee",
"mediumspringgreen": "#00fa9a",
"mediumturquoise": "#48d1cc",
"mediumvioletred": "#c71585",
"midnightblue": "#191970",
"mintcream": "#f5fffa",
"mistyrose": "#ffe4e1",
"moccasin": "#ffe4b5",
"navajowhite": "#ffdead",
"navy": "#000080",
"none": "#00000000",
"oldlace": "#fdf5e6",
"olive": "#808000",
"olivedrab": "#6b8e23",
"orange": "#ffa500",
"orangered": "#ff4500",
"orchid": "#da70d6",
"palegoldenrod": "#eee8aa",
"palegreen": "#98fb98",
"paleturquoise": "#afeeee",
"palevioletred": "#db7093",
"papayawhip": "#ffefd5",
"peachpuff": "#ffdab9",
"peru": "#cd853f",
"pink": "#ffc0cb",
"plum": "#dda0dd",
"powderblue": "#b0e0e6",
"purple": "#800080",
"rebeccapurple": "#663399",
"red": "#ff0000",
"rosybrown": "#bc8f8f",
"royalblue": "#4169e1",
"saddlebrown": "#8b4513",
"salmon": "#fa8072",
"sandybrown": "#f4a460",
"seagreen": "#2e8b57",
"seashell": "#fff5ee",
"sienna": "#a0522d",
"silver": "#c0c0c0",
"skyblue": "#87ceeb",
"slateblue": "#6a5acd",
"slategray": "#708090",
"slategrey": "#708090",
"snow": "#fffafa",
"springgreen": "#00ff7f",
"steelblue": "#4682b4",
"tan": "#d2b48c",
"teal": "#008080",
"thistle": "#d8bfd8",
"tomato": "#ff6347",
"transparent": "00000000",
"turquoise": "#40e0d0",
"violet": "#ee82ee",
"wheat": "#f5deb3",
"white": "#ffffff",
"whitesmoke": "#f5f5f5",
"yellow": "#ffff00",
"yellowgreen": "#9acd32"
}

17 changes: 10 additions & 7 deletions SwiftSVGTests/CGPathPoints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
// THE SOFTWARE.



import UIKit

#if os(iOS) || os(tvOS)
import UIKit
#elseif os(OSX)
import AppKit
#endif
import SwiftSVG

extension CGPath {

Expand All @@ -50,6 +53,8 @@ extension CGPath {
arrayPoints.append(element.points[2])
case .closeSubpath:
arrayPoints.append(element.points[0])
@unknown default:
fatalError("CGPath:points: no such element")
}
}
return arrayPoints
Expand All @@ -72,6 +77,8 @@ extension CGPath {
arrayPoints.append((element.points[2], .addCurveToPoint))
case .closeSubpath:
arrayPoints.append((element.points[0], .closeSubpath))
@unknown default:
fatalError("CGPath:points: no such element")
}
}
return arrayPoints
Expand All @@ -97,7 +104,3 @@ extension PathCommand {
}

}




11 changes: 8 additions & 3 deletions SwiftSVGTests/ClosePathTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,19 @@


import XCTest
@testable
import SwiftSVG

class ClosePathTests: XCTestCase {

func testClosePath() {
let testPath = UIBezierPath()
_ = MoveTo(parameters: [20, -30], pathType: .absolute, path:testPath)
_ = ClosePath(parameters: [], pathType: .absolute, path:testPath)
let lastPointAndType = testPath.cgPath.pointsAndTypes.last!
_ = MoveTo(pathType: .absolute)
_ = ClosePath(pathType: .absolute)
guard let lastPointAndType = testPath.cgPath.pointsAndTypes.last else {
XCTFail()
return
}
XCTAssert(lastPointAndType.1 == .closeSubpath, "Expected .closeSubpath, got \(lastPointAndType.1)")
XCTAssert(lastPointAndType.0.x.isNaN == true && lastPointAndType.0.y.isNaN == true, "Expected NaN, NaN, got \(lastPointAndType.0)")
}
Expand Down
2 changes: 2 additions & 0 deletions SwiftSVGTests/CoordinateLexerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@


import XCTest
@testable
import SwiftSVG

class IteratorTests: XCTestCase {

Expand Down
40 changes: 26 additions & 14 deletions SwiftSVGTests/CurveToTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,43 @@


import XCTest
@testable
import SwiftSVG

class CurveToTests: XCTestCase {

func testAbsoluteCurveTo() {
let testPath = UIBezierPath()
_ = MoveTo(parameters: [10, -20], pathType: .absolute, path: testPath)
_ = CurveTo(parameters: [66, 37, 32, -18, 23, 98], pathType: .absolute, path: testPath)
_ = MoveTo(pathType: .absolute)
_ = CurveTo(pathType: .absolute)
let points = testPath.cgPath.points
XCTAssert(points[0].x == 10 && points[0].y == -20, "Expected 10, -20, got \(points[0])")
XCTAssert(points[1].x == 66 && points[1].y == 37, "Expected 66, 37, got \(points[1])")
XCTAssert(points[2].x == 32 && points[2].y == -18, "Expected 32, -18, got \(points[2])")
XCTAssert(points[3].x == 23 && points[3].y == 98, "Expected 23, 98, got \(points[3])")
XCTAssert(points[3].x == testPath.currentPoint.x && points[3].y == testPath.currentPoint.y, "Expected {\(testPath.currentPoint)}, got \(points[3])")
print(points)
print(points.isEmpty)
if (points.isEmpty) {
XCTFail("Points array is empty")
} else {
XCTAssert(points[0].x == 10 && points[0].y == -20, "Expected 10, -20, got \(points[0])")
XCTAssert(points[1].x == 66 && points[1].y == 37, "Expected 66, 37, got \(points[1])")
XCTAssert(points[2].x == 32 && points[2].y == -18, "Expected 32, -18, got \(points[2])")
XCTAssert(points[3].x == 23 && points[3].y == 98, "Expected 23, 98, got \(points[3])")
XCTAssert(points[3].x == testPath.currentPoint.x && points[3].y == testPath.currentPoint.y, "Expected {\(testPath.currentPoint)}, got \(points[3])")
}
}

func testRelativeCurveTo() {
let testPath = UIBezierPath()
_ = MoveTo(parameters: [10, -20], pathType: .absolute, path: testPath)
_ = CurveTo(parameters: [66, 37, 32, -18, 23, 98], pathType: .relative, path: testPath)
_ = MoveTo(pathType: .absolute)
_ = CurveTo(pathType: .relative)
let points = testPath.cgPath.points
XCTAssert(points[0].x == 10 && points[0].y == -20, "Expected 10, -20, got \(points[0])")
XCTAssert(points[1].x == 76 && points[1].y == 17, "Expected 76, 17, got \(points[1])")
XCTAssert(points[2].x == 42 && points[2].y == -38, "Expected 42, -38, got \(points[2])")
XCTAssert(points[3].x == 33 && points[3].y == 78, "Expected 33, 78, got \(points[3])")
XCTAssert(points[3].x == testPath.currentPoint.x && points[3].y == testPath.currentPoint.y, "Expected {\(testPath.currentPoint)}, got \(points[3])")
if (points.isEmpty) {
XCTFail("Points array is empty")
} else {
XCTAssert(points[0].x == 10 && points[0].y == -20, "Expected 10, -20, got \(points[0])")
XCTAssert(points[1].x == 76 && points[1].y == 17, "Expected 76, 17, got \(points[1])")
XCTAssert(points[2].x == 42 && points[2].y == -38, "Expected 42, -38, got \(points[2])")
XCTAssert(points[3].x == 33 && points[3].y == 78, "Expected 33, 78, got \(points[3])")
XCTAssert(points[3].x == testPath.currentPoint.x && points[3].y == testPath.currentPoint.y, "Expected {\(testPath.currentPoint)}, got \(points[3])")
}
}

}
Loading