Skip to content

Commit 177d409

Browse files
committed
Added hole punch eye style
1 parent fcbc594 commit 177d409

File tree

6 files changed

+85
-1
lines changed

6 files changed

+85
-1
lines changed

Art/images/eye_holePunch.png

1.46 KB
Loading

Art/qrcode-designs.pcvd

6.94 KB
Binary file not shown.

Documentation/shape-configuration/eye-styles.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
| <a href="../../Art/images/eye_fireball.png"><img src="../../Art/images/eye_fireball.png" width="75" /></a> | __fireball__ | `QRCode.EyeShape.Fireball` | _none_ |
2020
| <a href="../../Art/images/eye_flame.png"><img src="../../Art/images/eye_flame.png" width="75" /></a> | __flame__ | `QRCode.EyeShape.Flame` | _none_ |
2121
| <a href="../../Art/images/eye_headlight.png"><img src="../../Art/images/eye_headlight.png" width="75" /></a> | __headlight__ | `QRCode.EyeShape.Headlight` |__Flippable__<br/> |
22+
| <a href="../../Art/images/eye_holePunch.png"><img src="../../Art/images/eye_holePunch.png" width="75" /></a> | __holePunch__ | `QRCode.EyeShape.HolePunch` | _none_ |
2223
| <a href="../../Art/images/eye_leaf.png"><img src="../../Art/images/eye_leaf.png" width="75" /></a> | __leaf__ | `QRCode.EyeShape.Leaf` | _none_ |
2324
| <a href="../../Art/images/eye_peacock.png"><img src="../../Art/images/eye_peacock.png" width="75" /></a> | __peacock__ | `QRCode.EyeShape.Peacock` | _none_ |
2425
| <a href="../../Art/images/eye_pinch.png"><img src="../../Art/images/eye_pinch.png" width="75" /></a> | __pinch__ | `QRCode.EyeShape.Pinch` | _none_ |

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ however you can supply a `PixelShape` object to custom-draw the data. There are
363363
You can provide an `EyeShape` object to style just the eyes of the generated qr code. There are built-in generators for
364364
square, circle, rounded rectangle, and more.
365365

366-
<img src="./Art/images/eye_barsHorizontal.png" width="60" title="Horizontal bars" /> <img src="./Art/images/eye_barsVertical.png" width="60" title="Vertical bars" /> <img src="./Art/images/eye_circle.png" width="60" title="Circle" /> <img src="./Art/images/eye_cloud.png" width="60" title="Cloud" /> <img src="./Art/images/eye_cloudCircle.png" width="60" title="Cloud Circle" /> <img src="./Art/images/eye_corneredPixels.png" width="60" title="Cornered pixels" /> <img src="./Art/images/eye_crt.png" width="60" title="CRT" /> <img src="./Art/images/eye_diagonalStripes.png" width="60" title="Diagonal Stripes" /> <img src="./Art/images/eye_dotDragHorizontal.png" width="60" title="Dot Drag Horizontal" /> <img src="./Art/images/eye_dotDragVertical.png" width="60" title="Dot Drag Vertical" /> <img src="./Art/images/eye_edges.png" width="60" title="Edges" /> <img src="./Art/images/eye_explode.png" width="60" title="Explode" /> <img src="./Art/images/eye_eye.png" width="60" title="Eye" /> <img src="./Art/images/eye_fabricScissors.png" width="60" title="Fabric Scissors" /> <img src="./Art/images/eye_fireball.png" width="60" title="Fireball" /> <img src="./Art/images/eye_flame.png" width="60" title="Flame" /> <img src="./Art/images/eye_headlight.png" width="60" title="Headlight" /> <img src="./Art/images/eye_leaf.png" width="60" title="Leaf" /> <img src="./Art/images/eye_peacock.png" width="60" title="Peacock" /> <img src="./Art/images/eye_pinch.png" width="60" title="Pinch" /> <img src="./Art/images/eye_pixels.png" width="60" title="Pixels" /> <img src="./Art/images/eye_roundedOuter.png" width="60" title="Rounded outer" /> <img src="./Art/images/eye_roundedPointingIn.png" width="60" title="Rounded Pointing In" /> <img src="./Art/images/eye_roundedPointingOut.png" width="60" title="Rounded pointing out" /> <img src="./Art/images/eye_roundedRect.png" width="60" title="Rounded rectangle" /> <img src="./Art/images/eye_shield.png" width="60" title="Shield" /> <img src="./Art/images/eye_spikyCircle.png" width="60" title="Spiky Circle" /> <img src="./Art/images/eye_square.png" width="60" title="Square" /> <img src="./Art/images/eye_squarePeg.png" width="60" title="Square Peg" /> <img src="./Art/images/eye_squircle.png" width="60" title="Squircle" /> <img src="./Art/images/eye_surroundingBars.png" width="60" title="Surrounding bars" /> <img src="./Art/images/eye_teardrop.png" width="60" title="Teardrop" /> <img src="./Art/images/eye_ufo.png" width="60" title="UFO" /> <img src="./Art/images/eye_ufoRounded.png" width="60" title="UFO Rounded" /> <img src="./Art/images/eye_usePixelShape.png" width="60" title="Use Pixel Shape" />
366+
<img src="./Art/images/eye_barsHorizontal.png" width="60" title="Horizontal bars" /> <img src="./Art/images/eye_barsVertical.png" width="60" title="Vertical bars" /> <img src="./Art/images/eye_circle.png" width="60" title="Circle" /> <img src="./Art/images/eye_cloud.png" width="60" title="Cloud" /> <img src="./Art/images/eye_cloudCircle.png" width="60" title="Cloud Circle" /> <img src="./Art/images/eye_corneredPixels.png" width="60" title="Cornered pixels" /> <img src="./Art/images/eye_crt.png" width="60" title="CRT" /> <img src="./Art/images/eye_diagonalStripes.png" width="60" title="Diagonal Stripes" /> <img src="./Art/images/eye_dotDragHorizontal.png" width="60" title="Dot Drag Horizontal" /> <img src="./Art/images/eye_dotDragVertical.png" width="60" title="Dot Drag Vertical" /> <img src="./Art/images/eye_edges.png" width="60" title="Edges" /> <img src="./Art/images/eye_explode.png" width="60" title="Explode" /> <img src="./Art/images/eye_eye.png" width="60" title="Eye" /> <img src="./Art/images/eye_fabricScissors.png" width="60" title="Fabric Scissors" /> <img src="./Art/images/eye_fireball.png" width="60" title="Fireball" /> <img src="./Art/images/eye_flame.png" width="60" title="Flame" /> <img src="./Art/images/eye_headlight.png" width="60" title="Headlight" /> <img src="./Art/images/eye_holePunch.png" width="60" title="Hole Punch" /> <img src="./Art/images/eye_leaf.png" width="60" title="Leaf" /> <img src="./Art/images/eye_peacock.png" width="60" title="Peacock" /> <img src="./Art/images/eye_pinch.png" width="60" title="Pinch" /> <img src="./Art/images/eye_pixels.png" width="60" title="Pixels" /> <img src="./Art/images/eye_roundedOuter.png" width="60" title="Rounded outer" /> <img src="./Art/images/eye_roundedPointingIn.png" width="60" title="Rounded Pointing In" /> <img src="./Art/images/eye_roundedPointingOut.png" width="60" title="Rounded pointing out" /> <img src="./Art/images/eye_roundedRect.png" width="60" title="Rounded rectangle" /> <img src="./Art/images/eye_shield.png" width="60" title="Shield" /> <img src="./Art/images/eye_spikyCircle.png" width="60" title="Spiky Circle" /> <img src="./Art/images/eye_square.png" width="60" title="Square" /> <img src="./Art/images/eye_squarePeg.png" width="60" title="Square Peg" /> <img src="./Art/images/eye_squircle.png" width="60" title="Squircle" /> <img src="./Art/images/eye_surroundingBars.png" width="60" title="Surrounding bars" /> <img src="./Art/images/eye_teardrop.png" width="60" title="Teardrop" /> <img src="./Art/images/eye_ufo.png" width="60" title="UFO" /> <img src="./Art/images/eye_ufoRounded.png" width="60" title="UFO Rounded" /> <img src="./Art/images/eye_usePixelShape.png" width="60" title="Use Pixel Shape" />
367367

368368
[Eye style configuration options](./Documentation/shape-configuration/eye-styles.md)
369369

Sources/QRCode/styles/eye/QRCodeEyeShapeFactory.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import Foundation
9898
QRCode.EyeShape.DiagonalStripes.self,
9999
QRCode.EyeShape.Flame.self,
100100
QRCode.EyeShape.CloudCircle.self,
101+
QRCode.EyeShape.HolePunch.self,
101102
].sorted(by: { a, b in a.Title < b.Title })
102103
}
103104

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// Copyright © 2025 Darren Ford. All rights reserved.
3+
//
4+
// MIT license
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7+
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
8+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9+
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in all copies or substantial
12+
// portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
15+
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
16+
// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18+
//
19+
20+
import CoreGraphics
21+
import Foundation
22+
23+
public extension QRCode.EyeShape {
24+
@objc(QRCodeEyeShapeHolePunch) class HolePunch: NSObject, QRCodeEyeShapeGenerator {
25+
@objc public static let Name = "holePunch"
26+
@objc public static var Title: String { "Hole Punch" }
27+
@objc public static func Create(_ settings: [String: Any]?) -> any QRCodeEyeShapeGenerator { HolePunch() }
28+
29+
@objc public func settings() -> [String: Any] { return [:] }
30+
@objc public func supportsSettingValue(forKey key: String) -> Bool { false }
31+
@objc public func setSettingValue(_ value: Any?, forKey key: String) -> Bool { false }
32+
33+
/// Make a copy of this shape generator
34+
@objc public func copyShape() -> any QRCodeEyeShapeGenerator { HolePunch() }
35+
36+
/// Reset the eye shape generator back to defaults
37+
@objc public func reset() { }
38+
39+
/// Returns the path representing the eye-outer shape
40+
public func eyePath() -> CGPath { eyeFrameOuter__ }
41+
/// Returns the path representing the background shape for the entire eye
42+
public func eyeBackgroundPath() -> CGPath { eyeFrameBackground__ }
43+
44+
private static let _defaultPupil = QRCode.PupilShape.Circle()
45+
/// Returns the generator for the default pixel shape
46+
public func defaultPupil() -> any QRCodePupilShapeGenerator { Self._defaultPupil }
47+
}
48+
}
49+
50+
public extension QRCodeEyeShapeGenerator where Self == QRCode.EyeShape.HolePunch {
51+
/// Create a dot drag eye shape generator
52+
/// - Returns: An eye shape generator
53+
@inlinable static func holePunch() -> QRCodeEyeShapeGenerator { QRCode.EyeShape.HolePunch() }
54+
}
55+
56+
// MARK: - Path generation
57+
58+
private let eyeFrameBackground__ = CGPath.make { eyebackgroundPath in
59+
eyebackgroundPath.move(to: CGPoint(x: 0, y: 0))
60+
eyebackgroundPath.line(to: CGPoint(x: 90, y: 0))
61+
eyebackgroundPath.line(to: CGPoint(x: 90, y: 90))
62+
eyebackgroundPath.line(to: CGPoint(x: 0, y: 90))
63+
eyebackgroundPath.line(to: CGPoint(x: 0, y: 0))
64+
eyebackgroundPath.close()
65+
}
66+
67+
private let eyeFrameOuter__ = CGPath.make { eyeouterPath in
68+
eyeouterPath.move(to: CGPoint(x: 45, y: 70))
69+
eyeouterPath.curve(to: CGPoint(x: 20, y: 45), controlPoint1: CGPoint(x: 31.19, y: 70), controlPoint2: CGPoint(x: 20, y: 58.81))
70+
eyeouterPath.curve(to: CGPoint(x: 34.91, y: 22.12), controlPoint1: CGPoint(x: 20, y: 34.78), controlPoint2: CGPoint(x: 26.13, y: 26))
71+
eyeouterPath.curve(to: CGPoint(x: 45, y: 20), controlPoint1: CGPoint(x: 37.99, y: 20.76), controlPoint2: CGPoint(x: 41.41, y: 20))
72+
eyeouterPath.curve(to: CGPoint(x: 70, y: 45), controlPoint1: CGPoint(x: 58.81, y: 20), controlPoint2: CGPoint(x: 70, y: 31.19))
73+
eyeouterPath.curve(to: CGPoint(x: 45, y: 70), controlPoint1: CGPoint(x: 70, y: 58.81), controlPoint2: CGPoint(x: 58.81, y: 70))
74+
eyeouterPath.close()
75+
eyeouterPath.move(to: CGPoint(x: 80, y: 80))
76+
eyeouterPath.curve(to: CGPoint(x: 80, y: 10), controlPoint1: CGPoint(x: 80, y: 80), controlPoint2: CGPoint(x: 80, y: 10))
77+
eyeouterPath.line(to: CGPoint(x: 10, y: 10))
78+
eyeouterPath.line(to: CGPoint(x: 10, y: 80))
79+
eyeouterPath.line(to: CGPoint(x: 80, y: 80))
80+
eyeouterPath.line(to: CGPoint(x: 80, y: 80))
81+
eyeouterPath.close()
82+
}

0 commit comments

Comments
 (0)