├── .gitattributes ├── .gitignore ├── .swiftlint.yml ├── Cartfile ├── Cartfile.resolved ├── Icns Composer.xcodeproj └── project.pbxproj ├── Icns Composer ├── AppDelegate.swift ├── Assets.xcassets │ ├── Contents.json │ └── IcnsComposer.appiconset │ │ ├── Contents.json │ │ ├── icon-1024.png │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-256.png │ │ ├── icon-32.png │ │ ├── icon-512.png │ │ └── icon-64.png ├── DragDropImageView.swift ├── IconImage.swift ├── Iconset.swift ├── Info.plist ├── MainMenu.xib ├── MainWindow.xib ├── MainWindowController.swift ├── NSImageExtensions.swift └── dsa_pub.pem ├── LICENSE ├── README.md └── screenshot.png /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj binary merge=union 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X Finder 2 | .DS_Store 3 | 4 | # Xcode per-user config 5 | *.mode1 6 | *.mode1v3 7 | *.mode2v3 8 | *.perspective 9 | *.perspectivev3 10 | *.pbxuser 11 | *.xcworkspace 12 | xcuserdata 13 | 14 | # Build products 15 | DerivedData/ 16 | build/ 17 | Carthage/ 18 | *.o 19 | *.LinkFileList 20 | *.hmap 21 | 22 | # Automatic backup files 23 | *~.nib/ 24 | *.swp 25 | *~ 26 | *.dat 27 | *.dep 28 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | line_length: 120 2 | cyclomatic_complexity: 12 3 | 4 | excluded: 5 | - Carthage 6 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "sparkle-project/Sparkle" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "sparkle-project/Sparkle" "1.24.0" 2 | -------------------------------------------------------------------------------- /Icns Composer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 20FA7A831B14E9FE00E7B8E7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20FA7A7D1B14E9FE00E7B8E7 /* AppDelegate.swift */; }; 11 | 20FA7A841B14E9FE00E7B8E7 /* DragDropImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20FA7A7E1B14E9FE00E7B8E7 /* DragDropImageView.swift */; }; 12 | 20FA7A851B14E9FE00E7B8E7 /* Iconset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20FA7A7F1B14E9FE00E7B8E7 /* Iconset.swift */; }; 13 | 20FA7A861B14E9FE00E7B8E7 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 20FA7A801B14E9FE00E7B8E7 /* MainWindow.xib */; }; 14 | 20FA7A871B14E9FE00E7B8E7 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20FA7A811B14E9FE00E7B8E7 /* MainWindowController.swift */; }; 15 | 20FA7A8B1B14EA2500E7B8E7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 20FA7A8A1B14EA2500E7B8E7 /* MainMenu.xib */; }; 16 | 8E1825C51D49F45E001259F1 /* IconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E1825C41D49F45E001259F1 /* IconImage.swift */; }; 17 | 8E3F61751D4D1EFD008A10D6 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E3F61741D4D1EFD008A10D6 /* Sparkle.framework */; }; 18 | 8E3F61761D4D1EFD008A10D6 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8E3F61741D4D1EFD008A10D6 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | 8E4E684F1BDAACEF004980A0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8E4E684E1BDAACEF004980A0 /* Assets.xcassets */; }; 20 | 8E7A659C1B5BB935003FC529 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E7A659B1B5BB935003FC529 /* NSImageExtensions.swift */; }; 21 | 8EA095AF1B583DC500DA6A2E /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 8EA095AE1B583DC500DA6A2E /* dsa_pub.pem */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 8E3F61771D4D1EFD008A10D6 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 8E3F61761D4D1EFD008A10D6 /* Sparkle.framework in Embed Frameworks */, 32 | ); 33 | name = "Embed Frameworks"; 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 20FA7A5D1B14E9D900E7B8E7 /* Icns Composer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Icns Composer.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 20FA7A611B14E9D900E7B8E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 20FA7A7D1B14E9FE00E7B8E7 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 42 | 20FA7A7E1B14E9FE00E7B8E7 /* DragDropImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragDropImageView.swift; sourceTree = ""; }; 43 | 20FA7A7F1B14E9FE00E7B8E7 /* Iconset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Iconset.swift; sourceTree = ""; }; 44 | 20FA7A801B14E9FE00E7B8E7 /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 45 | 20FA7A811B14E9FE00E7B8E7 /* MainWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 46 | 20FA7A8A1B14EA2500E7B8E7 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; 47 | 8E1825C41D49F45E001259F1 /* IconImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IconImage.swift; sourceTree = ""; }; 48 | 8E3F61741D4D1EFD008A10D6 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Carthage/Build/Mac/Sparkle.framework; sourceTree = ""; }; 49 | 8E4E684E1BDAACEF004980A0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 8E7A659B1B5BB935003FC529 /* NSImageExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImageExtensions.swift; sourceTree = ""; }; 51 | 8EA095AE1B583DC500DA6A2E /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 20FA7A5A1B14E9D900E7B8E7 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 8E3F61751D4D1EFD008A10D6 /* Sparkle.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 20FA7A541B14E9D800E7B8E7 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 20FA7A5F1B14E9D900E7B8E7 /* Icns Composer */, 70 | 8EA095A91B583B4B00DA6A2E /* Frameworks */, 71 | 20FA7A5E1B14E9D900E7B8E7 /* Products */, 72 | ); 73 | sourceTree = ""; 74 | }; 75 | 20FA7A5E1B14E9D900E7B8E7 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 20FA7A5D1B14E9D900E7B8E7 /* Icns Composer.app */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | 20FA7A5F1B14E9D900E7B8E7 /* Icns Composer */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 20FA7A7D1B14E9FE00E7B8E7 /* AppDelegate.swift */, 87 | 20FA7A811B14E9FE00E7B8E7 /* MainWindowController.swift */, 88 | 20FA7A7F1B14E9FE00E7B8E7 /* Iconset.swift */, 89 | 8E1825C41D49F45E001259F1 /* IconImage.swift */, 90 | 20FA7A7E1B14E9FE00E7B8E7 /* DragDropImageView.swift */, 91 | 8E7A659B1B5BB935003FC529 /* NSImageExtensions.swift */, 92 | 20FA7A891B14EA0400E7B8E7 /* UI */, 93 | 20FA7A601B14E9D900E7B8E7 /* Supporting Files */, 94 | ); 95 | path = "Icns Composer"; 96 | sourceTree = ""; 97 | }; 98 | 20FA7A601B14E9D900E7B8E7 /* Supporting Files */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 8E4E684E1BDAACEF004980A0 /* Assets.xcassets */, 102 | 20FA7A611B14E9D900E7B8E7 /* Info.plist */, 103 | 8EA095AE1B583DC500DA6A2E /* dsa_pub.pem */, 104 | ); 105 | name = "Supporting Files"; 106 | sourceTree = ""; 107 | }; 108 | 20FA7A891B14EA0400E7B8E7 /* UI */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 20FA7A8A1B14EA2500E7B8E7 /* MainMenu.xib */, 112 | 20FA7A801B14E9FE00E7B8E7 /* MainWindow.xib */, 113 | ); 114 | name = UI; 115 | sourceTree = ""; 116 | }; 117 | 8EA095A91B583B4B00DA6A2E /* Frameworks */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 8E3F61741D4D1EFD008A10D6 /* Sparkle.framework */, 121 | ); 122 | name = Frameworks; 123 | sourceTree = ""; 124 | }; 125 | /* End PBXGroup section */ 126 | 127 | /* Begin PBXNativeTarget section */ 128 | 20FA7A5C1B14E9D900E7B8E7 /* Icns Composer */ = { 129 | isa = PBXNativeTarget; 130 | buildConfigurationList = 20FA7A771B14E9D900E7B8E7 /* Build configuration list for PBXNativeTarget "Icns Composer" */; 131 | buildPhases = ( 132 | 20FA7A591B14E9D900E7B8E7 /* Sources */, 133 | 20FA7A5A1B14E9D900E7B8E7 /* Frameworks */, 134 | 20FA7A5B1B14E9D900E7B8E7 /* Resources */, 135 | 8E4CB2331CA196F4001D52C4 /* ShellScript */, 136 | 8E3F61771D4D1EFD008A10D6 /* Embed Frameworks */, 137 | ); 138 | buildRules = ( 139 | ); 140 | dependencies = ( 141 | ); 142 | name = "Icns Composer"; 143 | productName = "Icns Composer"; 144 | productReference = 20FA7A5D1B14E9D900E7B8E7 /* Icns Composer.app */; 145 | productType = "com.apple.product-type.application"; 146 | }; 147 | /* End PBXNativeTarget section */ 148 | 149 | /* Begin PBXProject section */ 150 | 20FA7A551B14E9D900E7B8E7 /* Project object */ = { 151 | isa = PBXProject; 152 | attributes = { 153 | LastSwiftMigration = 0700; 154 | LastSwiftUpdateCheck = 0700; 155 | LastUpgradeCheck = 1220; 156 | ORGANIZATIONNAME = "Raphael Hanneken"; 157 | TargetAttributes = { 158 | 20FA7A5C1B14E9D900E7B8E7 = { 159 | CreatedOnToolsVersion = 6.3.2; 160 | LastSwiftMigration = 1220; 161 | }; 162 | }; 163 | }; 164 | buildConfigurationList = 20FA7A581B14E9D900E7B8E7 /* Build configuration list for PBXProject "Icns Composer" */; 165 | compatibilityVersion = "Xcode 3.2"; 166 | developmentRegion = en; 167 | hasScannedForEncodings = 0; 168 | knownRegions = ( 169 | en, 170 | Base, 171 | ); 172 | mainGroup = 20FA7A541B14E9D800E7B8E7; 173 | productRefGroup = 20FA7A5E1B14E9D900E7B8E7 /* Products */; 174 | projectDirPath = ""; 175 | projectRoot = ""; 176 | targets = ( 177 | 20FA7A5C1B14E9D900E7B8E7 /* Icns Composer */, 178 | ); 179 | }; 180 | /* End PBXProject section */ 181 | 182 | /* Begin PBXResourcesBuildPhase section */ 183 | 20FA7A5B1B14E9D900E7B8E7 /* Resources */ = { 184 | isa = PBXResourcesBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | 8EA095AF1B583DC500DA6A2E /* dsa_pub.pem in Resources */, 188 | 20FA7A861B14E9FE00E7B8E7 /* MainWindow.xib in Resources */, 189 | 8E4E684F1BDAACEF004980A0 /* Assets.xcassets in Resources */, 190 | 20FA7A8B1B14EA2500E7B8E7 /* MainMenu.xib in Resources */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | /* End PBXResourcesBuildPhase section */ 195 | 196 | /* Begin PBXShellScriptBuildPhase section */ 197 | 8E4CB2331CA196F4001D52C4 /* ShellScript */ = { 198 | isa = PBXShellScriptBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | ); 202 | inputPaths = ( 203 | ); 204 | outputPaths = ( 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | shellPath = /bin/sh; 208 | shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect\n swiftlint\nelse\n echo \"Warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 209 | }; 210 | /* End PBXShellScriptBuildPhase section */ 211 | 212 | /* Begin PBXSourcesBuildPhase section */ 213 | 20FA7A591B14E9D900E7B8E7 /* Sources */ = { 214 | isa = PBXSourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | 8E1825C51D49F45E001259F1 /* IconImage.swift in Sources */, 218 | 20FA7A851B14E9FE00E7B8E7 /* Iconset.swift in Sources */, 219 | 8E7A659C1B5BB935003FC529 /* NSImageExtensions.swift in Sources */, 220 | 20FA7A831B14E9FE00E7B8E7 /* AppDelegate.swift in Sources */, 221 | 20FA7A871B14E9FE00E7B8E7 /* MainWindowController.swift in Sources */, 222 | 20FA7A841B14E9FE00E7B8E7 /* DragDropImageView.swift in Sources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXSourcesBuildPhase section */ 227 | 228 | /* Begin XCBuildConfiguration section */ 229 | 20FA7A751B14E9D900E7B8E7 /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | ALWAYS_SEARCH_USER_PATHS = NO; 233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 234 | CLANG_CXX_LIBRARY = "libc++"; 235 | CLANG_ENABLE_MODULES = YES; 236 | CLANG_ENABLE_OBJC_ARC = YES; 237 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 238 | CLANG_WARN_BOOL_CONVERSION = YES; 239 | CLANG_WARN_COMMA = YES; 240 | CLANG_WARN_CONSTANT_CONVERSION = YES; 241 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 243 | CLANG_WARN_EMPTY_BODY = YES; 244 | CLANG_WARN_ENUM_CONVERSION = YES; 245 | CLANG_WARN_INFINITE_RECURSION = YES; 246 | CLANG_WARN_INT_CONVERSION = YES; 247 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 248 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 249 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 251 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 252 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 253 | CLANG_WARN_STRICT_PROTOTYPES = YES; 254 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 255 | CLANG_WARN_UNREACHABLE_CODE = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | CODE_SIGN_IDENTITY = ""; 258 | COPY_PHASE_STRIP = YES; 259 | DEBUG_INFORMATION_FORMAT = dwarf; 260 | ENABLE_STRICT_OBJC_MSGSEND = YES; 261 | ENABLE_TESTABILITY = YES; 262 | GCC_C_LANGUAGE_STANDARD = gnu99; 263 | GCC_DYNAMIC_NO_PIC = NO; 264 | GCC_NO_COMMON_BLOCKS = YES; 265 | GCC_OPTIMIZATION_LEVEL = 0; 266 | GCC_PREPROCESSOR_DEFINITIONS = ( 267 | "DEBUG=1", 268 | "$(inherited)", 269 | ); 270 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | MACOSX_DEPLOYMENT_TARGET = 10.10; 278 | MTL_ENABLE_DEBUG_INFO = YES; 279 | ONLY_ACTIVE_ARCH = YES; 280 | SDKROOT = macosx; 281 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 282 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 283 | SWIFT_VERSION = 4.0; 284 | }; 285 | name = Debug; 286 | }; 287 | 20FA7A761B14E9D900E7B8E7 /* Release */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | ALWAYS_SEARCH_USER_PATHS = NO; 291 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 292 | CLANG_CXX_LIBRARY = "libc++"; 293 | CLANG_ENABLE_MODULES = YES; 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 296 | CLANG_WARN_BOOL_CONVERSION = YES; 297 | CLANG_WARN_COMMA = YES; 298 | CLANG_WARN_CONSTANT_CONVERSION = YES; 299 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 300 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 301 | CLANG_WARN_EMPTY_BODY = YES; 302 | CLANG_WARN_ENUM_CONVERSION = YES; 303 | CLANG_WARN_INFINITE_RECURSION = YES; 304 | CLANG_WARN_INT_CONVERSION = YES; 305 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 306 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 307 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 308 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 309 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 310 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 311 | CLANG_WARN_STRICT_PROTOTYPES = YES; 312 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 313 | CLANG_WARN_UNREACHABLE_CODE = YES; 314 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 315 | CODE_SIGN_IDENTITY = ""; 316 | COPY_PHASE_STRIP = YES; 317 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 318 | ENABLE_NS_ASSERTIONS = NO; 319 | ENABLE_STRICT_OBJC_MSGSEND = YES; 320 | GCC_C_LANGUAGE_STANDARD = gnu99; 321 | GCC_NO_COMMON_BLOCKS = YES; 322 | GCC_OPTIMIZATION_LEVEL = fast; 323 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 324 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 325 | GCC_WARN_UNDECLARED_SELECTOR = YES; 326 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 327 | GCC_WARN_UNUSED_FUNCTION = YES; 328 | GCC_WARN_UNUSED_VARIABLE = YES; 329 | MACOSX_DEPLOYMENT_TARGET = 10.10; 330 | MTL_ENABLE_DEBUG_INFO = NO; 331 | SDKROOT = macosx; 332 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 333 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 334 | SWIFT_VERSION = 4.0; 335 | }; 336 | name = Release; 337 | }; 338 | 20FA7A781B14E9D900E7B8E7 /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ASSETCATALOG_COMPILER_APPICON_NAME = IcnsComposer; 342 | CODE_SIGN_IDENTITY = "-"; 343 | COMBINE_HIDPI_IMAGES = YES; 344 | CURRENT_PROJECT_VERSION = 94; 345 | FRAMEWORK_SEARCH_PATHS = ( 346 | "$(inherited)", 347 | "$(PROJECT_DIR)/**", 348 | "$(PROJECT_DIR)/Carthage/Build/Mac", 349 | ); 350 | INFOPLIST_FILE = "Icns Composer/Info.plist"; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 352 | MARKETING_VERSION = 2020.11.0; 353 | OTHER_LDFLAGS = "-Wl,-rpath,@loader_path/../Frameworks"; 354 | PRODUCT_BUNDLE_IDENTIFIER = io.raphaelhanneken.icnscomposer; 355 | PRODUCT_NAME = "$(TARGET_NAME)"; 356 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 357 | SWIFT_VERSION = 5.0; 358 | }; 359 | name = Debug; 360 | }; 361 | 20FA7A791B14E9D900E7B8E7 /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ASSETCATALOG_COMPILER_APPICON_NAME = IcnsComposer; 365 | CODE_SIGN_IDENTITY = "-"; 366 | COMBINE_HIDPI_IMAGES = YES; 367 | CURRENT_PROJECT_VERSION = 94; 368 | FRAMEWORK_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "$(PROJECT_DIR)/**", 371 | "$(PROJECT_DIR)/Carthage/Build/Mac", 372 | ); 373 | INFOPLIST_FILE = "Icns Composer/Info.plist"; 374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 375 | MARKETING_VERSION = 2020.11.0; 376 | OTHER_LDFLAGS = "-Wl,-rpath,@loader_path/../Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = io.raphaelhanneken.icnscomposer; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 380 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 381 | SWIFT_VERSION = 5.0; 382 | }; 383 | name = Release; 384 | }; 385 | /* End XCBuildConfiguration section */ 386 | 387 | /* Begin XCConfigurationList section */ 388 | 20FA7A581B14E9D900E7B8E7 /* Build configuration list for PBXProject "Icns Composer" */ = { 389 | isa = XCConfigurationList; 390 | buildConfigurations = ( 391 | 20FA7A751B14E9D900E7B8E7 /* Debug */, 392 | 20FA7A761B14E9D900E7B8E7 /* Release */, 393 | ); 394 | defaultConfigurationIsVisible = 0; 395 | defaultConfigurationName = Release; 396 | }; 397 | 20FA7A771B14E9D900E7B8E7 /* Build configuration list for PBXNativeTarget "Icns Composer" */ = { 398 | isa = XCConfigurationList; 399 | buildConfigurations = ( 400 | 20FA7A781B14E9D900E7B8E7 /* Debug */, 401 | 20FA7A791B14E9D900E7B8E7 /* Release */, 402 | ); 403 | defaultConfigurationIsVisible = 0; 404 | defaultConfigurationName = Release; 405 | }; 406 | /* End XCConfigurationList section */ 407 | }; 408 | rootObject = 20FA7A551B14E9D900E7B8E7 /* Project object */; 409 | } 410 | -------------------------------------------------------------------------------- /Icns Composer/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | @NSApplicationMain 10 | class AppDelegate: NSObject, NSApplicationDelegate { 11 | 12 | var mainWindowController: MainWindowController? 13 | 14 | func applicationDidFinishLaunching(_: Notification) { 15 | let mainWindowController = MainWindowController() 16 | mainWindowController.showWindow(self) 17 | 18 | self.mainWindowController = mainWindowController 19 | } 20 | 21 | // Reopen mainWindow, when the user clicks on the dock icon. 22 | func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool { 23 | if let mainWindowController = self.mainWindowController { 24 | mainWindowController.showWindow(self) 25 | } 26 | return true 27 | } 28 | 29 | func applicationWillTerminate(_: Notification) { 30 | // Insert code here to tear down your application 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon-32.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon-32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon-64.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon-128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon-256.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon-256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon-512.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon-512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon-1024.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-1024.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-128.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-16.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-256.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-32.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-512.png -------------------------------------------------------------------------------- /Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/Icns Composer/Assets.xcassets/IcnsComposer.appiconset/icon-64.png -------------------------------------------------------------------------------- /Icns Composer/DragDropImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DragAndDropImageView.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | class DragDropImageView: NSImageView, NSDraggingSource { 10 | 11 | /// Holds the last mouse down event, to track the drag distance. 12 | var mouseDownEvent: NSEvent? 13 | 14 | override init(frame frameRect: NSRect) { 15 | super.init(frame: frameRect) 16 | 17 | // Assure editable is set to true, to enable drop capabilities. 18 | isEditable = true 19 | } 20 | 21 | required init?(coder: NSCoder) { 22 | super.init(coder: coder) 23 | 24 | // Assure editable is set to true, to enable drop capabilities. 25 | isEditable = true 26 | } 27 | 28 | override func draw(_ dirtyRect: NSRect) { 29 | super.draw(dirtyRect) 30 | } 31 | 32 | // MARK: - NSDraggingSource 33 | 34 | // Since we only want to copy/delete the current image we register ourselfes 35 | // for .Copy and .Delete operations. 36 | func draggingSession(_: NSDraggingSession, sourceOperationMaskFor _: NSDraggingContext) -> NSDragOperation { 37 | return NSDragOperation.copy.union(.delete) 38 | } 39 | 40 | // Clear the ImageView on delete operation; e.g. the image gets 41 | // dropped on the trash can in the dock. 42 | func draggingSession(_: NSDraggingSession, endedAt _: NSPoint, operation: NSDragOperation) { 43 | if operation == .delete { 44 | image = nil 45 | } 46 | } 47 | 48 | // Track mouse down events and safe the to the poperty. 49 | override func mouseDown(with theEvent: NSEvent) { 50 | mouseDownEvent = theEvent 51 | } 52 | 53 | // Track mouse dragged events to handle dragging sessions. 54 | override func mouseDragged(with theEvent: NSEvent) { 55 | // Get the image to drag 56 | guard let image = image else { 57 | return 58 | } 59 | // Calculate the drag distance... 60 | guard let mouseDown = mouseDownEvent?.locationInWindow else { 61 | return 62 | } 63 | let dragPoint = theEvent.locationInWindow 64 | let dragDistance = hypot(mouseDown.x - dragPoint.x, mouseDown.y - dragPoint.y) 65 | 66 | // ...to cancel the dragging session in case of accidental drag. 67 | if dragDistance < 3 { 68 | return 69 | } 70 | 71 | // Do some math to properly resize the given image. 72 | let size = NSSize(width: log10(image.size.width) * 30, height: log10(image.size.height) * 30) 73 | 74 | if let img = image.resize(toSize: size) { 75 | // Create a new NSDraggingItem with the image as content. 76 | let draggingItem = NSDraggingItem(pasteboardWriter: image) 77 | // Calculate the mouseDown location from the window's coordinate system to the ImageViews 78 | // coordinate system, to use it as origin for the dragging frame. 79 | let draggingFrameOrigin = convert(mouseDown, from: nil) 80 | // Build the dragging frame and offset it by half the image size on each axis 81 | // to center the mouse cursor within the dragging frame. 82 | let draggingFrame = NSRect(origin: draggingFrameOrigin, size: img.size).offsetBy(dx: -img.size.width / 2, 83 | dy: -img.size.height / 2) 84 | 85 | // Assign the dragging frame to the draggingFrame property of our dragging item. 86 | draggingItem.draggingFrame = draggingFrame 87 | 88 | // Provide the components of the dragging image. 89 | draggingItem.imageComponentsProvider = { 90 | let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon) 91 | component.contents = image 92 | component.frame = NSRect(origin: NSPoint(), size: draggingFrame.size) 93 | 94 | return [component] 95 | } 96 | 97 | // Begin actual dragging session. Woohow! 98 | beginDraggingSession(with: [draggingItem], event: mouseDownEvent!, source: self) 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Icns Composer/IconImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IconImage.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | /// The scales of an icon image. 10 | /// 11 | /// - scale1x: An image scale of @1x 12 | /// - scale2x: An image scale of @2x 13 | enum ImageScale: String { 14 | case scale1x = "@1x" 15 | case scale2x = "@2x" 16 | } 17 | 18 | struct IconImage { 19 | 20 | /// The image object. 21 | let image: NSImage? 22 | 23 | /// The scale of the image object. 24 | let scale: ImageScale 25 | 26 | /// The images size. 27 | let size: NSSize 28 | 29 | /// The filename of the icon image based on it's size and scale, e.g. icon_32x32@2x.png 30 | var filename: String { 31 | switch scale { 32 | case .scale1x: 33 | return "icon_\(Int(size.width))x\(Int(size.height))\(scale.rawValue).png" 34 | case .scale2x: 35 | return "icon_\(Int(size.width / 2))x\(Int(size.height / 2))\(scale.rawValue).png" 36 | } 37 | } 38 | 39 | /// Initializes a new iconset image. 40 | /// 41 | /// - parameter image: The NSImage object, the IconImage should. 42 | /// - parameter size: The NSSize the supplied image should be resized to. 43 | /// - parameter scale: The scale type of the image. 44 | init?(_ image: NSImage?, withSize size: NSSize, andScale scale: ImageScale) { 45 | guard let image = image else { 46 | return nil 47 | } 48 | 49 | self.image = image.resize(toSize: size) 50 | self.scale = scale 51 | self.size = size 52 | } 53 | 54 | /// Writes the iconset image to the given url. 55 | /// 56 | /// - parameter url: The url to save the image to. 57 | func writeToURL(_ url: URL) throws { 58 | let imgURL = url.appendingPathComponent(filename, isDirectory: false) 59 | 60 | if let png = image?.PNGRepresentation { 61 | try png.write(to: imgURL, options: .atomic) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Icns Composer/Iconset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Iconset.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | /// Error cases for icns file generation 10 | /// 11 | /// - missingURL: The given URL, to save the icns file to, is missing. 12 | enum IconsetError: Error { 13 | case missingURL 14 | } 15 | 16 | struct Iconset { 17 | 18 | /// The necessary images to create an iconset that conforms iconutil 19 | var images: [String: IconImage] 20 | 21 | /// Initializes a new Iconset 22 | init() { 23 | images = [String: IconImage]() 24 | } 25 | 26 | /// Subscript to access a specific image inside the Iconset by it's filename. 27 | /// 28 | /// - parameter filename: The filename of the image to access 29 | subscript(filename: String) -> IconImage? { 30 | get { return images[filename] } 31 | set { images[filename] = newValue } 32 | } 33 | 34 | /// Saves an icns file to the supplied url. 35 | /// 36 | /// - parameter url: URL to save the icns file to. 37 | /// - throws: A MissingURL error, when the supplied url can't be unwrapped. 38 | func writeToURL(_ url: URL?) throws { 39 | guard let url = url else { 40 | throw IconsetError.missingURL 41 | } 42 | 43 | let tmpURL = try writeToTemporaryDir() 44 | try runIconUtilWithInput(tmpURL, andOutputURL: url) 45 | 46 | NSWorkspace.shared.open(url.deletingLastPathComponent()) 47 | } 48 | 49 | /// Create a new iconset within the user's temp directory. 50 | /// 51 | /// - returns: The URL where the iconset were written to. 52 | fileprivate func writeToTemporaryDir() throws -> URL { 53 | let icnSet = "\(Int(arc4random_uniform(99999) + 10000)).iconset/" 54 | let tmpURL = URL(fileURLWithPath: NSTemporaryDirectory() + icnSet, isDirectory: true) 55 | 56 | try FileManager.default.createDirectory(at: tmpURL, withIntermediateDirectories: true, attributes: nil) 57 | 58 | for (_, image) in images { 59 | try image.writeToURL(tmpURL) 60 | } 61 | 62 | return tmpURL 63 | } 64 | 65 | /// Executes iconutil with the given url as input path. 66 | /// 67 | /// - parameter input: Path to a convertable iconset directory. 68 | /// - parameter output: Path to the location, where to save the generated icns file. 69 | /// - throws: Throws a MissingURL error, in case one of the supplied urls cant be unwrapped. 70 | private func runIconUtilWithInput(_ input: URL?, andOutputURL output: URL?) throws { 71 | guard let input = input, var output = output else { 72 | throw IconsetError.missingURL 73 | } 74 | 75 | if output.pathExtension != "icns" { 76 | output = output.appendingPathExtension("icns") 77 | } 78 | 79 | let iconUtil = Process() 80 | 81 | iconUtil.launchPath = "/usr/bin/iconutil" 82 | iconUtil.arguments = ["-c", "icns", "-o", output.path, input.path] 83 | iconUtil.launch() 84 | iconUtil.waitUntilExit() 85 | 86 | try FileManager.default.removeItem(at: input) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Icns Composer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSApplicationCategoryType 26 | public.app-category.developer-tools 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSAppTransportSecurity 30 | 31 | NSExceptionDomains 32 | 33 | github-cloud.s3.amazonaws.com 34 | 35 | NSIncludesSubdomains 36 | 37 | NSTemporaryExceptionAllowsInsecureHTTPLoads 38 | 39 | 40 | github.com 41 | 42 | NSIncludesSubdomains 43 | 44 | NSTemporaryExceptionAllowsInsecureHTTPLoads 45 | 46 | 47 | raphaelhanneken.com 48 | 49 | NSIncludesSubdomains 50 | 51 | NSTemporaryExceptionAllowsInsecureHTTPLoads 52 | 53 | 54 | raphaelhanneken.github.io 55 | 56 | NSIncludesSubdomains 57 | 58 | NSTemporaryExceptionAllowsInsecureHTTPLoads 59 | 60 | 61 | 62 | 63 | NSHumanReadableCopyright 64 | Copyright © 2015 Raphael Hanneken. All rights reserved. 65 | NSMainNibFile 66 | MainMenu 67 | NSPrincipalClass 68 | NSApplication 69 | SUFeedURL 70 | https://raphaelhanneken.github.io/icnscomposer/sparkle/appcast.xml 71 | SUPublicDSAKeyFile 72 | dsa_pub.pem 73 | 74 | 75 | -------------------------------------------------------------------------------- /Icns Composer/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | Default 541 | 542 | 543 | 544 | 545 | 546 | 547 | Left to Right 548 | 549 | 550 | 551 | 552 | 553 | 554 | Right to Left 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | Default 566 | 567 | 568 | 569 | 570 | 571 | 572 | Left to Right 573 | 574 | 575 | 576 | 577 | 578 | 579 | Right to Left 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | -------------------------------------------------------------------------------- /Icns Composer/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Icns Composer/MainWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowController.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | /// Manages the MainWindow.xib. 10 | class MainWindowController: NSWindowController, NSWindowDelegate { 11 | 12 | /// Handles creation of the .icns file. 13 | var iconset = Iconset() 14 | 15 | override var windowNibName: NSNib.Name { 16 | return "MainWindow" 17 | } 18 | 19 | /// Starts the export process for the current iconset. 20 | /// 21 | /// - parameter sender: NSToolbarItem that sent the export message. 22 | @IBAction func export(_: NSToolbarItem) { 23 | guard let window = window else { 24 | return 25 | } 26 | 27 | let dialog = NSSavePanel() 28 | dialog.allowedFileTypes = ["icns"] 29 | dialog.allowsOtherFileTypes = false 30 | dialog.beginSheetModal(for: window) { (result: NSApplication.ModalResponse) -> Void in 31 | if result != NSApplication.ModalResponse.OK { 32 | return 33 | } 34 | 35 | do { 36 | try self.iconset.writeToURL(dialog.url) 37 | } catch { 38 | let alert = NSAlert() 39 | alert.messageText = "Oh snap!" 40 | alert.informativeText = "Something went somewhere terribly wrong." 41 | alert.beginSheetModal(for: window, completionHandler: nil) 42 | } 43 | } 44 | } 45 | 46 | /// Gets called everytime a user drops an image onto a connected NSImageView. 47 | /// Resizes the dropped images to the appropriate size and adds them to the icon object. 48 | /// 49 | /// - parameter sender: The NSImageView that the images have been assigned to. 50 | @IBAction func resize(_ sender: NSImageView) { 51 | let img = IconImage(sender.image, 52 | withSize: NSSize(width: Int(sender.tag / 2), height: Int(sender.tag / 2)), 53 | andScale: .scale1x) 54 | 55 | let img2x = IconImage(sender.image, 56 | withSize: NSSize(width: sender.tag, height: sender.tag), 57 | andScale: .scale2x) 58 | 59 | if let filename1x = img?.filename, let filename2x = img2x?.filename { 60 | iconset[filename1x] = img 61 | iconset[filename2x] = img2x 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Icns Composer/NSImageExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSImageExtensions.swift 3 | // Icns Composer 4 | // https://github.com/raphaelhanneken/icnscomposer 5 | // 6 | 7 | import Cocoa 8 | 9 | /// Exceptions for the image extension class. 10 | /// 11 | /// - creatingPngRepresentationFailed: Is thrown when the creation of the png representation failed. 12 | enum NSImageExtensionError: Error { 13 | case creatingPngRepresentationFailed 14 | } 15 | 16 | extension NSImage { 17 | 18 | var height: CGFloat { 19 | return size.height 20 | } 21 | 22 | var width: CGFloat { 23 | return size.width 24 | } 25 | 26 | var PNGRepresentation: Data? { 27 | if let tiff = self.tiffRepresentation, let tiffData = NSBitmapImageRep(data: tiff) { 28 | return tiffData.representation(using: .png, properties: [:]) 29 | } 30 | return nil 31 | } 32 | 33 | /// Resizes the image to the given size. 34 | /// 35 | /// - parameter size: The size to resize the image to. 36 | /// - returns: The resized image. 37 | func resize(toSize size: NSSize) -> NSImage? { 38 | let frame = NSRect(x: 0, y: 0, width: size.width, height: size.height) 39 | guard let rep = self.bestRepresentation(for: frame, context: nil, hints: nil) else { 40 | return nil 41 | } 42 | 43 | let img = NSImage(size: size, flipped: false, drawingHandler: { (_) -> Bool in 44 | 45 | if rep.draw(in: frame) { 46 | return true 47 | } 48 | return false 49 | }) 50 | 51 | return img 52 | } 53 | 54 | /// Copies the image and resizes it to the supplied size, while maintaining it's 55 | /// original aspect ratio. 56 | /// 57 | /// - parameter size: The target size of the image. 58 | /// - returns: The resized image. 59 | func resizeMaintainingAspectRatio(withSize size: NSSize) -> NSImage? { 60 | let newSize: NSSize 61 | 62 | let widthRatio = size.width / width 63 | let heightRatio = size.height / height 64 | 65 | if widthRatio > heightRatio { 66 | newSize = NSSize(width: floor(width * widthRatio), 67 | height: floor(height * widthRatio)) 68 | } else { 69 | newSize = NSSize(width: floor(width * heightRatio), 70 | height: floor(height * heightRatio)) 71 | } 72 | return resize(toSize: newSize) 73 | } 74 | 75 | /// Resizes the image, to nearly fit the supplied cropping size 76 | /// and return a cropped copy the image. 77 | /// 78 | /// - parameter size: The size of the new image. 79 | /// - returns: The cropped image. 80 | func crop(toSize: NSSize) -> NSImage? { 81 | guard let resized = self.resizeMaintainingAspectRatio(withSize: size) else { 82 | return nil 83 | } 84 | 85 | // swiftlint:disable identifier_name 86 | let x = floor((resized.width - size.width) / 2) 87 | let y = floor((resized.height - size.height) / 2) 88 | let frame = NSRect(x: x, y: y, width: width, height: height) 89 | 90 | guard let rep = resized.bestRepresentation(for: frame, context: nil, hints: nil) else { 91 | return nil 92 | } 93 | 94 | let img = NSImage(size: size) 95 | defer { img.unlockFocus() } 96 | img.lockFocus() 97 | 98 | if rep.draw(in: NSRect(x: 0, y: 0, width: width, height: height), 99 | from: frame, 100 | operation: NSCompositingOperation.copy, 101 | fraction: 1.0, 102 | respectFlipped: false, 103 | hints: [:]) { 104 | return img 105 | } 106 | 107 | return nil 108 | } 109 | 110 | /// Saves the images PNG representation to the supplied file URL. 111 | /// 112 | /// - parameter url: The file URL to save the png file to. 113 | /// - throws: An NSImageExtension Error. 114 | func savePngTo(url: URL) throws { 115 | guard let png = self.PNGRepresentation else { 116 | throw NSImageExtensionError.creatingPngRepresentationFailed 117 | } 118 | 119 | try png.write(to: url, options: .atomicWrite) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Icns Composer/dsa_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | 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 35 | 1YsaWKXC+YuvUFyVH3U= 36 | -----END PUBLIC KEY----- 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Raphael Hanneken 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Icns Composer # 2 | 3 | If you're like me, you love the high quality icons OS X provides. And you probably like to create your own icons for one or another app. Since Apple doesn't support 1024x1024 retina images with 'Icon Composer' anymore, at least as far as I know, I decided to create a small app that does. __Icns Composer__. You can simply drag and drop your image onto Icns Composer, just like you did with Apple's Icon Composer, and click Export. 4 | 5 | ![Screenshot](screenshot.png) 6 | 7 | 8 | 9 | #### Looking for a way to create Xcode image assets? #### 10 | You want to create Xcode image assets (*.xcassets)? Make sure to check out [Iconizer](http://behoernchen.github.io/iconizer/index.html)! 11 | 12 | 13 | ## How do I install it? ## 14 | 15 | You have two options: 16 | 17 | 1. Download the latest [release](https://github.com/behoernchen/IcnsComposer/releases) and drop it into your Applications folder. 18 | 2. Download the source code and build it with Xcode yourself. 19 | 20 | 21 | 22 | ## Contribute ## 23 | 24 | You can fork this project, right here on Github, make your awesome changes and send me a pull request. Just make sure to fork the latest development version. 25 | 26 | 27 | 28 | ---------- 29 | ### License ### 30 | 31 | The MIT License (MIT) 32 | 33 | Copyright (c) 2015 Raphael Hanneken 34 | 35 | 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: 36 | 37 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 38 | 39 | 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. 40 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphaelhanneken/icnscomposer/b36c0bac8e0448842b883cd3212ca84e3adae9df/screenshot.png --------------------------------------------------------------------------------