├── .gitignore ├── Images └── complete.png ├── LICENSE ├── README.md └── Resource ├── AppIconGenerator.swift └── input.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /Images/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/AppIconGenerator/e8f0f116bdac7d2a294c459acf57e12ee6d7ce2a/Images/complete.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 W_C__L 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AppIconGenerator 2 | ![Language](https://img.shields.io/badge/Language-%20swift4%20%20-red.svg) 3 | ![Language](https://img.shields.io/badge/Platform-%20macOS%20%20-red.svg) 4 | 5 | 一键生成AppIcon的swift脚本 (Generate the swift script for AppIcon) 6 | 7 | ## Requirements 8 | 9 | - swift4.0 10 | 11 | ## Features 12 | 13 | - 一键生成AppIcon 14 | - 支持iphone、ipad、Mac、AppleWatch和CarPlay 15 | 16 | ## Usage 17 | 18 | 进入Resource文件夹下,执行GenerationAppIcon.swift 19 | 20 | ```shell 21 | cd Resource 22 | swift AppIconGenerator.swift 23 | ``` 24 | 25 | ![](Images/complete.png) 26 | 27 | ## License 28 | 29 | GenerationAppIcon [MIT license](LICENSE). 30 | 31 | -------------------------------------------------------------------------------- /Resource/AppIconGenerator.swift: -------------------------------------------------------------------------------- 1 | // ************************************************** 2 | // * _____ * 3 | // * __ _ __ ___ \ / * 4 | // * \ \/ \/ / / __\ / / * 5 | // * \ _ / | (__ / / * 6 | // * \/ \/ \___/ / /__ * 7 | // * /_____/ * 8 | // * * 9 | // ************************************************** 10 | // Github :https://github.com/imwcl 11 | // HomePage:https://imwcl.com 12 | // CSDN :http://blog.csdn.net/wang631106979 13 | // 14 | // Created by 王崇磊 on 16/9/14. 15 | // Copyright © 2016年 王崇磊. All rights reserved. 16 | // 17 | // @class GenerationAppIcon.swift 18 | // @abstract 自动生成AppIcon的swift脚本 19 | // @discussion 一键生成AppIcon 20 | // 21 | 22 | import Foundation 23 | 24 | /// 完整的Contents.json数据 25 | let jsonStr = 26 | """ 27 | { 28 | "images" : [ 29 | { 30 | "size" : "20x20", 31 | "idiom" : "iphone", 32 | "filename" : "Icon-App-20x20@2x.png", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "size" : "20x20", 37 | "idiom" : "iphone", 38 | "filename" : "Icon-App-20x20@3x.png", 39 | "scale" : "3x" 40 | }, 41 | { 42 | "size" : "29x29", 43 | "idiom" : "iphone", 44 | "filename" : "Icon-App-29x29@1x.png", 45 | "scale" : "1x" 46 | }, 47 | { 48 | "size" : "29x29", 49 | "idiom" : "iphone", 50 | "filename" : "Icon-App-29x29@2x.png", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "size" : "29x29", 55 | "idiom" : "iphone", 56 | "filename" : "Icon-App-29x29@3x.png", 57 | "scale" : "3x" 58 | }, 59 | { 60 | "size" : "40x40", 61 | "idiom" : "iphone", 62 | "filename" : "Icon-App-40x40@2x.png", 63 | "scale" : "2x" 64 | }, 65 | { 66 | "size" : "40x40", 67 | "idiom" : "iphone", 68 | "filename" : "Icon-App-40x40@3x.png", 69 | "scale" : "3x" 70 | }, 71 | { 72 | "size" : "57x57", 73 | "idiom" : "iphone", 74 | "filename" : "Icon-App-57x57@1x.png", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "size" : "57x57", 79 | "idiom" : "iphone", 80 | "filename" : "Icon-App-57x57@2x.png", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "size" : "60x60", 85 | "idiom" : "iphone", 86 | "filename" : "Icon-App-60x60@2x.png", 87 | "scale" : "2x" 88 | }, 89 | { 90 | "size" : "60x60", 91 | "idiom" : "iphone", 92 | "filename" : "Icon-App-60x60@3x.png", 93 | "scale" : "3x" 94 | }, 95 | { 96 | "size" : "20x20", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-ipad-App-20x20@1x.png", 99 | "scale" : "1x" 100 | }, 101 | { 102 | "size" : "20x20", 103 | "idiom" : "ipad", 104 | "filename" : "Icon-ipad-App-20x20@2x.png", 105 | "scale" : "2x" 106 | }, 107 | { 108 | "size" : "29x29", 109 | "idiom" : "ipad", 110 | "filename" : "Icon-ipad-App-29x29@1x.png", 111 | "scale" : "1x" 112 | }, 113 | { 114 | "size" : "29x29", 115 | "idiom" : "ipad", 116 | "filename" : "Icon-ipad-App-29x29@2x.png", 117 | "scale" : "2x" 118 | }, 119 | { 120 | "size" : "40x40", 121 | "idiom" : "ipad", 122 | "filename" : "Icon-ipad-App-40x40@1x.png", 123 | "scale" : "1x" 124 | }, 125 | { 126 | "size" : "40x40", 127 | "idiom" : "ipad", 128 | "filename" : "Icon-ipad-App-40x40@2x.png", 129 | "scale" : "2x" 130 | }, 131 | { 132 | "size" : "50x50", 133 | "idiom" : "ipad", 134 | "filename" : "Icon-ipad-Small-50x50@1x.png", 135 | "scale" : "1x" 136 | }, 137 | { 138 | "size" : "50x50", 139 | "idiom" : "ipad", 140 | "filename" : "Icon-ipad-Small-50x50@2x.png", 141 | "scale" : "2x" 142 | }, 143 | { 144 | "size" : "72x72", 145 | "idiom" : "ipad", 146 | "filename" : "Icon-ipad-App-72x72@1x.png", 147 | "scale" : "1x" 148 | }, 149 | { 150 | "size" : "72x72", 151 | "idiom" : "ipad", 152 | "filename" : "Icon-ipad-App-72x72@2x.png", 153 | "scale" : "2x" 154 | }, 155 | { 156 | "size" : "76x76", 157 | "idiom" : "ipad", 158 | "filename" : "Icon-ipad-App-76x76@1x.png", 159 | "scale" : "1x" 160 | }, 161 | { 162 | "size" : "76x76", 163 | "idiom" : "ipad", 164 | "filename" : "Icon-ipad-App-76x76@2x.png", 165 | "scale" : "2x" 166 | }, 167 | { 168 | "size" : "83.5x83.5", 169 | "idiom" : "ipad", 170 | "filename" : "Icon-ipad-App-83.5x83.5@2x.png", 171 | "scale" : "2x" 172 | }, 173 | { 174 | "idiom" : "ios-marketing", 175 | "size" : "1024x1024", 176 | "filename" : "Icon-ios-App-1024x1024@1x.png", 177 | "scale" : "1x" 178 | }, 179 | { 180 | "idiom" : "car", 181 | "size" : "60x60", 182 | "filename" : "Icon-car-App-60x60@2x.png", 183 | "scale" : "2x" 184 | }, 185 | { 186 | "idiom" : "car", 187 | "size" : "60x60", 188 | "filename" : "Icon-car-App-60x60@3x.png", 189 | "scale" : "3x" 190 | }, 191 | { 192 | "idiom" : "mac", 193 | "size" : "16x16", 194 | "filename" : "Icon-mac-App-16x16@1x.png", 195 | "scale" : "1x" 196 | }, 197 | { 198 | "idiom" : "mac", 199 | "size" : "16x16", 200 | "filename" : "Icon-mac-App-16x16@2x.png", 201 | "scale" : "2x" 202 | }, 203 | { 204 | "idiom" : "mac", 205 | "size" : "32x32", 206 | "filename" : "Icon-mac-App-32x32@1x.png", 207 | "scale" : "1x" 208 | }, 209 | { 210 | "idiom" : "mac", 211 | "size" : "32x32", 212 | "filename" : "Icon-mac-App-32x32@2x.png", 213 | "scale" : "2x" 214 | }, 215 | { 216 | "idiom" : "mac", 217 | "size" : "128x128", 218 | "filename" : "Icon-mac-App-128x128@1x.png", 219 | "scale" : "1x" 220 | }, 221 | { 222 | "idiom" : "mac", 223 | "size" : "128x128", 224 | "filename" : "Icon-mac-App-128x128@2x.png", 225 | "scale" : "2x" 226 | }, 227 | { 228 | "idiom" : "mac", 229 | "size" : "256x256", 230 | "filename" : "Icon-mac-App-256x256@1x.png", 231 | "scale" : "1x" 232 | }, 233 | { 234 | "idiom" : "mac", 235 | "size" : "256x256", 236 | "filename" : "Icon-mac-App-256x256@2x.png", 237 | "scale" : "2x" 238 | }, 239 | { 240 | "idiom" : "mac", 241 | "size" : "512x512", 242 | "filename" : "Icon-mac-App-512x512@1x.png", 243 | "scale" : "1x" 244 | }, 245 | { 246 | "idiom" : "mac", 247 | "size" : "512x512", 248 | "filename" : "Icon-mac-App-512x512@2x.png", 249 | "scale" : "2x" 250 | }, 251 | { 252 | "size" : "24x24", 253 | "idiom" : "watch", 254 | "filename" : "Icon-watch-App-24x24@2x.png", 255 | "scale" : "2x", 256 | "role" : "notificationCenter", 257 | "subtype" : "38mm" 258 | }, 259 | { 260 | "size" : "27.5x27.5", 261 | "idiom" : "watch", 262 | "filename" : "Icon-watch-App-27.5x27.5@2x.png", 263 | "scale" : "2x", 264 | "role" : "notificationCenter", 265 | "subtype" : "42mm" 266 | }, 267 | { 268 | "size" : "29x29", 269 | "idiom" : "watch", 270 | "role" : "companionSettings", 271 | "filename" : "Icon-watch-App-29x29@2x.png", 272 | "scale" : "2x" 273 | }, 274 | { 275 | "size" : "29x29", 276 | "idiom" : "watch", 277 | "role" : "companionSettings", 278 | "filename" : "Icon-watch-App-29x29@3x.png", 279 | "scale" : "3x" 280 | }, 281 | { 282 | "size" : "40x40", 283 | "idiom" : "watch", 284 | "filename" : "Icon-watch-App-40x40@2x.png", 285 | "scale" : "2x", 286 | "role" : "appLauncher", 287 | "subtype" : "38mm" 288 | }, 289 | { 290 | "size" : "86x86", 291 | "idiom" : "watch", 292 | "filename" : "Icon-watch-App-86x86@2x.png", 293 | "scale" : "2x", 294 | "role" : "quickLook", 295 | "subtype" : "38mm" 296 | }, 297 | { 298 | "size" : "98x98", 299 | "idiom" : "watch", 300 | "filename" : "Icon-watch-App-98x98@2x.png", 301 | "scale" : "2x", 302 | "role" : "quickLook", 303 | "subtype" : "42mm" 304 | }, 305 | { 306 | "idiom" : "watch-marketing", 307 | "size" : "1024x1024", 308 | "filename" : "Icon-watch-App-1024x1024@1x.png", 309 | "scale" : "1x" 310 | } 311 | ], 312 | "info" : { 313 | "version" : 1, 314 | "author" : "xcode" 315 | } 316 | } 317 | """ 318 | 319 | struct AppIconImageItem: Codable { 320 | let size: String 321 | let idiom: String 322 | let filename: String 323 | let scale: String 324 | let role: String? 325 | let subtype: String? 326 | } 327 | 328 | struct AppIconInfo: Codable { 329 | let version: Int 330 | let author: String 331 | } 332 | 333 | struct AppIcon: Codable { 334 | var images: [AppIconImageItem] 335 | let info: AppIconInfo 336 | } 337 | 338 | struct AppIconType: OptionSet { 339 | let rawValue: Int 340 | 341 | static let iPhone = AppIconType(rawValue: 1 << 0) 342 | static let iPad = AppIconType(rawValue: 1 << 1) 343 | static let appleWatch = AppIconType(rawValue: 1 << 2) 344 | static let mac = AppIconType(rawValue: 1 << 3) 345 | static let carPlay = AppIconType(rawValue: 1 << 4) 346 | static let errorType = AppIconType(rawValue: 1 << 5) 347 | 348 | func getTypeStr() -> String { 349 | switch self { 350 | case .iPhone: 351 | return "iphone" 352 | case .iPad: 353 | return "ipad" 354 | case .appleWatch: 355 | return "watch" 356 | case .mac: 357 | return "mac" 358 | case .carPlay: 359 | return "car" 360 | default: 361 | return "error" 362 | } 363 | } 364 | 365 | /// 通过输入的字符串获得AppIconType 366 | /// 367 | /// - Parameter typeStr: 输入的typeStr 368 | /// - Returns: 返回的AppIconType 369 | static func getTypeAndTypes(typeStr: String) ->(type: AppIconType, types: [AppIconType]) { 370 | var type: AppIconType = .errorType 371 | var types = [AppIconType]() 372 | var strs = typeStr.components(separatedBy: ",") 373 | /// 去除重复数据 374 | strs = Array(Set(strs)) 375 | if strs.count != 0 { 376 | /// 通过strs获取到AppIconType的数组 377 | types = strs.map { 378 | switch $0 { 379 | case "1": 380 | return AppIconType.iPhone 381 | case "2": 382 | return AppIconType.iPad 383 | case "3": 384 | return AppIconType.appleWatch 385 | case "4": 386 | return AppIconType.mac 387 | case "5": 388 | return AppIconType.carPlay 389 | default: 390 | return AppIconType.errorType 391 | } 392 | }.filter { 393 | if $0 == AppIconType.errorType { 394 | return false 395 | } 396 | return true 397 | } 398 | type = AppIconType(types) 399 | } 400 | return (type, types) 401 | } 402 | } 403 | 404 | /// 获取image的分辨率 405 | /// 406 | /// - Parameter image: 传入的image 407 | /// - Returns: 返回的分辨率 408 | func getImageInfo(image: CGImage) -> (width: Int, height: Int) { 409 | let width = image.width 410 | let height = image.height 411 | print("图片分辨率:\(width) * \(height)") 412 | return (width, height) 413 | } 414 | 415 | /// 图片是否有效 416 | /// 417 | /// - Parameter info: 传入图片的分辨率 418 | /// - Returns: 返回结果 419 | func imageIsValid(info: (width: Int, height: Int)) -> Bool { 420 | if info.width < 1024 && info.height < 1024 { 421 | return false 422 | } 423 | return true 424 | } 425 | 426 | /// 通过输入的type获得相应的appIcon 427 | /// 428 | /// - Parameter typeStr: 输入的type 429 | /// - Returns: 返回的AppIcon 430 | func getAppIcon(typeStr: String) -> AppIcon? { 431 | if let jsonData = jsonStr.data(using: .utf8) { 432 | let decoder = JSONDecoder() 433 | do { 434 | var appIcon = try decoder.decode(AppIcon.self, from: jsonData) 435 | let typeAndTypes = AppIconType.getTypeAndTypes(typeStr: typeStr) 436 | if typeAndTypes.type != .errorType { 437 | let typeStrs: [String] = typeAndTypes.types.map { $0.getTypeStr() }.filter { $0 == "error" ? false : true } 438 | appIcon.images = appIcon.images.filter { 439 | if (typeAndTypes.type.contains(.iPhone) || typeAndTypes.type.contains(.iPad)), $0.idiom == "ios-marketing" { 440 | return true 441 | } 442 | if typeAndTypes.type.contains(.appleWatch), $0.idiom == "watch-marketing" { 443 | return true 444 | } 445 | return typeStrs.contains($0.idiom) 446 | } 447 | }else { 448 | return nil 449 | } 450 | if appIcon.images.count == 0 { 451 | return nil 452 | } 453 | return appIcon 454 | }catch { 455 | print("解析json失败") 456 | print(error.localizedDescription) 457 | } 458 | }else { 459 | print("解析json失败") 460 | } 461 | return nil 462 | } 463 | 464 | /// 创建contentsJson 465 | /// 466 | /// - Parameter appIcon: 传入的appIcon 467 | func createAppIconContentsJson(appIcon: AppIcon) { 468 | print("\n开始生成contentsJson\n") 469 | let encoder = JSONEncoder() 470 | do { 471 | encoder.outputFormatting = .prettyPrinted 472 | let appIconData = try encoder.encode(appIcon) 473 | if let appIconStr = String.init(data: appIconData, encoding: .utf8) { 474 | let contentJsonPath = "AppIcon.appiconset/Contents.json" 475 | let contentJsonUrl = URL(fileURLWithPath: contentJsonPath) 476 | try appIconStr.write(to: contentJsonUrl, atomically: true, encoding: .utf8) 477 | print("contentsJson生成成功\n") 478 | }else { 479 | print("contentsJson生成失败") 480 | } 481 | }catch { 482 | print(error.localizedDescription) 483 | } 484 | } 485 | 486 | /// 生成单个image 487 | /// 488 | /// - Parameters: 489 | /// - size: 图片的大小 490 | /// - scale: 倍数 491 | /// - filename: 文件名 492 | func createImage(size: CGSize, scale: CGFloat, image: CGImage, filename: String) { 493 | print("开始生成图片: \(filename)") 494 | let width = Int(size.width * scale) 495 | let height = Int(size.height * scale) 496 | let bitsPerComponent = image.bitsPerComponent 497 | let bytesPerRow = image.bytesPerRow 498 | let colorSpace = CGColorSpaceCreateDeviceRGB() 499 | 500 | if let context = CGContext.init(data: nil, 501 | width: width, 502 | height: height, 503 | bitsPerComponent: bitsPerComponent, 504 | bytesPerRow: bytesPerRow, 505 | space: colorSpace, 506 | bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) { 507 | context.interpolationQuality = .high 508 | context.draw(image, in: .init(origin: .zero, size: .init(width: width, height: height))) 509 | if let outputImage = context.makeImage() { 510 | let outputImagePath = "AppIcon.appiconset/\(filename)" 511 | let outputUrl = URL(fileURLWithPath: outputImagePath) as CFURL 512 | let destination = CGImageDestinationCreateWithURL(outputUrl, kUTTypePNG, 1, nil) 513 | if let destination = destination { 514 | CGImageDestinationAddImage(destination, outputImage, nil) 515 | if CGImageDestinationFinalize(destination) { 516 | print("图片: \(filename) 生成成功\n") 517 | }else { 518 | print("图片: \(filename) 生成失败\n") 519 | } 520 | } 521 | }else { 522 | print("图片: \(filename) 生成失败\n") 523 | } 524 | } 525 | } 526 | 527 | /// 通过imageItem获得item信息 528 | /// 529 | /// - Parameter imageItem: 传入的imageItem 530 | /// - Returns: 返回的信息 531 | func getImageItemInfo(imageItem: AppIconImageItem) -> (size: CGSize, scale: CGFloat)? { 532 | let sizeStrs = imageItem.size.components(separatedBy: "x") 533 | let scaleStrs = imageItem.scale.components(separatedBy: "x") 534 | if let width = sizeStrs.first, 535 | let height = sizeStrs.last, 536 | let scale = scaleStrs.first { 537 | let widthInt = CGFloat(Double(width) ?? 0) 538 | let heightInt = CGFloat(Double(height) ?? 0) 539 | let scaleInt = CGFloat(Double(scale) ?? 0) 540 | return (.init(width: widthInt, height: heightInt), scaleInt) 541 | } 542 | return nil 543 | } 544 | 545 | /// 根据appIcon生成images 546 | /// 547 | /// - Parameter appIcon: appIcon 548 | func createImages(appIcon: AppIcon, image: CGImage) { 549 | print("开始生成Images\n") 550 | for imageitem in appIcon.images { 551 | if let info = getImageItemInfo(imageItem: imageitem) { 552 | createImage(size: info.size, scale: info.scale, image: image, filename: imageitem.filename) 553 | }else { 554 | let encoder = JSONEncoder() 555 | do { 556 | encoder.outputFormatting = .prettyPrinted 557 | let imageitemData = try encoder.encode(imageitem) 558 | if let imageitemStr = String.init(data: imageitemData, encoding: .utf8) { 559 | print("json 格式不对:\(imageitemStr)") 560 | }else { 561 | print("json 格式不对") 562 | } 563 | }catch { 564 | print(error.localizedDescription) 565 | } 566 | } 567 | } 568 | } 569 | 570 | /// 创建appicon文件 571 | /// 572 | /// - Parameter appIcon: appicon 573 | func createFile(appIcon: AppIcon, image: CGImage) { 574 | let fileManager = FileManager.default 575 | let filePath = "AppIcon.appiconset" 576 | do { 577 | if fileManager.fileExists(atPath: filePath) { 578 | try fileManager.removeItem(atPath: filePath) 579 | } 580 | try fileManager.createDirectory(atPath: filePath, withIntermediateDirectories: true, attributes: nil) 581 | createAppIconContentsJson(appIcon: appIcon) 582 | createImages(appIcon: appIcon, image: image) 583 | print("~~~~~~~~~~~~~~完成~~~~~~~~~~~~~~") 584 | }catch { 585 | print("文件目录\(filePath)创建失败") 586 | print(error.localizedDescription) 587 | } 588 | } 589 | 590 | /// 开始选择AppIcon类型 591 | func selectAppIconType(image: CGImage) { 592 | print( 593 | """ 594 | \n请输入想要转换Icon类型的编号(可多选,用,号隔开,例如:1,2,4,默认为1): 595 | 1.iPhone 596 | 2.iPad 597 | 3.AppleWatch 598 | 4.Mac 599 | 5.CarPlay 600 | """ 601 | ) 602 | if var typeStr = readLine() { 603 | if typeStr.count == 0 { 604 | typeStr = "1" 605 | } 606 | if let appIcon = getAppIcon(typeStr: typeStr) { 607 | createFile(appIcon: appIcon, image: image) 608 | }else { 609 | print("输入的类型格式有误,请输入例如:1,2,4") 610 | } 611 | }else { 612 | print("获取Icon类型失败") 613 | } 614 | } 615 | 616 | func detailInputImage(url: URL) { 617 | do{ 618 | let inoutData = try Data(contentsOf: url) 619 | print("图片大小:\(inoutData.count / 1024) kb") 620 | let dataProvider = CGDataProvider(data: inoutData as CFData) 621 | if let inputImage = CGImage(pngDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent) { 622 | if imageIsValid(info: getImageInfo(image: inputImage)) { 623 | selectAppIconType(image: inputImage) 624 | }else { 625 | print("图片的分辨率不能小于1024x1024") 626 | } 627 | }else { 628 | print("转换失败,图片必须是png格式") 629 | } 630 | }catch { 631 | print(error.localizedDescription) 632 | } 633 | } 634 | 635 | func start() { 636 | print( 637 | """ 638 | ************************************************** 639 | * _____ * 640 | * __ _ __ ___ \\ / * 641 | * \\ \\/ \\/ / / __\\ / / * 642 | * \\ _ / | (__ / / * 643 | * \\/ \\/ \\___/ / /__ * 644 | * /_____/ * 645 | * * 646 | ************************************************** 647 | Github :https://github.com/imwcl 648 | HomePage:https://imwcl.com 649 | CSDN :http://blog.csdn.net/wang631106979 \n 650 | """ 651 | ) 652 | print("请输入输入图片名(默认为input.png):") 653 | if var inputPath = readLine() { 654 | if inputPath.count == 0 { 655 | inputPath = "input.png" 656 | } 657 | let url = URL(fileURLWithPath: inputPath) 658 | detailInputImage(url: url) 659 | } else { 660 | print("输入失败") 661 | } 662 | } 663 | 664 | start() 665 | 666 | 667 | -------------------------------------------------------------------------------- /Resource/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/AppIconGenerator/e8f0f116bdac7d2a294c459acf57e12ee6d7ce2a/Resource/input.png --------------------------------------------------------------------------------