diff --git a/Art/images/data_circuit.png b/Art/images/data_circuit.png new file mode 100644 index 00000000..39943327 Binary files /dev/null and b/Art/images/data_circuit.png differ diff --git a/Art/paths.pcvd b/Art/paths.pcvd index 39c7fb9c..04621dfa 100644 Binary files a/Art/paths.pcvd and b/Art/paths.pcvd differ diff --git a/DSF_QRCode.podspec b/DSF_QRCode.podspec index b905e175..4ddb210f 100644 --- a/DSF_QRCode.podspec +++ b/DSF_QRCode.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'DSF_QRCode' -s.version = '20.4.2' +s.version = '20.5.0' s.summary = 'A simple drop-in macOS/iOS/tvOS/watchOS QR Code generator view for Swift, Objective-C and SwiftUI.' s.homepage = 'https://github.com/dagronf/QRCode' s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/README.md b/README.md index 5a4886bc..1ecc81cc 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,32 @@ The QRCode is made up of four distinct components The 'shape' represents the way that each of the components are drawn +#### 'OnPixels' shape + +The data shape represents how the 'pixels' within the QR code are displayed. By default, this is a simple square, +however you can supply a `PixelShape` object to custom-draw the data. There are built-in generators for a variety of styles. + +| Preview | Name | Class | Description | +|---|---|---|---| +| |"blob"|`QRCode.PixelShape.Blob`|A blobby style| +| |"circle"|`QRCode.PixelShape.Circle`|A basic circle pixel| +| |"circuit"|`QRCode.PixelShape.Circuit`|Circuits!| +| | "crt" |`QRCode.PixelShape.CRT`| A CRT shape | +| |"curvePixel"|`QRCode.PixelShape.CurvePixel`|A pixel that curves to follow paths| +| |"flower"|`QRCode.PixelShape.Flower`|A 'flower' style| +| |"horizontal"|`QRCode.PixelShape.Horizontal`|The pixels are horizonally joined to make continuous horizontal bars| +| |"pointy"|`QRCode.PixelShape.Pointy`|A 'pointy' style| +| |"razor"|`QRCode.PixelShape.Razor`| A 'razor' style| +| |"roundedEndIndent"|`QRCode.PixelShape.RoundedEndIndent`|Rounded path with circular indented ends| +| |"roundedPath"|`QRCode.PixelShape.RoundedPath`|A smooth rounded-edge path| +| |"roundedRect"|`QRCode.PixelShape.RoundedRect`|A basic rounded rectangle pixel with configurable radius| +| |"sharp"|`QRCode.PixelShape.Sharp`|A 'sharp' style| +| | "shiny" |`QRCode.PixelShape.Shiny` |A pixel style that appears 'shiny'| +| |"square"|`QRCode.PixelShape.Square`|A basic square pixel (default)| +| |"squircle"|`QRCode.PixelShape.Squircle`|A superellipse shape (somewhere between a square and a circle)| +| |"star"|`QRCode.PixelShape.Star`|A 'star' style| +| |"vertical"|`QRCode.PixelShape.Vertical`|The pixels are vertically joined to make continuous vertical bars| + #### Eye shape You can provide an `EyeShape` object to style just the eyes of the generated qr code. There are built-in generators for @@ -431,31 +457,6 @@ doc.design.style.onPixels = QRCode.FillStyle.Solid(0.624, 0.424, 0.400) -#### 'OnPixels' shape - -The data shape represents how the 'pixels' within the QR code are displayed. By default, this is a simple square, -however you can supply a `PixelShape` object to custom-draw the data. There are built-in generators for a variety of styles. - -| Preview | Name | Class | Description | -|---|---|---|---| -| |"blob"|`QRCode.PixelShape.Blob`|A blobby style| -| |"circle"|`QRCode.PixelShape.Circle`|A basic circle pixel| -| | "crt" |`QRCode.PixelShape.CRT`| A CRT shape | -| |"curvePixel"|`QRCode.PixelShape.CurvePixel`|A pixel that curves to follow paths| -| |"flower"|`QRCode.PixelShape.Flower`|A 'flower' style| -| |"horizontal"|`QRCode.PixelShape.Horizontal`|The pixels are horizonally joined to make continuous horizontal bars| -| |"pointy"|`QRCode.PixelShape.Pointy`|A 'pointy' style| -| |"razor"|`QRCode.PixelShape.Razor`| A 'razor' style| -| |"roundedEndIndent"|`QRCode.PixelShape.RoundedEndIndent`|Rounded path with circular indented ends| -| |"roundedPath"|`QRCode.PixelShape.RoundedPath`|A smooth rounded-edge path| -| |"roundedRect"|`QRCode.PixelShape.RoundedRect`|A basic rounded rectangle pixel with configurable radius| -| |"sharp"|`QRCode.PixelShape.Sharp`|A 'sharp' style| -| | "shiny" |`QRCode.PixelShape.Shiny` |A pixel style that appears 'shiny'| -| |"square"|`QRCode.PixelShape.Square`|A basic square pixel (default)| -| |"squircle"|`QRCode.PixelShape.Squircle`|A superellipse shape (somewhere between a square and a circle)| -| |"star"|`QRCode.PixelShape.Star`|A 'star' style| -| |"vertical"|`QRCode.PixelShape.Vertical`|The pixels are vertically joined to make continuous vertical bars| - #### 'offPixels' shape (optional) You can specify a shape to be drawn when a data 'pixel' is _off_. This can be used to make your qr code prettier. @@ -1150,9 +1151,9 @@ OPTIONS: --all-pixel-shapes Print all the available pixel shapes. -d, --on-pixel-shape - The onPixels shape to use. Available shapes are crt, circle, curvePixel, flower, horizontal, - pointy, razor, roundedEndIndent, roundedPath, roundedRect, sharp, shiny, square, squircle, - star, vertical. + The onPixels shape to use. Available shapes are blob, crt, circle, circuit, curvePixel, + flower, horizontal, pointy, razor, roundedEndIndent, roundedPath, roundedRect, sharp, shiny, + square, squircle, star, vertical. -n, --on-pixel-inset-fraction The spacing around each individual pixel in the onPixels section -r, --on-pixel-shape-corner-radius diff --git a/Sources/QRCode/styles/data/QRCodePixelShapeCircuit.swift b/Sources/QRCode/styles/data/QRCodePixelShapeCircuit.swift new file mode 100644 index 00000000..282ffa29 --- /dev/null +++ b/Sources/QRCode/styles/data/QRCodePixelShapeCircuit.swift @@ -0,0 +1,509 @@ +// +// QRCodePixelShapeCircuit.swift +// +// Copyright © 2024 Darren Ford. All rights reserved. +// +// MIT license +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial +// portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +import Foundation +import CoreGraphics + +public extension QRCode.PixelShape { + /// A generator for a pixel shape that displays connected circles + @objc(QRCodePixelShapeCircuit) class Circuit: NSObject, QRCodePixelShapeGenerator { + /// The generator name + @objc public static let Name: String = "circuit" + /// The generator title + @objc public static var Title: String { "Circuit" } + /// Create an instance of this path generator with the specified settings + @objc public static func Create(_ settings: [String: Any]?) -> any QRCodePixelShapeGenerator { Circuit() } + + /// Make a copy of the object + @objc public func copyShape() -> any QRCodePixelShapeGenerator { Circuit() } + } +} + +public extension QRCode.PixelShape.Circuit { + /// Generate a CGPath from the matrix contents + /// - Parameters: + /// - matrix: The matrix to generate + /// - size: The size of the resulting CGPath + /// - Returns: A path + @objc func generatePath(from matrix: BoolMatrix, size: CGSize) -> CGPath { + let dx = size.width / CGFloat(matrix.dimension) + let dy = size.height / CGFloat(matrix.dimension) + let dm = min(dx, dy) + + let xoff = (size.width - (CGFloat(matrix.dimension) * dm)) / 2.0 + let yoff = (size.height - (CGFloat(matrix.dimension) * dm)) / 2.0 + + // The scale required to convert our template paths to output path size + let w = QRCode.PixelShape.RoundedPath.DefaultSize.width + let scaleTransform = CGAffineTransform(scaleX: dm / w, y: dm / w) + + let path = CGMutablePath() + + for row in 0 ..< matrix.dimension { + for col in 0 ..< matrix.dimension { + let translate = CGAffineTransform(translationX: CGFloat(col) * dm + xoff, y: CGFloat(row) * dm + yoff) + let ne = Neighbours(matrix: matrix, row: row, col: col) + if matrix[row, col] == true { + + if ne.top, !ne.bottom, !ne.leading, !ne.trailing { + path.addPath(Self.templateBottom, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, ne.bottom, !ne.leading, !ne.trailing { + path.addPath(Self.templateTop, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, !ne.bottom, ne.leading, !ne.trailing { + path.addPath(Self.templateLeft, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, !ne.bottom, !ne.leading, ne.trailing { + path.addPath(Self.templateRight, transform: scaleTransform.concatenating(translate)) + } + + else if ne.top, ne.bottom, !ne.leading, !ne.trailing { + path.addPath(Self.templateTopBottom, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, !ne.bottom, ne.leading, ne.trailing { + path.addPath(Self.templateLeftRight, transform: scaleTransform.concatenating(translate)) + } + + else if ne.top, !ne.bottom, ne.leading, !ne.trailing { + path.addPath(Self.templateBottomLeft, transform: scaleTransform.concatenating(translate)) + } + else if ne.top, !ne.bottom, !ne.leading, ne.trailing { + path.addPath(Self.templateBottomRight, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, ne.bottom, ne.leading, !ne.trailing { + path.addPath(Self.templateTopLeft, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, ne.bottom, !ne.leading, ne.trailing { + path.addPath(Self.templateTopRight, transform: scaleTransform.concatenating(translate)) + } + + else if ne.top, !ne.bottom, ne.leading, ne.trailing { + path.addPath(Self.templateLeftBottomRight, transform: scaleTransform.concatenating(translate)) + } + else if !ne.top, ne.bottom, ne.leading, ne.trailing { + path.addPath(Self.templateTopLeftRight, transform: scaleTransform.concatenating(translate)) + } + else if ne.top, ne.bottom, !ne.leading, ne.trailing { + path.addPath(Self.templateTopRightBottom, transform: scaleTransform.concatenating(translate)) + } + else if ne.top, ne.bottom, ne.leading, !ne.trailing { + path.addPath(Self.templateTopLeftBottom, transform: scaleTransform.concatenating(translate)) + } + + else if ne.top, ne.bottom, ne.leading, ne.trailing { + path.addPath(Self.templateTopLeftBottomRight, transform: scaleTransform.concatenating(translate)) + } + + else { + path.addPath(Self.templateCentroid, transform: scaleTransform.concatenating(translate)) + } + } + } + } + path.closeSubpath() + return path + } +} + +// MARK: - Settings + +public extension QRCode.PixelShape.Circuit { + /// Does the shape generator support setting values for a particular key? + @objc func supportsSettingValue(forKey key: String) -> Bool { false } + /// Returns a storable representation of the shape handler + @objc func settings() -> [String: Any] { return [:] } + /// Set a configuration value for a particular setting string + @objc func setSettingValue(_ value: Any?, forKey key: String) -> Bool { false } +} + +// MARK: - Pixel creation conveniences + +public extension QRCodePixelShapeGenerator where Self == QRCode.PixelShape.Circuit { + /// Create a organic pixel generator + /// - Returns: A pixel generator + @inlinable static func circuit() -> QRCodePixelShapeGenerator { + QRCode.PixelShape.Circuit() + } +} + +// MARK: - Shapes + +// Inner corner templates + +private extension QRCode.PixelShape.Circuit { + static let templateCentroid = CGPath(ellipseIn: CGRect(x: 1, y: 1, width: 8, height: 8), transform: nil) + + static let templateTop = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.64, y: 8.01), controlPoint1: CGPoint(x: 6.85, y: 8.53), controlPoint2: CGPoint(x: 7.55, y: 8.07)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 7.27), controlPoint2: CGPoint(x: 9, y: 6.19)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 9, y: 2.79), controlPoint2: CGPoint(x: 7.21, y: 1)) + $0.curve(to: CGPoint(x: 2.94, y: 1.57), controlPoint1: CGPoint(x: 4.25, y: 1), controlPoint2: CGPoint(x: 3.54, y: 1.21)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 1.78, y: 2.27), controlPoint2: CGPoint(x: 1, y: 3.54)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 1, y: 6.19), controlPoint2: CGPoint(x: 1.52, y: 7.27)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.close() + } + + static let templateBottom = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 0)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 6.2, y: 0), controlPoint2: CGPoint(x: 6.15, y: 0.5)) + $0.curve(to: CGPoint(x: 7.64, y: 1.99), controlPoint1: CGPoint(x: 6.85, y: 1.47), controlPoint2: CGPoint(x: 7.55, y: 1.93)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 2.73), controlPoint2: CGPoint(x: 9, y: 3.81)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 9, y: 7.21), controlPoint2: CGPoint(x: 7.21, y: 9)) + $0.curve(to: CGPoint(x: 2.94, y: 8.43), controlPoint1: CGPoint(x: 4.25, y: 9), controlPoint2: CGPoint(x: 3.54, y: 8.79)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 1.78, y: 7.73), controlPoint2: CGPoint(x: 1, y: 6.46)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 1, y: 3.81), controlPoint2: CGPoint(x: 1.52, y: 2.73)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 2.41, y: 1.96), controlPoint2: CGPoint(x: 3.14, y: 1.48)) + $0.curve(to: CGPoint(x: 3.8, y: 0), controlPoint1: CGPoint(x: 3.85, y: 0.5), controlPoint2: CGPoint(x: 3.8, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.close() + } + + static let templateLeft = + CGPath.make { + $0.move(to: CGPoint(x: 0, y: 3.8)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 0, y: 3.8), controlPoint2: CGPoint(x: 0.5, y: 3.85)) + $0.curve(to: CGPoint(x: 1.99, y: 2.36), controlPoint1: CGPoint(x: 1.47, y: 3.15), controlPoint2: CGPoint(x: 1.93, y: 2.45)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 2.73, y: 1.52), controlPoint2: CGPoint(x: 3.81, y: 1)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 7.21, y: 1), controlPoint2: CGPoint(x: 9, y: 2.79)) + $0.curve(to: CGPoint(x: 8.43, y: 7.06), controlPoint1: CGPoint(x: 9, y: 5.75), controlPoint2: CGPoint(x: 8.79, y: 6.46)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 7.73, y: 8.22), controlPoint2: CGPoint(x: 6.46, y: 9)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 3.81, y: 9), controlPoint2: CGPoint(x: 2.73, y: 8.48)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 1.96, y: 7.59), controlPoint2: CGPoint(x: 1.48, y: 6.86)) + $0.curve(to: CGPoint(x: 0, y: 6.2), controlPoint1: CGPoint(x: 0.5, y: 6.15), controlPoint2: CGPoint(x: 0, y: 6.2)) + $0.line(to: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 3.8)) + $0.close() + } + + static let templateRight = + CGPath.make { + $0.move(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8.01, y: 2.36), controlPoint1: CGPoint(x: 8.53, y: 3.15), controlPoint2: CGPoint(x: 8.07, y: 2.45)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 7.27, y: 1.52), controlPoint2: CGPoint(x: 6.19, y: 1)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 2.79, y: 1), controlPoint2: CGPoint(x: 1, y: 2.79)) + $0.curve(to: CGPoint(x: 1.57, y: 7.06), controlPoint1: CGPoint(x: 1, y: 5.75), controlPoint2: CGPoint(x: 1.21, y: 6.46)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 2.27, y: 8.22), controlPoint2: CGPoint(x: 3.54, y: 9)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 6.19, y: 9), controlPoint2: CGPoint(x: 7.27, y: 8.48)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.close() + } + + // - + + static let templateTopBottom = + CGPath.make { + $0.move(to: CGPoint(x: 7.65, y: 2)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 7.59, y: 1.96), controlPoint2: CGPoint(x: 6.86, y: 1.48)) + $0.curve(to: CGPoint(x: 6.2, y: 0), controlPoint1: CGPoint(x: 6.15, y: 0.5), controlPoint2: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 3.8, y: 0)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 3.8, y: 0), controlPoint2: CGPoint(x: 3.85, y: 0.5)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 3.14, y: 1.48), controlPoint2: CGPoint(x: 2.41, y: 1.96)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 1.52, y: 2.73), controlPoint2: CGPoint(x: 1, y: 3.81)) + $0.curve(to: CGPoint(x: 1.57, y: 7.06), controlPoint1: CGPoint(x: 1, y: 5.75), controlPoint2: CGPoint(x: 1.21, y: 6.46)) + $0.curve(to: CGPoint(x: 2.08, y: 7.73), controlPoint1: CGPoint(x: 1.71, y: 7.3), controlPoint2: CGPoint(x: 1.89, y: 7.53)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 2.17, y: 7.83), controlPoint2: CGPoint(x: 2.26, y: 7.92)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.line(to: CGPoint(x: 3.54, y: 9.08)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.84, y: 9.55), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.65, y: 8), controlPoint1: CGPoint(x: 6.86, y: 8.52), controlPoint2: CGPoint(x: 7.59, y: 8.04)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 7.27), controlPoint2: CGPoint(x: 9, y: 6.19)) + $0.curve(to: CGPoint(x: 7.65, y: 2), controlPoint1: CGPoint(x: 9, y: 3.81), controlPoint2: CGPoint(x: 8.48, y: 2.73)) + $0.close() + } + + static let templateLeftRight = + CGPath.make { + $0.move(to: CGPoint(x: 8, y: 7.65)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 8.52, y: 3.14), controlPoint2: CGPoint(x: 8.04, y: 2.41)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 7.27, y: 1.52), controlPoint2: CGPoint(x: 6.19, y: 1)) + $0.curve(to: CGPoint(x: 2.94, y: 1.57), controlPoint1: CGPoint(x: 4.25, y: 1), controlPoint2: CGPoint(x: 3.54, y: 1.21)) + $0.curve(to: CGPoint(x: 2.27, y: 2.08), controlPoint1: CGPoint(x: 2.7, y: 1.71), controlPoint2: CGPoint(x: 2.47, y: 1.89)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 2.17, y: 2.17), controlPoint2: CGPoint(x: 2.08, y: 2.26)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 1.96, y: 2.41), controlPoint2: CGPoint(x: 1.48, y: 3.14)) + $0.line(to: CGPoint(x: 0.92, y: 3.54)) + $0.curve(to: CGPoint(x: 0, y: 3.8), controlPoint1: CGPoint(x: 0.45, y: 3.84), controlPoint2: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 6.2)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 0, y: 6.2), controlPoint2: CGPoint(x: 0.5, y: 6.15)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 1.48, y: 6.86), controlPoint2: CGPoint(x: 1.96, y: 7.59)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 2.73, y: 8.48), controlPoint2: CGPoint(x: 3.81, y: 9)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 6.19, y: 9), controlPoint2: CGPoint(x: 7.27, y: 8.48)) + $0.close() + } + + // - + + static let templateTopLeftRight = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.64, y: 8.01), controlPoint1: CGPoint(x: 6.85, y: 8.53), controlPoint2: CGPoint(x: 7.55, y: 8.07)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 7.77, y: 7.89), controlPoint2: CGPoint(x: 7.89, y: 7.77)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 8.52, y: 3.14), controlPoint2: CGPoint(x: 8.04, y: 2.41)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 7.27, y: 1.52), controlPoint2: CGPoint(x: 6.19, y: 1)) + $0.curve(to: CGPoint(x: 2.94, y: 1.57), controlPoint1: CGPoint(x: 4.25, y: 1), controlPoint2: CGPoint(x: 3.54, y: 1.21)) + $0.curve(to: CGPoint(x: 2.27, y: 2.08), controlPoint1: CGPoint(x: 2.7, y: 1.71), controlPoint2: CGPoint(x: 2.47, y: 1.89)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 2.17, y: 2.17), controlPoint2: CGPoint(x: 2.08, y: 2.26)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 1.96, y: 2.41), controlPoint2: CGPoint(x: 1.48, y: 3.14)) + $0.line(to: CGPoint(x: 0.92, y: 3.54)) + $0.curve(to: CGPoint(x: 0, y: 3.8), controlPoint1: CGPoint(x: 0.45, y: 3.84), controlPoint2: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 6.2)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 0, y: 6.2), controlPoint2: CGPoint(x: 0.5, y: 6.15)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 1.48, y: 6.86), controlPoint2: CGPoint(x: 1.96, y: 7.59)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 2.11, y: 7.77), controlPoint2: CGPoint(x: 2.23, y: 7.89)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.close() + } + + static let templateLeftBottomRight = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 0)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 6.2, y: 0), controlPoint2: CGPoint(x: 6.15, y: 0.5)) + $0.curve(to: CGPoint(x: 7.64, y: 1.99), controlPoint1: CGPoint(x: 6.85, y: 1.47), controlPoint2: CGPoint(x: 7.55, y: 1.93)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 7.77, y: 2.11), controlPoint2: CGPoint(x: 7.89, y: 2.23)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 8.04, y: 2.41), controlPoint2: CGPoint(x: 8.52, y: 3.14)) + $0.curve(to: CGPoint(x: 10, y: 3.8), controlPoint1: CGPoint(x: 9.5, y: 3.85), controlPoint2: CGPoint(x: 10, y: 3.8)) + $0.line(to: CGPoint(x: 10, y: 6.2)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 10, y: 6.2), controlPoint2: CGPoint(x: 9.5, y: 6.15)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 8.52, y: 6.86), controlPoint2: CGPoint(x: 8.04, y: 7.59)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 7.27, y: 8.48), controlPoint2: CGPoint(x: 6.19, y: 9)) + $0.curve(to: CGPoint(x: 2.94, y: 8.43), controlPoint1: CGPoint(x: 4.25, y: 9), controlPoint2: CGPoint(x: 3.54, y: 8.79)) + $0.curve(to: CGPoint(x: 2.27, y: 7.92), controlPoint1: CGPoint(x: 2.7, y: 8.29), controlPoint2: CGPoint(x: 2.47, y: 8.11)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 2.17, y: 7.83), controlPoint2: CGPoint(x: 2.08, y: 7.74)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 1.96, y: 7.59), controlPoint2: CGPoint(x: 1.48, y: 6.86)) + $0.line(to: CGPoint(x: 0.92, y: 6.46)) + $0.curve(to: CGPoint(x: 0, y: 6.2), controlPoint1: CGPoint(x: 0.45, y: 6.16), controlPoint2: CGPoint(x: 0, y: 6.2)) + $0.line(to: CGPoint(x: 0, y: 3.8)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 0, y: 3.8), controlPoint2: CGPoint(x: 0.5, y: 3.85)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 1.48, y: 3.14), controlPoint2: CGPoint(x: 1.96, y: 2.41)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 2.11, y: 2.23), controlPoint2: CGPoint(x: 2.23, y: 2.11)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 2.41, y: 1.96), controlPoint2: CGPoint(x: 3.14, y: 1.48)) + $0.curve(to: CGPoint(x: 3.8, y: 0), controlPoint1: CGPoint(x: 3.85, y: 0.5), controlPoint2: CGPoint(x: 3.8, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.close() + } + + static let templateTopRightBottom = + CGPath.make { + $0.move(to: CGPoint(x: 10, y: 6.2)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 10, y: 6.2), controlPoint2: CGPoint(x: 9.5, y: 6.15)) + $0.curve(to: CGPoint(x: 8.01, y: 7.64), controlPoint1: CGPoint(x: 8.53, y: 6.85), controlPoint2: CGPoint(x: 8.07, y: 7.55)) + $0.curve(to: CGPoint(x: 7.65, y: 8), controlPoint1: CGPoint(x: 7.89, y: 7.77), controlPoint2: CGPoint(x: 7.77, y: 7.89)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 7.59, y: 8.04), controlPoint2: CGPoint(x: 6.86, y: 8.52)) + $0.curve(to: CGPoint(x: 6.2, y: 10), controlPoint1: CGPoint(x: 6.15, y: 9.5), controlPoint2: CGPoint(x: 6.2, y: 10)) + $0.line(to: CGPoint(x: 3.8, y: 10)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 3.8, y: 10), controlPoint2: CGPoint(x: 3.85, y: 9.5)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 3.14, y: 8.52), controlPoint2: CGPoint(x: 2.41, y: 8.04)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 1.52, y: 7.27), controlPoint2: CGPoint(x: 1, y: 6.19)) + $0.curve(to: CGPoint(x: 1.57, y: 2.94), controlPoint1: CGPoint(x: 1, y: 4.25), controlPoint2: CGPoint(x: 1.21, y: 3.54)) + $0.curve(to: CGPoint(x: 2.08, y: 2.27), controlPoint1: CGPoint(x: 1.71, y: 2.7), controlPoint2: CGPoint(x: 1.89, y: 2.47)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 2.17, y: 2.17), controlPoint2: CGPoint(x: 2.26, y: 2.08)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 2.41, y: 1.96), controlPoint2: CGPoint(x: 3.14, y: 1.48)) + $0.line(to: CGPoint(x: 3.54, y: 0.92)) + $0.curve(to: CGPoint(x: 3.8, y: 0), controlPoint1: CGPoint(x: 3.84, y: 0.45), controlPoint2: CGPoint(x: 3.8, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 6.2, y: 0), controlPoint2: CGPoint(x: 6.15, y: 0.5)) + $0.curve(to: CGPoint(x: 7.65, y: 2), controlPoint1: CGPoint(x: 6.86, y: 1.48), controlPoint2: CGPoint(x: 7.59, y: 1.96)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 7.77, y: 2.11), controlPoint2: CGPoint(x: 7.89, y: 2.23)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 8.04, y: 2.41), controlPoint2: CGPoint(x: 8.52, y: 3.14)) + $0.curve(to: CGPoint(x: 10, y: 3.8), controlPoint1: CGPoint(x: 9.5, y: 3.85), controlPoint2: CGPoint(x: 10, y: 3.8)) + $0.line(to: CGPoint(x: 10, y: 6.2)) + $0.close() + } + + static let templateTopLeftBottom = + CGPath.make { + $0.move(to: CGPoint(x: 0, y: 6.2)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 0, y: 6.2), controlPoint2: CGPoint(x: 0.5, y: 6.15)) + $0.curve(to: CGPoint(x: 1.99, y: 7.64), controlPoint1: CGPoint(x: 1.47, y: 6.85), controlPoint2: CGPoint(x: 1.93, y: 7.55)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 2.11, y: 7.77), controlPoint2: CGPoint(x: 2.23, y: 7.89)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.65, y: 8), controlPoint1: CGPoint(x: 6.86, y: 8.52), controlPoint2: CGPoint(x: 7.59, y: 8.04)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 7.27), controlPoint2: CGPoint(x: 9, y: 6.19)) + $0.curve(to: CGPoint(x: 8.43, y: 2.94), controlPoint1: CGPoint(x: 9, y: 4.25), controlPoint2: CGPoint(x: 8.79, y: 3.54)) + $0.curve(to: CGPoint(x: 7.92, y: 2.27), controlPoint1: CGPoint(x: 8.29, y: 2.7), controlPoint2: CGPoint(x: 8.11, y: 2.47)) + $0.curve(to: CGPoint(x: 7.65, y: 2), controlPoint1: CGPoint(x: 7.83, y: 2.17), controlPoint2: CGPoint(x: 7.74, y: 2.08)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 7.59, y: 1.96), controlPoint2: CGPoint(x: 6.86, y: 1.48)) + $0.line(to: CGPoint(x: 6.46, y: 0.92)) + $0.curve(to: CGPoint(x: 6.2, y: 0), controlPoint1: CGPoint(x: 6.16, y: 0.45), controlPoint2: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 3.8, y: 0)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 3.8, y: 0), controlPoint2: CGPoint(x: 3.85, y: 0.5)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 3.14, y: 1.48), controlPoint2: CGPoint(x: 2.41, y: 1.96)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 2.23, y: 2.11), controlPoint2: CGPoint(x: 2.11, y: 2.23)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 1.96, y: 2.41), controlPoint2: CGPoint(x: 1.48, y: 3.14)) + $0.curve(to: CGPoint(x: 0, y: 3.8), controlPoint1: CGPoint(x: 0.5, y: 3.85), controlPoint2: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 6.2)) + $0.close() + } + + + // - + + static let templateTopLeftBottomRight = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.64, y: 8.01), controlPoint1: CGPoint(x: 6.85, y: 8.53), controlPoint2: CGPoint(x: 7.55, y: 8.07)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 7.77, y: 7.89), controlPoint2: CGPoint(x: 7.89, y: 7.77)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 8.52, y: 3.14), controlPoint2: CGPoint(x: 8.04, y: 2.41)) + $0.curve(to: CGPoint(x: 7.65, y: 2), controlPoint1: CGPoint(x: 7.89, y: 2.23), controlPoint2: CGPoint(x: 7.77, y: 2.11)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 7.59, y: 1.96), controlPoint2: CGPoint(x: 6.86, y: 1.48)) + $0.curve(to: CGPoint(x: 6.2, y: 0), controlPoint1: CGPoint(x: 6.15, y: 0.5), controlPoint2: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 3.8, y: 0)) + $0.curve(to: CGPoint(x: 3.54, y: 0.92), controlPoint1: CGPoint(x: 3.8, y: 0), controlPoint2: CGPoint(x: 3.84, y: 0.45)) + $0.line(to: CGPoint(x: 3.49, y: 1)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 3.14, y: 1.48), controlPoint2: CGPoint(x: 2.41, y: 1.96)) + $0.curve(to: CGPoint(x: 2.27, y: 2.08), controlPoint1: CGPoint(x: 2.35, y: 2), controlPoint2: CGPoint(x: 2.27, y: 2.08)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 2.17, y: 2.17), controlPoint2: CGPoint(x: 2.08, y: 2.26)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 1.96, y: 2.41), controlPoint2: CGPoint(x: 1.48, y: 3.14)) + $0.curve(to: CGPoint(x: 0, y: 3.8), controlPoint1: CGPoint(x: 0.5, y: 3.85), controlPoint2: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 6.2)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 0, y: 6.2), controlPoint2: CGPoint(x: 0.5, y: 6.15)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 1.48, y: 6.86), controlPoint2: CGPoint(x: 1.96, y: 7.59)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 2.11, y: 7.77), controlPoint2: CGPoint(x: 2.23, y: 7.89)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.close() + } + + // - + + static let templateTopLeft = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.64, y: 8.01), controlPoint1: CGPoint(x: 6.85, y: 8.53), controlPoint2: CGPoint(x: 7.55, y: 8.07)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 7.27), controlPoint2: CGPoint(x: 9, y: 6.19)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 9, y: 2.79), controlPoint2: CGPoint(x: 7.21, y: 1)) + $0.curve(to: CGPoint(x: 2.94, y: 1.57), controlPoint1: CGPoint(x: 4.25, y: 1), controlPoint2: CGPoint(x: 3.54, y: 1.21)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 2.59, y: 1.78), controlPoint2: CGPoint(x: 2.27, y: 2.05)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 1.96, y: 2.41), controlPoint2: CGPoint(x: 1.48, y: 3.14)) + $0.curve(to: CGPoint(x: 0, y: 3.8), controlPoint1: CGPoint(x: 0.5, y: 3.85), controlPoint2: CGPoint(x: 0, y: 3.8)) + $0.line(to: CGPoint(x: 0, y: 6.2)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 0, y: 6.2), controlPoint2: CGPoint(x: 0.5, y: 6.15)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 1.48, y: 6.86), controlPoint2: CGPoint(x: 1.96, y: 7.59)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 2.11, y: 7.77), controlPoint2: CGPoint(x: 2.23, y: 7.89)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.close() + } + + static let templateTopRight = + CGPath.make { + $0.move(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8.01, y: 2.36), controlPoint1: CGPoint(x: 8.53, y: 3.15), controlPoint2: CGPoint(x: 8.07, y: 2.45)) + $0.curve(to: CGPoint(x: 5, y: 1), controlPoint1: CGPoint(x: 7.27, y: 1.52), controlPoint2: CGPoint(x: 6.19, y: 1)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 2.79, y: 1), controlPoint2: CGPoint(x: 1, y: 2.79)) + $0.curve(to: CGPoint(x: 1.57, y: 7.06), controlPoint1: CGPoint(x: 1, y: 5.75), controlPoint2: CGPoint(x: 1.21, y: 6.46)) + $0.curve(to: CGPoint(x: 2.35, y: 8), controlPoint1: CGPoint(x: 1.78, y: 7.41), controlPoint2: CGPoint(x: 2.05, y: 7.73)) + $0.curve(to: CGPoint(x: 3.49, y: 9), controlPoint1: CGPoint(x: 2.41, y: 8.04), controlPoint2: CGPoint(x: 3.14, y: 8.52)) + $0.curve(to: CGPoint(x: 3.8, y: 10), controlPoint1: CGPoint(x: 3.85, y: 9.5), controlPoint2: CGPoint(x: 3.8, y: 10)) + $0.line(to: CGPoint(x: 6.2, y: 10)) + $0.curve(to: CGPoint(x: 6.51, y: 9), controlPoint1: CGPoint(x: 6.2, y: 10), controlPoint2: CGPoint(x: 6.15, y: 9.5)) + $0.curve(to: CGPoint(x: 7.65, y: 8), controlPoint1: CGPoint(x: 6.86, y: 8.52), controlPoint2: CGPoint(x: 7.59, y: 8.04)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 7.77, y: 7.89), controlPoint2: CGPoint(x: 7.89, y: 7.77)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.close() + } + + static let templateBottomLeft = + CGPath.make { + $0.move(to: CGPoint(x: 6.2, y: 0)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 6.2, y: 0), controlPoint2: CGPoint(x: 6.15, y: 0.5)) + $0.curve(to: CGPoint(x: 7.64, y: 1.99), controlPoint1: CGPoint(x: 6.85, y: 1.47), controlPoint2: CGPoint(x: 7.55, y: 1.93)) + $0.curve(to: CGPoint(x: 9, y: 5), controlPoint1: CGPoint(x: 8.48, y: 2.73), controlPoint2: CGPoint(x: 9, y: 3.81)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 9, y: 7.21), controlPoint2: CGPoint(x: 7.21, y: 9)) + $0.curve(to: CGPoint(x: 2.94, y: 8.43), controlPoint1: CGPoint(x: 4.25, y: 9), controlPoint2: CGPoint(x: 3.54, y: 8.79)) + $0.curve(to: CGPoint(x: 2, y: 7.65), controlPoint1: CGPoint(x: 2.59, y: 8.22), controlPoint2: CGPoint(x: 2.27, y: 7.95)) + $0.curve(to: CGPoint(x: 1, y: 6.51), controlPoint1: CGPoint(x: 1.96, y: 7.59), controlPoint2: CGPoint(x: 1.48, y: 6.86)) + $0.curve(to: CGPoint(x: 0, y: 6.2), controlPoint1: CGPoint(x: 0.5, y: 6.15), controlPoint2: CGPoint(x: 0, y: 6.2)) + $0.line(to: CGPoint(x: 0, y: 3.8)) + $0.curve(to: CGPoint(x: 1, y: 3.49), controlPoint1: CGPoint(x: 0, y: 3.8), controlPoint2: CGPoint(x: 0.5, y: 3.85)) + $0.curve(to: CGPoint(x: 2, y: 2.35), controlPoint1: CGPoint(x: 1.48, y: 3.14), controlPoint2: CGPoint(x: 1.96, y: 2.41)) + $0.curve(to: CGPoint(x: 2.35, y: 2), controlPoint1: CGPoint(x: 2.11, y: 2.23), controlPoint2: CGPoint(x: 2.23, y: 2.11)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 2.41, y: 1.96), controlPoint2: CGPoint(x: 3.14, y: 1.48)) + $0.curve(to: CGPoint(x: 3.8, y: 0), controlPoint1: CGPoint(x: 3.85, y: 0.5), controlPoint2: CGPoint(x: 3.8, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 6.2, y: 0)) + $0.close() + } + + static let templateBottomRight = + CGPath.make { + $0.move(to: CGPoint(x: 3.8, y: 0)) + $0.curve(to: CGPoint(x: 3.49, y: 1), controlPoint1: CGPoint(x: 3.8, y: 0), controlPoint2: CGPoint(x: 3.85, y: 0.5)) + $0.curve(to: CGPoint(x: 2.36, y: 1.99), controlPoint1: CGPoint(x: 3.15, y: 1.47), controlPoint2: CGPoint(x: 2.45, y: 1.93)) + $0.curve(to: CGPoint(x: 1, y: 5), controlPoint1: CGPoint(x: 1.52, y: 2.73), controlPoint2: CGPoint(x: 1, y: 3.81)) + $0.curve(to: CGPoint(x: 5, y: 9), controlPoint1: CGPoint(x: 1, y: 7.21), controlPoint2: CGPoint(x: 2.79, y: 9)) + $0.curve(to: CGPoint(x: 7.06, y: 8.43), controlPoint1: CGPoint(x: 5.75, y: 9), controlPoint2: CGPoint(x: 6.46, y: 8.79)) + $0.curve(to: CGPoint(x: 8, y: 7.65), controlPoint1: CGPoint(x: 7.41, y: 8.22), controlPoint2: CGPoint(x: 7.73, y: 7.95)) + $0.curve(to: CGPoint(x: 9, y: 6.51), controlPoint1: CGPoint(x: 8.04, y: 7.59), controlPoint2: CGPoint(x: 8.52, y: 6.86)) + $0.curve(to: CGPoint(x: 10, y: 6.2), controlPoint1: CGPoint(x: 9.5, y: 6.15), controlPoint2: CGPoint(x: 10, y: 6.2)) + $0.line(to: CGPoint(x: 10, y: 3.8)) + $0.curve(to: CGPoint(x: 9, y: 3.49), controlPoint1: CGPoint(x: 10, y: 3.8), controlPoint2: CGPoint(x: 9.5, y: 3.85)) + $0.curve(to: CGPoint(x: 8, y: 2.35), controlPoint1: CGPoint(x: 8.52, y: 3.14), controlPoint2: CGPoint(x: 8.04, y: 2.41)) + $0.curve(to: CGPoint(x: 7.65, y: 2), controlPoint1: CGPoint(x: 7.89, y: 2.23), controlPoint2: CGPoint(x: 7.77, y: 2.11)) + $0.curve(to: CGPoint(x: 6.51, y: 1), controlPoint1: CGPoint(x: 7.59, y: 1.96), controlPoint2: CGPoint(x: 6.86, y: 1.48)) + $0.curve(to: CGPoint(x: 6.2, y: 0), controlPoint1: CGPoint(x: 6.15, y: 0.5), controlPoint2: CGPoint(x: 6.2, y: 0)) + $0.line(to: CGPoint(x: 3.8, y: 0)) + $0.line(to: CGPoint(x: 3.8, y: 0)) + $0.close() + } +} diff --git a/Sources/QRCode/styles/data/QRCodePixelShapeFactory.swift b/Sources/QRCode/styles/data/QRCodePixelShapeFactory.swift index 1ac1da9a..ed7f31e9 100644 --- a/Sources/QRCode/styles/data/QRCodePixelShapeFactory.swift +++ b/Sources/QRCode/styles/data/QRCodePixelShapeFactory.swift @@ -80,6 +80,7 @@ import Foundation QRCode.PixelShape.Shiny.self, QRCode.PixelShape.CRT.self, QRCode.PixelShape.Blob.self, + QRCode.PixelShape.Circuit.self, ].sorted(by: { a, b in a.Title < b.Title }) /// The default matrix to use when generating pixel sample images diff --git a/Tests/QRCodeTests/QRCodeDocGenerator.swift b/Tests/QRCodeTests/QRCodeDocGenerator.swift index 3a7ced16..e5e5248a 100644 --- a/Tests/QRCodeTests/QRCodeDocGenerator.swift +++ b/Tests/QRCodeTests/QRCodeDocGenerator.swift @@ -92,8 +92,8 @@ final class QRCodeDocGeneratorTests: XCTestCase { markdownText += "### Samples\n\n" - markdownText += "| | L | M | Q | H | SVG | neg |\n" - markdownText += "|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|\n" + markdownText += "| | L | M | Q | H | SVG | PDF | neg |\n" + markdownText += "|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|\n" doc.design.style.onPixels = .solid(0.6, 0, 0) doc.design.style.eye = .solid(0, 0, 0) @@ -127,6 +127,13 @@ final class QRCodeDocGeneratorTests: XCTestCase { markdownText += "
⚖️|" } + do { + let pdf = try doc.pdfData(dimension: dimension) + let filename = "pixelint - \(name).pdf" + let link = try imageStore.store(pdf, filename: filename) + markdownText += "
⚖️|" + } + do { doc.design.shape.negatedOnPixelsOnly = true let inverted = try doc.pdfData(dimension: dimension) @@ -148,8 +155,8 @@ final class QRCodeDocGeneratorTests: XCTestCase { markdownText += "## Pixel Shapes (3rd party Generator)\n\n" - markdownText += "| | L | M | Q | H | SVG | neg |\n" - markdownText += "|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|\n" + markdownText += "| | L | M | Q | H | SVG | PDF | neg |\n" + markdownText += "|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|\n" let names = QRCodePixelShapeFactory.shared.availableGeneratorNames.sorted() for name in names { @@ -178,6 +185,14 @@ final class QRCodeDocGeneratorTests: XCTestCase { let link = try imageStore.store(svgImage, filename: filename) markdownText += "
⚖️|" } + + do { + let pdf = try doc.pdfData(dimension: dimension) + let filename = "pixelext - \(name).pdf" + let link = try imageStore.store(pdf, filename: filename) + markdownText += "
⚖️|" + } + do { doc.design.shape.negatedOnPixelsOnly = true let inverted = try doc.pdfData(dimension: dimension)