Skip to content

Commit 66d6522

Browse files
committed
Basic support for SK1 palettes
1 parent 6bbd11d commit 66d6522

File tree

11 files changed

+308
-13
lines changed

11 files changed

+308
-13
lines changed

Quicklook/Palette Viewer/Palette Viewer.xcodeproj/project.pbxproj

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@
163163
2339F52B2BCE48EE000C74F6 /* MacTextEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MacTextEditorView.swift; sourceTree = "<group>"; };
164164
2339F52E2BCE490F000C74F6 /* LineNumberRulerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineNumberRulerView.swift; sourceTree = "<group>"; };
165165
2339F5302BCF3F33000C74F6 /* InputStream+extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InputStream+extensions.swift"; sourceTree = "<group>"; };
166-
234369B22DDAD4A800179233 /* CSSParsingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CSSParsingTests.swift; sourceTree = "<group>"; };
167166
2344F2432A5CDA4500E04CE1 /* CodePopupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodePopupView.swift; sourceTree = "<group>"; };
168167
234D89732C20F182003D403B /* NumberFormatter+extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+extensions.swift"; sourceTree = "<group>"; };
169168
23524E5B2A79BA5F00F3FAEF /* GradientEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientEditor.swift; sourceTree = "<group>"; };
@@ -301,7 +300,6 @@
301300
23C29F452A8F020700CAC733 /* PaletteViewerPaletteThumbnailGenerator */,
302301
23A03DF628332AA2003846A4 /* Frameworks */,
303302
23A03DE028332A83003846A4 /* Products */,
304-
234369B22DDAD4A800179233 /* CSSParsingTests.swift */,
305303
);
306304
sourceTree = "<group>";
307305
};
@@ -772,7 +770,7 @@
772770
"@executable_path/../../../../Frameworks",
773771
);
774772
MACOSX_DEPLOYMENT_TARGET = 13.0;
775-
MARKETING_VERSION = 2.0.3;
773+
MARKETING_VERSION = 2.0.5;
776774
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.gradient-thumbnail-generator";
777775
PRODUCT_NAME = "$(TARGET_NAME)";
778776
SKIP_INSTALL = YES;
@@ -802,7 +800,7 @@
802800
"@executable_path/../../../../Frameworks",
803801
);
804802
MACOSX_DEPLOYMENT_TARGET = 13.0;
805-
MARKETING_VERSION = 2.0.3;
803+
MARKETING_VERSION = 2.0.5;
806804
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.gradient-thumbnail-generator";
807805
PRODUCT_NAME = "$(TARGET_NAME)";
808806
SKIP_INSTALL = YES;
@@ -949,7 +947,7 @@
949947
"@executable_path/../../../../Frameworks",
950948
);
951949
MACOSX_DEPLOYMENT_TARGET = 13.0;
952-
MARKETING_VERSION = 2.0.3;
950+
MARKETING_VERSION = 2.0.5;
953951
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.quicklook-palette";
954952
PRODUCT_NAME = "$(TARGET_NAME)";
955953
SKIP_INSTALL = YES;
@@ -979,7 +977,7 @@
979977
"@executable_path/../../../../Frameworks",
980978
);
981979
MACOSX_DEPLOYMENT_TARGET = 13.0;
982-
MARKETING_VERSION = 2.0.3;
980+
MARKETING_VERSION = 2.0.5;
983981
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.quicklook-palette";
984982
PRODUCT_NAME = "$(TARGET_NAME)";
985983
SKIP_INSTALL = YES;
@@ -1014,7 +1012,7 @@
10141012
"@executable_path/../Frameworks",
10151013
);
10161014
MACOSX_DEPLOYMENT_TARGET = 14.0;
1017-
MARKETING_VERSION = 2.0.3;
1015+
MARKETING_VERSION = 2.0.5;
10181016
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer";
10191017
PRODUCT_NAME = "$(TARGET_NAME)";
10201018
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1048,7 +1046,7 @@
10481046
"@executable_path/../Frameworks",
10491047
);
10501048
MACOSX_DEPLOYMENT_TARGET = 14.0;
1051-
MARKETING_VERSION = 2.0.3;
1049+
MARKETING_VERSION = 2.0.5;
10521050
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer";
10531051
PRODUCT_NAME = "$(TARGET_NAME)";
10541052
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -1077,7 +1075,7 @@
10771075
"@executable_path/../../../../Frameworks",
10781076
);
10791077
MACOSX_DEPLOYMENT_TARGET = 13.0;
1080-
MARKETING_VERSION = 2.0.3;
1078+
MARKETING_VERSION = 2.0.5;
10811079
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.palette-thumbnail-generator";
10821080
PRODUCT_NAME = "$(TARGET_NAME)";
10831081
SKIP_INSTALL = YES;
@@ -1107,7 +1105,7 @@
11071105
"@executable_path/../../../../Frameworks",
11081106
);
11091107
MACOSX_DEPLOYMENT_TARGET = 13.0;
1110-
MARKETING_VERSION = 2.0.3;
1108+
MARKETING_VERSION = 2.0.5;
11111109
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.palette-thumbnail-generator";
11121110
PRODUCT_NAME = "$(TARGET_NAME)";
11131111
SKIP_INSTALL = YES;
@@ -1138,7 +1136,7 @@
11381136
"@executable_path/../../../../Frameworks",
11391137
);
11401138
MACOSX_DEPLOYMENT_TARGET = 13.0;
1141-
MARKETING_VERSION = 2.0.3;
1139+
MARKETING_VERSION = 2.0.5;
11421140
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.quicklook-gradient";
11431141
PRODUCT_NAME = "$(TARGET_NAME)";
11441142
SKIP_INSTALL = YES;
@@ -1169,7 +1167,7 @@
11691167
"@executable_path/../../../../Frameworks",
11701168
);
11711169
MACOSX_DEPLOYMENT_TARGET = 13.0;
1172-
MARKETING_VERSION = 2.0.3;
1170+
MARKETING_VERSION = 2.0.5;
11731171
PRODUCT_BUNDLE_IDENTIFIER = "org.dagronf.palette-viewer.quicklook-gradient";
11741172
PRODUCT_NAME = "$(TARGET_NAME)";
11751173
SKIP_INSTALL = YES;

Quicklook/Palette Viewer/Palette Viewer/Info.plist

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,20 @@
530530
<key>NSDocumentClass</key>
531531
<string>$(PRODUCT_MODULE_NAME).Document</string>
532532
</dict>
533+
<dict>
534+
<key>CFBundleTypeName</key>
535+
<string>sK1 Color Palette</string>
536+
<key>CFBundleTypeRole</key>
537+
<string>Editor</string>
538+
<key>LSHandlerRank</key>
539+
<string>Default</string>
540+
<key>LSItemContentTypes</key>
541+
<array>
542+
<string>public.dagronf.colorpalette.palette.sk1</string>
543+
</array>
544+
<key>NSDocumentClass</key>
545+
<string>$(PRODUCT_MODULE_NAME).Document</string>
546+
</dict>
533547
</array>
534548
<key>UTExportedTypeDeclarations</key>
535549
<array>
@@ -1164,6 +1178,25 @@
11641178
</array>
11651179
</dict>
11661180
</dict>
1181+
<dict>
1182+
<key>UTTypeConformsTo</key>
1183+
<array>
1184+
<string>public.text</string>
1185+
</array>
1186+
<key>UTTypeDescription</key>
1187+
<string>sK1 Color Palette</string>
1188+
<key>UTTypeIcons</key>
1189+
<dict/>
1190+
<key>UTTypeIdentifier</key>
1191+
<string>public.dagronf.colorpalette.palette.sk1</string>
1192+
<key>UTTypeTagSpecification</key>
1193+
<dict>
1194+
<key>public.filename-extension</key>
1195+
<array>
1196+
<string>skp</string>
1197+
</array>
1198+
</dict>
1199+
</dict>
11671200
</array>
11681201
<key>UTImportedTypeDeclarations</key>
11691202
<array>

Quicklook/Palette Viewer/PaletteViewerPaletteThumbnailGenerator/Info.plist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<string>public.dagronf.colorpalette.palette.swatchbooker</string>
3636
<string>public.dagronf.colorpalette.palette.afpalette</string>
3737
<string>public.dagronf.colorpalette.palette.xara.palette</string>
38+
<string>public.dagronf.colorpalette.palette.sk1</string>
3839
</array>
3940
<key>QLThumbnailMinimumDimension</key>
4041
<integer>0</integer>

Quicklook/Palette Viewer/PaletteViewerQuickLookPlugin/Info.plist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<string>public.dagronf.colorpalette.palette.swatchbooker</string>
3838
<string>public.dagronf.colorpalette.palette.afpalette</string>
3939
<string>public.dagronf.colorpalette.palette.xara.palette</string>
40+
<string>public.dagronf.colorpalette.palette.sk1</string>
4041
</array>
4142
<key>QLSupportsSearchableItems</key>
4243
<false/>

Quicklook/Palette Viewer/Shared/PALCommon.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public let ExportablePaletteTypes: [String] = [
2727
PAL.Coder.ProcreateSwatchesCoder.utTypeString,
2828
PAL.Coder.AutodeskColorBook.utTypeString,
2929
PAL.Coder.SimplePaletteCoder.utTypeString,
30-
PAL.Coder.JCW.utTypeString
30+
PAL.Coder.JCW.utTypeString,
31+
PAL.Coder.SKP.utTypeString
3132
]
3233

3334
public let ExportablePaletteUTTypes: [UTType] = {

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Supports the following :-
5050
* Simple Palette format (`.color-palette`)
5151
* SwatchBooker format (`.sbz`) ***(read only) (Apple platforms only)***
5252
* Xara Designer Palette format (`.jcw`)
53+
* SK1 Color Palette (`.skp`) ***Very basic support***
5354

5455
## Supported gradient formats
5556

@@ -124,6 +125,7 @@ Some features :-
124125
|`PAL.Coder.ScribusXMLPaletteCoder` | Scribus XML palette (.xml) |
125126
|`PAL.Coder.SimplePaletteCoder` | Simple Palette (.color-palette) v0.1 |
126127
|`PAL.Coder.SketchPalette` | Sketch Palette (.sketchpalette) |
128+
|`PAL.Coder.SKP` | SK1 Color Palette (.skp) |
127129
|`PAL.Coder.SVG` | SVG image file (.svg) |
128130
|`PAL.Coder.SwatchbookerCoder | Swatchbooker Palette (.sbz) |
129131
|`PAL.Coder.VGA24BitPaletteCoder` | 24-bit VGA palette (.pal) |
@@ -218,6 +220,7 @@ let paletteData = palette.export(format: .ase)
218220
| `PAL.Coder.ScribusXMLPaletteCoder` | XML ||||||| RGB/CMYK only ||
219221
| `PAL.Coder.SimplePaletteCoder` | JSON ||||||| RGB only ||
220222
| `PAL.Coder.SketchPalette` | XML ||||||| RGB only ||
223+
| `PAL.Coder.SKP` | Text ||||||| RGB only ||
221224
| `PAL.Coder.SVG` | SVG text ||||||| RGB only ||
222225
| `PAL.Coder.SwatchbookerCoder` | Binary |||||||||
223226
| `PAL.Coder.ProcreateSwatchesCoder` | Binary |||||||||
@@ -431,6 +434,12 @@ which only deals with loading gradients.
431434

432435
This coder is somewhat hacky. For the sample files I've used it seems to work!
433436

437+
### SK1 palette support
438+
439+
SK1 (SKP) palettes appears to be chunks of Python code. The coder for it is very simple - it basically regexes on
440+
the `color(['RGB'` line to pull out r,g,b,a and name components. There is no check whether the file is valid, as
441+
this would require a complete python compilation.
442+
434443
## Disclaimer
435444

436445
I am not affiliated with any of the brands mentioned within this package. All trademarks and brand names are the property of their respective owners.
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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 DSFRegex
21+
import Foundation
22+
23+
public extension PAL.Coder {
24+
/// A coder for SK1 color palettes
25+
///
26+
/// The decoder here is _very_ rudimentary, as the SKP format appears to be Python code
27+
/// I was too lazy to write a full python executable, so I'm just using very simple regex matching for RGB entries
28+
struct SKP: PAL_PaletteCoder {
29+
public let format: PAL.PaletteFormat = .skp
30+
public let name = "SK1 Color Palette"
31+
public let fileExtension = ["skp"]
32+
public static let utTypeString = "public.dagronf.colorpalette.palette.sk1" // conforms to `public.text`
33+
34+
public init() {}
35+
}
36+
}
37+
38+
private let __rgbColorRegex = try! DSFRegex(#"color\(\['RGB', \[(\b\d+(?:\.\d+)?\b), (\b\d+(?:\.\d+)?\b), (\b\d+(?:\.\d+)?\b)\], (\b\d+(?:\.\d+)?\b),.*?'(.*?)'"#)
39+
private let __paletteNameRegex = try! DSFRegex(#"set_name\((?:.*?)'(.*?)'\)"#)
40+
41+
// MARK: - Decoding
42+
43+
public extension PAL.Coder.SKP {
44+
/// Create a palette from the contents of the input stream
45+
/// - Parameter inputStream: The input stream containing the encoded palette
46+
/// - Returns: A palette
47+
func decode(from inputStream: InputStream) throws -> PAL.Palette {
48+
// Load text from the input stream
49+
guard let decoded = String.decode(from: inputStream) else {
50+
throw PAL.CommonError.unableToLoadFile
51+
}
52+
53+
// All the lines in the file
54+
let lines = decoded.text.lines
55+
56+
// Check we're a valid
57+
guard let first = lines.first, first.hasPrefix("##sK1 palette") else {
58+
throw PAL.CommonError.invalidFormat
59+
}
60+
61+
var palette = PAL.Palette(format: self.format)
62+
63+
for line in lines.dropFirst() {
64+
let l = line.trimmingCharacters(in: CharacterSet.whitespaces)
65+
66+
if l.isEmpty {
67+
// Skip over empty lines
68+
break
69+
}
70+
71+
do {
72+
// Check if it's the palette name
73+
// set_name('Bluecurve icon colors')
74+
let namedefs = __paletteNameRegex.matches(for: l)
75+
namedefs.forEach { match in
76+
let name = String(l[match.captures[0]])
77+
if name.isNotEmpty {
78+
palette.name = name
79+
}
80+
}
81+
}
82+
83+
// Check if it's a color definition
84+
do {
85+
let searchResult = __rgbColorRegex.matches(for: l)
86+
// Loop over each of the matches found, and print them out
87+
searchResult.forEach { match in
88+
if
89+
let red = Double(l[match.captures[0]]),
90+
let green = Double(l[match.captures[1]]),
91+
let blue = Double(l[match.captures[2]]),
92+
let alpha = Double(l[match.captures[3]])
93+
{
94+
let name = String(l[match.captures[4]])
95+
let color = rgbf(red, green, blue, alpha, name: name)
96+
palette.colors.append(color)
97+
}
98+
}
99+
}
100+
}
101+
if palette.allColors().count == 0 {
102+
throw PAL.CommonError.invalidFormat
103+
}
104+
return palette
105+
}
106+
}
107+
108+
// MARK: - Encoding
109+
110+
public extension PAL.Coder.SKP {
111+
/// Encode the palette
112+
/// - Parameter palette: The palette to encode
113+
/// - Returns: The encoded representation of the palette
114+
func encode(_ palette: PAL.Palette) throws -> Data {
115+
116+
var result = "##sK1 palette\n"
117+
result += "palette()\n"
118+
result += "set_name('\(palette.name)')\n"
119+
result += "set_source('ColorPaletteCodable')\n"
120+
result += "set_columns(4)\n"
121+
122+
for color in palette.allColors() {
123+
let rgb = try color.rgb()
124+
let colorName = color.name.replacingOccurrences(of: "'\"", with: "_")
125+
result += "color(['RGB', [\(rgb.rf), \(rgb.gf), \(rgb.bf)], \(rgb.af), '\(colorName)'])\n"
126+
}
127+
128+
result += "palette_end()\n"
129+
130+
guard let data = result.data(using: .utf8) else {
131+
throw PAL.CommonError.invalidFormat
132+
}
133+
return data
134+
}
135+
}
136+
137+
// MARK: - UTType identifiers
138+
139+
#if canImport(UniformTypeIdentifiers)
140+
import UniformTypeIdentifiers
141+
@available(macOS 11, iOS 14, tvOS 14, watchOS 7, *)
142+
public extension UTType {
143+
static let sk1 = UTType(exportedAs: PAL.Coder.SKP.utTypeString, conformingTo: .text)
144+
}
145+
#endif
146+
147+
148+
// MARK: - Notes
149+
150+
151+
/*
152+
##sK1 palette
153+
palette()
154+
set_name('iOS 7 colors')
155+
set_source('Apple')
156+
add_comments('The palette is published here:')
157+
add_comments('https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/ColorImagesText.html')
158+
set_columns(4)
159+
color(['RGB', [0.35294117647058826, 0.7843137254901961, 0.9803921568627451], 1.0, '#5AC8FA'])
160+
color(['RGB', [1.0, 0.8, 0.0], 1.0, '#FFCC00'])
161+
color(['RGB', [1.0, 0.5843137254901961, 0.0], 1.0, '#FF9500'])
162+
color(['RGB', [1.0, 0.17647058823529413, 0.3333333333333333], 1.0, '#FF2D55'])
163+
color(['RGB', [0.0, 0.47843137254901963, 1.0], 1.0, '#007AFF'])
164+
color(['RGB', [0.2980392156862745, 0.8509803921568627, 0.39215686274509803], 1.0, '#4CD964'])
165+
color(['RGB', [1.0, 0.23137254901960785, 0.18823529411764706], 1.0, '#FF3B30'])
166+
color(['RGB', [0.5568627450980392, 0.5568627450980392, 0.5764705882352941], 1.0, '#8E8E93'])
167+
palette_end()
168+
*/

0 commit comments

Comments
 (0)