diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024x1024.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024x1024.png index 382e6d5..ebca93c 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024x1024.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024x1024.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20.png index 4638526..6c4734b 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png index 8df75dd..3e538a8 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29.png index 1c8ec18..6b44ff7 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png index eaadf69..2ecc455 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40.png index 8df75dd..3e538a8 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png index a3c4e13..2e6671d 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76.png index ff0963e..23ac28b 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png index 0184330..73e06fd 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83.5x83.5@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83.5x83.5@2x.png index 4486aa8..912a8c7 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83.5x83.5@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83.5x83.5@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png index 8df75dd..3e538a8 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png index 3bef99e..eea0de7 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png index eaadf69..2ecc455 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png index b22fe14..02c32e1 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png index a3c4e13..2e6671d 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png index 9c0e64e..4990796 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png index 9c0e64e..4990796 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png index 50347f7..bf1e089 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png index 8426ce7..8d4a071 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png index 92e51b9..a62957e 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-128x128@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png index 52bc97c..38d2926 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png index 0f6117e..8f4e69e 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-16x16@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png index 92e51b9..a62957e 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png index 508ae7b..f501df0 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-256x256@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png index 0f6117e..8f4e69e 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png index a88e47f..ea4317c 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-32x32@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png index 508ae7b..f501df0 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512.png differ diff --git a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png index 2907040..22ae5e6 100644 Binary files a/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png and b/Example/IconHarness/Assets.xcassets/AppIcon.appiconset/AppIcon-mac-512x512@2x.png differ diff --git a/Example/IconHarness/Assets.xcassets/Contents.json b/Example/IconHarness/Assets.xcassets/Contents.json index da4a164..73c0059 100644 --- a/Example/IconHarness/Assets.xcassets/Contents.json +++ b/Example/IconHarness/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Sources/SwiftUIcon/IconGenerator.swift b/Sources/SwiftUIcon/IconGenerator.swift index 08fd1c4..67970ce 100644 --- a/Sources/SwiftUIcon/IconGenerator.swift +++ b/Sources/SwiftUIcon/IconGenerator.swift @@ -155,8 +155,11 @@ struct IconSet: Encodable { for image in images { if !image.placeholder, let filename = image.filename { - let data = try content.generateImageData(size: image.size * image.scale.multiplier, roundedFrame: image.idiom == .mac) - try data.write(to: iconSetUrl.appendingPathComponent(filename)) + try content.writeImage( + to: iconSetUrl.appendingPathComponent(filename), + size: image.size * image.scale.multiplier, + roundedFrame: image.idiom == .mac + ) } } @@ -201,33 +204,64 @@ extension CGSize { enum GenerationError: Error { case couldNotGetImageRep case couldNotGeneratePNG + case couldNotWriteImage } @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension View { /// Generates an image from the current View + /// - Parameter url: The file url to write the image /// - Parameter size: The size of the image to generate /// - Parameter roundedFrame: Whether the image should be clipped to macOS like rounded frame or not - func generateImageData(size: CGSize, roundedFrame: Bool) throws -> Data { + public func writeImage(to url: URL, size: CGSize, roundedFrame: Bool = false) throws { + + // works around FB9488576 by scaling up the view, and then scaling down the rasterized image + let upscaledSize = CGSize(width: size.width * 4.0, height: size.height * 4.0) + let wrapper = roundedFrame - ? NSHostingView(rootView: self.frameIcon(dimension: min(size.width, size.height) * 0.8)) + ? NSHostingView(rootView: self.frameIcon(dimension: min(upscaledSize.width, upscaledSize.height) * 0.8)) : NSHostingView(rootView: self) - wrapper.frame = CGRect(origin: .zero, size: size) + wrapper.frame = CGRect(origin: .zero, size: upscaledSize) - let frame = CGRect(origin: .zero, size: wrapper.convertFromBacking(wrapper.bounds.size)) - guard let bitmapRepresentation = wrapper.bitmapImageRepForCachingDisplay(in: frame) else { + guard let bitmapRepresentation = wrapper.bitmapImageRepForCachingDisplay(in: wrapper.bounds) else { throw GenerationError.couldNotGetImageRep } bitmapRepresentation.size = wrapper.bounds.size wrapper.cacheDisplay(in: wrapper.bounds, to: bitmapRepresentation) - guard let data = bitmapRepresentation.representation(using: .png, properties: [:]) else { + guard let image = bitmapRepresentation.cgImage else { + throw GenerationError.couldNotGeneratePNG + } + + // generate a CGContext and draw the image into it at the desired size + let context = CGContext( + data: nil, + width: Int(size.width), + height: Int(size.height), + bitsPerComponent: image.bitsPerComponent, + bytesPerRow: 0, + space: image.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!, + bitmapInfo: image.bitmapInfo.rawValue + ) + + context?.interpolationQuality = .high + context?.draw(image, in: CGRect(origin: .zero, size: size)) + + guard let scaledImage = context?.makeImage() else { throw GenerationError.couldNotGeneratePNG } - return data + // write the image to disk + guard let destination = CGImageDestinationCreateWithURL(url as CFURL, kUTTypePNG, 1, nil) else { + throw GenerationError.couldNotWriteImage + } + + CGImageDestinationAddImage(destination, scaledImage, nil) + if !CGImageDestinationFinalize(destination) { + throw GenerationError.couldNotWriteImage + } } }