fastlane-plugin-wpmreleasetoolkit 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/drawText +1 -0
- data/ext/drawText/drawText Tests/DigitParsingTests.swift +21 -0
- data/ext/drawText/drawText Tests/ExtensionsTests.swift +5 -0
- data/ext/drawText/drawText Tests/Info.plist +22 -0
- data/ext/drawText/drawText Tests/StylesheetTests.swift +31 -0
- data/ext/drawText/drawText Tests/Test Cases/default-stylesheet.txt +10 -0
- data/ext/drawText/drawText Tests/Test Cases/external-styles-sample.css +3 -0
- data/ext/drawText/drawText Tests/Test Cases/external-styles-test.txt +13 -0
- data/ext/drawText/drawText Tests/Test Cases/large-text-block.txt +1 -0
- data/ext/drawText/drawText Tests/Test Cases/regular-text-block.txt +2 -0
- data/ext/drawText/drawText Tests/Test Cases/rtl-text-block.txt +2 -0
- data/ext/drawText/drawText Tests/Test Cases/text-size-adjustment-test.txt +10 -0
- data/ext/drawText/drawText Tests/TextImageTests.swift +99 -0
- data/ext/drawText/drawText Tests/drawText_Tests.swift +14 -0
- data/ext/drawText/drawText.xcodeproj/project.pbxproj +508 -0
- data/ext/drawText/drawText.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/ext/drawText/drawText.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/ext/drawText/drawText.xcodeproj/xcshareddata/xcschemes/drawText Tests.xcscheme +57 -0
- data/ext/drawText/drawText.xcodeproj/xcshareddata/xcschemes/drawText.xcscheme +109 -0
- data/ext/drawText/drawText/Assets/style.css +1 -0
- data/ext/drawText/drawText/CoreTextStack.swift +113 -0
- data/ext/drawText/drawText/Helpers/CommandLineHelpers.swift +36 -0
- data/ext/drawText/drawText/Helpers/Extensions.swift +27 -0
- data/ext/drawText/drawText/Helpers/FileSystemHelper.swift +24 -0
- data/ext/drawText/drawText/Stylesheet.swift +48 -0
- data/ext/drawText/drawText/TextImage.swift +100 -0
- data/ext/drawText/drawText/main.swift +61 -0
- data/ext/drawText/makefile.example +8 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
- metadata +41 -14
@@ -0,0 +1,57 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Scheme
|
3
|
+
LastUpgradeVersion = "1030"
|
4
|
+
version = "1.3">
|
5
|
+
<BuildAction
|
6
|
+
parallelizeBuildables = "YES"
|
7
|
+
buildImplicitDependencies = "YES">
|
8
|
+
</BuildAction>
|
9
|
+
<TestAction
|
10
|
+
buildConfiguration = "Debug"
|
11
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
12
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
13
|
+
codeCoverageEnabled = "YES"
|
14
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
15
|
+
<Testables>
|
16
|
+
<TestableReference
|
17
|
+
skipped = "NO">
|
18
|
+
<BuildableReference
|
19
|
+
BuildableIdentifier = "primary"
|
20
|
+
BlueprintIdentifier = "F907EA6F22F3736E00196382"
|
21
|
+
BuildableName = "drawText Tests.xctest"
|
22
|
+
BlueprintName = "drawText Tests"
|
23
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
24
|
+
</BuildableReference>
|
25
|
+
</TestableReference>
|
26
|
+
</Testables>
|
27
|
+
<AdditionalOptions>
|
28
|
+
</AdditionalOptions>
|
29
|
+
</TestAction>
|
30
|
+
<LaunchAction
|
31
|
+
buildConfiguration = "Debug"
|
32
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
33
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
34
|
+
launchStyle = "0"
|
35
|
+
useCustomWorkingDirectory = "NO"
|
36
|
+
ignoresPersistentStateOnLaunch = "NO"
|
37
|
+
debugDocumentVersioning = "YES"
|
38
|
+
debugServiceExtension = "internal"
|
39
|
+
allowLocationSimulation = "YES">
|
40
|
+
<AdditionalOptions>
|
41
|
+
</AdditionalOptions>
|
42
|
+
</LaunchAction>
|
43
|
+
<ProfileAction
|
44
|
+
buildConfiguration = "Release"
|
45
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
46
|
+
savedToolIdentifier = ""
|
47
|
+
useCustomWorkingDirectory = "NO"
|
48
|
+
debugDocumentVersioning = "YES">
|
49
|
+
</ProfileAction>
|
50
|
+
<AnalyzeAction
|
51
|
+
buildConfiguration = "Debug">
|
52
|
+
</AnalyzeAction>
|
53
|
+
<ArchiveAction
|
54
|
+
buildConfiguration = "Release"
|
55
|
+
revealArchiveInOrganizer = "YES">
|
56
|
+
</ArchiveAction>
|
57
|
+
</Scheme>
|
@@ -0,0 +1,109 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Scheme
|
3
|
+
LastUpgradeVersion = "1030"
|
4
|
+
version = "1.3">
|
5
|
+
<BuildAction
|
6
|
+
parallelizeBuildables = "YES"
|
7
|
+
buildImplicitDependencies = "YES">
|
8
|
+
<BuildActionEntries>
|
9
|
+
<BuildActionEntry
|
10
|
+
buildForTesting = "YES"
|
11
|
+
buildForRunning = "YES"
|
12
|
+
buildForProfiling = "YES"
|
13
|
+
buildForArchiving = "YES"
|
14
|
+
buildForAnalyzing = "YES">
|
15
|
+
<BuildableReference
|
16
|
+
BuildableIdentifier = "primary"
|
17
|
+
BlueprintIdentifier = "F99B0B9722F24329002851D8"
|
18
|
+
BuildableName = "drawText"
|
19
|
+
BlueprintName = "drawText"
|
20
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
21
|
+
</BuildableReference>
|
22
|
+
</BuildActionEntry>
|
23
|
+
</BuildActionEntries>
|
24
|
+
</BuildAction>
|
25
|
+
<TestAction
|
26
|
+
buildConfiguration = "Debug"
|
27
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
28
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
29
|
+
codeCoverageEnabled = "YES"
|
30
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
31
|
+
<Testables>
|
32
|
+
<TestableReference
|
33
|
+
skipped = "NO">
|
34
|
+
<BuildableReference
|
35
|
+
BuildableIdentifier = "primary"
|
36
|
+
BlueprintIdentifier = "F907EA6F22F3736E00196382"
|
37
|
+
BuildableName = "drawText Tests.xctest"
|
38
|
+
BlueprintName = "drawText Tests"
|
39
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
40
|
+
</BuildableReference>
|
41
|
+
</TestableReference>
|
42
|
+
</Testables>
|
43
|
+
<MacroExpansion>
|
44
|
+
<BuildableReference
|
45
|
+
BuildableIdentifier = "primary"
|
46
|
+
BlueprintIdentifier = "F99B0B9722F24329002851D8"
|
47
|
+
BuildableName = "drawText"
|
48
|
+
BlueprintName = "drawText"
|
49
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
50
|
+
</BuildableReference>
|
51
|
+
</MacroExpansion>
|
52
|
+
<AdditionalOptions>
|
53
|
+
</AdditionalOptions>
|
54
|
+
</TestAction>
|
55
|
+
<LaunchAction
|
56
|
+
buildConfiguration = "Debug"
|
57
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
58
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
59
|
+
launchStyle = "0"
|
60
|
+
useCustomWorkingDirectory = "NO"
|
61
|
+
ignoresPersistentStateOnLaunch = "NO"
|
62
|
+
debugDocumentVersioning = "YES"
|
63
|
+
debugServiceExtension = "internal"
|
64
|
+
allowLocationSimulation = "YES">
|
65
|
+
<BuildableProductRunnable
|
66
|
+
runnableDebuggingMode = "0">
|
67
|
+
<BuildableReference
|
68
|
+
BuildableIdentifier = "primary"
|
69
|
+
BlueprintIdentifier = "F99B0B9722F24329002851D8"
|
70
|
+
BuildableName = "drawText"
|
71
|
+
BlueprintName = "drawText"
|
72
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
73
|
+
</BuildableReference>
|
74
|
+
</BuildableProductRunnable>
|
75
|
+
<EnvironmentVariables>
|
76
|
+
<EnvironmentVariable
|
77
|
+
key = "CG_CONTEXT_SHOW_BACKTRACE"
|
78
|
+
value = ""
|
79
|
+
isEnabled = "YES">
|
80
|
+
</EnvironmentVariable>
|
81
|
+
</EnvironmentVariables>
|
82
|
+
<AdditionalOptions>
|
83
|
+
</AdditionalOptions>
|
84
|
+
</LaunchAction>
|
85
|
+
<ProfileAction
|
86
|
+
buildConfiguration = "Release"
|
87
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
88
|
+
savedToolIdentifier = ""
|
89
|
+
useCustomWorkingDirectory = "NO"
|
90
|
+
debugDocumentVersioning = "YES">
|
91
|
+
<BuildableProductRunnable
|
92
|
+
runnableDebuggingMode = "0">
|
93
|
+
<BuildableReference
|
94
|
+
BuildableIdentifier = "primary"
|
95
|
+
BlueprintIdentifier = "F99B0B9722F24329002851D8"
|
96
|
+
BuildableName = "drawText"
|
97
|
+
BlueprintName = "drawText"
|
98
|
+
ReferencedContainer = "container:drawText.xcodeproj">
|
99
|
+
</BuildableReference>
|
100
|
+
</BuildableProductRunnable>
|
101
|
+
</ProfileAction>
|
102
|
+
<AnalyzeAction
|
103
|
+
buildConfiguration = "Debug">
|
104
|
+
</AnalyzeAction>
|
105
|
+
<ArchiveAction
|
106
|
+
buildConfiguration = "Release"
|
107
|
+
revealArchiveInOrganizer = "YES">
|
108
|
+
</ArchiveAction>
|
109
|
+
</Scheme>
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import Cocoa
|
2
|
+
import CoreGraphics
|
3
|
+
|
4
|
+
struct CoreTextStack {
|
5
|
+
|
6
|
+
let layoutManager: NSLayoutManager
|
7
|
+
let textContainer: NSTextContainer
|
8
|
+
var textStorage: NSTextStorage
|
9
|
+
|
10
|
+
let frameSize: CGSize
|
11
|
+
var alignment: NSTextAlignment
|
12
|
+
|
13
|
+
enum Errors: Error {
|
14
|
+
case unableToInitializeTextStorage
|
15
|
+
}
|
16
|
+
|
17
|
+
init(html: Data, size: CGSize, alignment: NSTextAlignment = .natural) throws {
|
18
|
+
|
19
|
+
guard let textStorage = NSTextStorage(html: html, documentAttributes: nil) else {
|
20
|
+
throw Errors.unableToInitializeTextStorage
|
21
|
+
}
|
22
|
+
|
23
|
+
///Storage
|
24
|
+
self.textStorage = textStorage
|
25
|
+
self.textContainer = NSTextContainer(size: size)
|
26
|
+
self.layoutManager = NSLayoutManager()
|
27
|
+
self.frameSize = size
|
28
|
+
self.alignment = alignment
|
29
|
+
|
30
|
+
/// Setup
|
31
|
+
layoutManager.addTextContainer(textContainer)
|
32
|
+
textStorage.addLayoutManager(layoutManager)
|
33
|
+
|
34
|
+
/// Configuration
|
35
|
+
textContainer.lineFragmentPadding = 0
|
36
|
+
textContainer.lineBreakMode = .byWordWrapping
|
37
|
+
layoutManager.usesFontLeading = true
|
38
|
+
layoutManager.typesetter.lineFragmentPadding = 0
|
39
|
+
|
40
|
+
applyParagraphStyles()
|
41
|
+
}
|
42
|
+
|
43
|
+
func setFontSize(_ size: CGFloat) {
|
44
|
+
|
45
|
+
/// Process each attribute run separately so that if the first word is bold,
|
46
|
+
/// it doesn't make all of the words bold.
|
47
|
+
textStorage.attributeRuns.forEach {
|
48
|
+
|
49
|
+
let range = NSRange(location: 0, length: $0.length)
|
50
|
+
|
51
|
+
$0.font = NSFont(name: $0.font!.fontName, size: size)
|
52
|
+
$0.edited(.editedAttributes, range: range, changeInLength: 0)
|
53
|
+
$0.fixAttributes(in: range)
|
54
|
+
}
|
55
|
+
|
56
|
+
applyParagraphStyles()
|
57
|
+
}
|
58
|
+
|
59
|
+
mutating func setAlignment(_ alignment: NSTextAlignment) {
|
60
|
+
self.alignment = alignment
|
61
|
+
applyParagraphStyles()
|
62
|
+
}
|
63
|
+
|
64
|
+
func applyParagraphStyles() {
|
65
|
+
|
66
|
+
let paragraphStyle = NSMutableParagraphStyle()
|
67
|
+
paragraphStyle.paragraphSpacingBefore = 0
|
68
|
+
paragraphStyle.paragraphSpacing = 0
|
69
|
+
paragraphStyle.alignment = self.alignment
|
70
|
+
|
71
|
+
textStorage.addAttributes([
|
72
|
+
NSAttributedString.Key.paragraphStyle: paragraphStyle
|
73
|
+
], range: range)
|
74
|
+
textStorage.edited(.editedAttributes, range: range, changeInLength: 0)
|
75
|
+
textStorage.fixAttributes(in: range)
|
76
|
+
}
|
77
|
+
|
78
|
+
func draw(inContext context: NSGraphicsContext) throws -> CGImage {
|
79
|
+
NSGraphicsContext.saveGraphicsState()
|
80
|
+
|
81
|
+
/// Without the transform, text is drawn upside down and backwards because of
|
82
|
+
/// macOS' flipped coordinate system.
|
83
|
+
NSGraphicsContext.current = NSGraphicsContext(cgContext: context.cgContext, flipped: true)
|
84
|
+
let transform = NSAffineTransform()
|
85
|
+
transform.scaleX(by: 1, yBy: -1)
|
86
|
+
transform.translateX(by: 0, yBy: frameSize.height * -1)
|
87
|
+
transform.concat()
|
88
|
+
|
89
|
+
layoutManager.drawGlyphs(forGlyphRange: range, at: .zero)
|
90
|
+
|
91
|
+
guard let image = context.cgContext.makeImage() else {
|
92
|
+
throw TextImageProcessingError(kind: .unableToDrawImage)
|
93
|
+
}
|
94
|
+
NSGraphicsContext.restoreGraphicsState()
|
95
|
+
|
96
|
+
return image
|
97
|
+
}
|
98
|
+
|
99
|
+
/// `fits` is used to determine whether we should shrink the font size in order to fit the text in
|
100
|
+
/// a smaller box. Turns out the best way to do that is to check whether all the characters fit into
|
101
|
+
/// the textContainer, rather than trying to measure the drawing area.
|
102
|
+
var fits: Bool {
|
103
|
+
|
104
|
+
let textStorageLength = textStorage.length
|
105
|
+
let textContainerRange = layoutManager.glyphRange(for: textContainer)
|
106
|
+
|
107
|
+
return textStorageLength == textContainerRange.length
|
108
|
+
}
|
109
|
+
|
110
|
+
var range: NSRange {
|
111
|
+
return layoutManager.glyphRange(for: textContainer)
|
112
|
+
}
|
113
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import Foundation
|
2
|
+
|
3
|
+
func readCommandLineArguments() -> [String : String] {
|
4
|
+
|
5
|
+
return CommandLine.arguments
|
6
|
+
.filter{ $0.contains("=") }
|
7
|
+
.reduce([String : String](), { (dictionary, argument) -> [String : String] in
|
8
|
+
|
9
|
+
var dictionary = dictionary //shadow for mutability
|
10
|
+
|
11
|
+
var parts = argument.split(separator: "=")
|
12
|
+
dictionary[String(parts.remove(at: 0))] = parts.joined(separator: "=")
|
13
|
+
|
14
|
+
return dictionary
|
15
|
+
})
|
16
|
+
}
|
17
|
+
|
18
|
+
func printUsageAndExit() -> Never {
|
19
|
+
print("""
|
20
|
+
Usage: ./draw-text
|
21
|
+
html={file path or quotes-enclosed HTML string [required]}
|
22
|
+
maxWidth={ integer [required] }
|
23
|
+
maxHeight={ integer [required] }
|
24
|
+
fontSize={ CSS-size compatible string [default = 12px }
|
25
|
+
color={ color or hex code [default = white] }
|
26
|
+
align={ CSS text-alignment value [default = center] }
|
27
|
+
stylesheet={ File Path to a custom stylesheet [default = none] }
|
28
|
+
""")
|
29
|
+
exit(1)
|
30
|
+
}
|
31
|
+
|
32
|
+
func printError(_ string: String) {
|
33
|
+
let redColor = "\u{001B}[0;31m"
|
34
|
+
let endColor = "\u{001B}[0;m"
|
35
|
+
fputs("\(redColor)Error: \(string)\(endColor)\n", stderr)
|
36
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import Foundation
|
2
|
+
import Cocoa
|
3
|
+
|
4
|
+
extension String {
|
5
|
+
var digits: Int? {
|
6
|
+
let digits = self
|
7
|
+
.components(separatedBy: CharacterSet.decimalDigits.inverted)
|
8
|
+
.joined()
|
9
|
+
|
10
|
+
return Int(digits)
|
11
|
+
}
|
12
|
+
|
13
|
+
var withNewlinesConvertedToBreakTags: String {
|
14
|
+
return self.replacingOccurrences(of: "\n", with: "<br />")
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
extension NSTextAlignment {
|
19
|
+
static func fromString(_ string: String) -> NSTextAlignment {
|
20
|
+
switch string.lowercased() {
|
21
|
+
case "left": return .left
|
22
|
+
case "center": return .center
|
23
|
+
case "right": return .right
|
24
|
+
default: return .natural
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import Foundation
|
2
|
+
import Cocoa
|
3
|
+
|
4
|
+
struct File {
|
5
|
+
|
6
|
+
static func write(image: CGImage, toFileAtPath path: String) {
|
7
|
+
|
8
|
+
/// Turn it into a `png`
|
9
|
+
let rep = NSBitmapImageRep(cgImage: image)
|
10
|
+
let pngData = rep.representation(using: .png, properties: [:])
|
11
|
+
|
12
|
+
/// Then write it out to the provided path
|
13
|
+
do {
|
14
|
+
let pathString = NSString(string: path).expandingTildeInPath
|
15
|
+
let output = NSURL(fileURLWithPath: pathString)
|
16
|
+
|
17
|
+
try pngData?.write(to: output as URL)
|
18
|
+
}
|
19
|
+
catch let err {
|
20
|
+
printError("Unable to write image to \(path): \(err.localizedDescription)")
|
21
|
+
exit(6)
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import Cocoa
|
2
|
+
|
3
|
+
struct Stylesheet {
|
4
|
+
|
5
|
+
var contents: String = ""
|
6
|
+
var externalStyles = "/* EXTERNAL STYLES */"
|
7
|
+
|
8
|
+
private let color: String
|
9
|
+
|
10
|
+
init(color: String, fontSize: Int) {
|
11
|
+
self.fontSize = fontSize
|
12
|
+
self.color = color
|
13
|
+
|
14
|
+
update()
|
15
|
+
}
|
16
|
+
|
17
|
+
mutating func updateWith(filePath: String) {
|
18
|
+
|
19
|
+
guard
|
20
|
+
FileManager.default.fileExists(atPath: filePath),
|
21
|
+
let fileContents = FileManager.default.contents(atPath: filePath),
|
22
|
+
let externalStyles = String(bytes: fileContents, encoding: .utf8) else {
|
23
|
+
return
|
24
|
+
}
|
25
|
+
|
26
|
+
self.externalStyles = externalStyles
|
27
|
+
update()
|
28
|
+
}
|
29
|
+
|
30
|
+
var fontSize: Int {
|
31
|
+
didSet { update() }
|
32
|
+
}
|
33
|
+
|
34
|
+
fileprivate mutating func update() {
|
35
|
+
self.contents = """
|
36
|
+
<style>
|
37
|
+
* {
|
38
|
+
padding: 0;
|
39
|
+
margin: 0;
|
40
|
+
color: \(color);
|
41
|
+
font-size: \(fontSize)px;
|
42
|
+
}
|
43
|
+
|
44
|
+
\(externalStyles)
|
45
|
+
</style>
|
46
|
+
""".trimmingCharacters(in: .whitespacesAndNewlines)
|
47
|
+
}
|
48
|
+
}
|