diff --git a/SwiftDraw/DOM.SVG+Parse.swift b/SwiftDraw/DOM.SVG+Parse.swift new file mode 100644 index 0000000..262fc4d --- /dev/null +++ b/SwiftDraw/DOM.SVG+Parse.swift @@ -0,0 +1,47 @@ +// +// DOM.SVG+Parse.swift +// SwiftDraw +// +// Created by Simon Whitty on 23/2/25. +// Copyright 2025 Simon Whitty +// +// Distributed under the permissive zlib license +// Get the latest version from here: +// +// https://github.com/swhitty/SwiftDraw +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + +import Foundation + +extension DOM.SVG { + + static func parse(fileURL url: URL, options: XMLParser.Options = .skipInvalidElements) throws -> DOM.SVG { + let element = try XML.SAXParser.parse(contentsOf: url) + let parser = XMLParser(options: options, filename: url.lastPathComponent) + return try parser.parseSVG(element) + } + + static func parse(data: Data, options: XMLParser.Options = .skipInvalidElements) throws -> DOM.SVG { + let element = try XML.SAXParser.parse(data: data) + let parser = XMLParser(options: options) + return try parser.parseSVG(element) + } +} diff --git a/SwiftDraw/SVG+Insets.swift b/SwiftDraw/SVG+Insets.swift new file mode 100644 index 0000000..5c34684 --- /dev/null +++ b/SwiftDraw/SVG+Insets.swift @@ -0,0 +1,59 @@ +// +// SVG+Insets.swift +// SwiftDraw +// +// Created by Simon Whitty on 23/2/25. +// Copyright 2025 Simon Whitty +// +// Distributed under the permissive zlib license +// Get the latest version from here: +// +// https://github.com/swhitty/SwiftDraw +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + +import Foundation + +#if canImport(CoreGraphics) +import CoreGraphics +#endif + +public extension SVG { + struct Insets: Equatable { + public var top: CGFloat + public var left: CGFloat + public var bottom: CGFloat + public var right: CGFloat + + public init( + top: CGFloat = 0, + left: CGFloat = 0, + bottom: CGFloat = 0, + right: CGFloat = 0 + ) { + self.top = top + self.left = left + self.bottom = bottom + self.right = right + } + + public static let zero = Insets(top: 0, left: 0, bottom: 0, right: 0) + } +} diff --git a/SwiftDraw/SVG.swift b/SwiftDraw/SVG.swift index 3528d6c..da9ade5 100644 --- a/SwiftDraw/SVG.swift +++ b/SwiftDraw/SVG.swift @@ -34,14 +34,56 @@ import Foundation #if canImport(CoreGraphics) import CoreGraphics -@objc(SVGImage) -public final class SVG: NSObject { +public struct SVG { public let size: CGSize //An Image is simply an array of CoreGraphics draw commands //see: Renderer.swift let commands: [RendererCommand] + public init?(fileURL url: URL, options: SVG.Options = .default) { + do { + let svg = try DOM.SVG.parse(fileURL: url) + self.init(dom: svg, options: options) + } catch { + XMLParser.logParsingError(for: error, filename: url.lastPathComponent, parsing: nil) + return nil + } + } + + public init?(named name: String, in bundle: Bundle = Bundle.main, options: SVG.Options = .default) { + guard let url = bundle.url(forResource: name, withExtension: nil) else { + return nil + } + + self.init(fileURL: url, options: options) + } + + public init?(data: Data, options: SVG.Options = .default) { + guard let svg = try? DOM.SVG.parse(data: data) else { + return nil + } + + self.init(dom: svg, options: options) + } + + public struct Options: OptionSet { + public let rawValue: Int + public init(rawValue: Int) { + self.rawValue = rawValue + } + + public static let hideUnsupportedFilters = Options(rawValue: 1 << 0) + + public static let `default`: Options = [] + } +} + +@available(*, unavailable, renamed: "SVG") +public enum Image { } + +extension SVG { + init(dom: DOM.SVG, options: Options) { self.size = CGSize(width: dom.width, height: dom.height) @@ -60,25 +102,11 @@ public final class SVG: NSObject { generator.renderCommands(for: layer) ) } - - public struct Options: OptionSet { - public let rawValue: Int - public init(rawValue: Int) { - self.rawValue = rawValue - } - - public static let hideUnsupportedFilters = Options(rawValue: 1 << 0) - - public static let `default`: Options = [] - } } -@available(*, unavailable, renamed: "SVG") -public enum Image { } - #else -public final class SVG: NSObject { +public struct SVG { public let size: CGSize init(dom: DOM.SVG, options: Options) { @@ -116,69 +144,3 @@ public extension SVG { } } #endif - -extension DOM.SVG { - - static func parse(fileURL url: URL, options: XMLParser.Options = .skipInvalidElements) throws -> DOM.SVG { - let element = try XML.SAXParser.parse(contentsOf: url) - let parser = XMLParser(options: options, filename: url.lastPathComponent) - return try parser.parseSVG(element) - } - - static func parse(data: Data, options: XMLParser.Options = .skipInvalidElements) throws -> DOM.SVG { - let element = try XML.SAXParser.parse(data: data) - let parser = XMLParser(options: options) - return try parser.parseSVG(element) - } -} - -public extension SVG { - - convenience init?(fileURL url: URL, options: SVG.Options = .default) { - do { - let svg = try DOM.SVG.parse(fileURL: url) - self.init(dom: svg, options: options) - } catch { - XMLParser.logParsingError(for: error, filename: url.lastPathComponent, parsing: nil) - return nil - } - } - - convenience init?(named name: String, in bundle: Bundle = Bundle.main, options: SVG.Options = .default) { - guard let url = bundle.url(forResource: name, withExtension: nil) else { - return nil - } - - self.init(fileURL: url, options: options) - } - - convenience init?(data: Data, options: SVG.Options = .default) { - guard let svg = try? DOM.SVG.parse(data: data) else { - return nil - } - - self.init(dom: svg, options: options) - } - - - struct Insets: Equatable { - public var top: CGFloat - public var left: CGFloat - public var bottom: CGFloat - public var right: CGFloat - - public init( - top: CGFloat = 0, - left: CGFloat = 0, - bottom: CGFloat = 0, - right: CGFloat = 0 - ) { - self.top = top - self.left = left - self.bottom = bottom - self.right = right - } - - public static let zero = Insets(top: 0, left: 0, bottom: 0, right: 0) - } -} diff --git a/SwiftDrawTests/SVGTests.swift b/SwiftDrawTests/SVGTests.swift index eaa184c..7d99468 100644 --- a/SwiftDrawTests/SVGTests.swift +++ b/SwiftDrawTests/SVGTests.swift @@ -32,6 +32,7 @@ import XCTest @testable import SwiftDraw +#if canImport(CoreGraphics) final class SVGTests: XCTestCase { func testValidSVGLoads() { @@ -46,7 +47,6 @@ final class SVGTests: XCTestCase { XCTAssertNil(SVG(named: "missing.svg", in: .test)) } -#if canImport(CoreGraphics) func testImageRasterizes() { let image = SVG.makeLines() let rendered = image.rasterize(scale: 1) @@ -71,7 +71,6 @@ final class SVGTests: XCTestCase { XCTAssertNoThrow(try image.jpegData()) XCTAssertNoThrow(try image.pdfData()) } -#endif #if canImport(UIKit) func testRasterize() { @@ -86,7 +85,6 @@ final class SVGTests: XCTestCase { XCTAssertEqual(reloaded.scale, 1) } #endif - } private extension SVG { @@ -98,3 +96,4 @@ private extension SVG { return SVG(dom: svg, options: .default) } } +#endif diff --git a/SwiftDrawTests/UIImage+ImageTests.swift b/SwiftDrawTests/UIImage+ImageTests.swift index 95440d9..d86bd58 100644 --- a/SwiftDrawTests/UIImage+ImageTests.swift +++ b/SwiftDrawTests/UIImage+ImageTests.swift @@ -74,8 +74,6 @@ final class UIImageTests: XCTestCase { } } -#endif - private extension SVG { static func parse(_ code: String) throws -> SVG { @@ -90,3 +88,5 @@ private extension SVG { var errorDescription: String? = "Invalid SVG" } } + +#endif