Danielle
Danielle

Reputation: 211

Xcode 11 PDF image assets "Preserve Vector Data" not working in SwiftUI?

I'm trying to use vector-based PDF images using "Single-Scale" in an app I'm working on using SwiftUI in Xcode 11, but the image always looks blurry when I scale it up in size.

I had no trouble with this in UIKit in Xcode 11. I created a dummy app with 2 scenes, both displaying the same vector image. I created the first scene in a storyboard, then used a HostingViewController to embed an identical scene made in SwiftUI. When I ran the app, the first scene (UIKit) displayed a crisp, non blurry image. The second (SwiftUI) scene however, was blurry and didn't appear to be using vector data, despite using the same source image asset.

I was able to "work around" this by creating a UIImage with the vector image, then using this UIImage extension to resize the UIImage before it's passed into Image. However, the size I enter in the resized(to:) method makes no difference at runtime, so I also have to add .frame(w:,h:) to image in 'var body' to make it show the correct size.

let uiImage = UIImage(named: "Logo-vector")!
var image: Image {
        Image(uiImage: uiImage.resized(to: CGSize(width: 500, height: 500)))
            .resizable()
}

var body: some View {
        NavigationView {
            VStack(alignment: .center, spacing: 8) {
                Spacer()
                Text("Logo vector SwiftUI")
                image
                    .frame(width: 240, height: 216)
                ...
                }
                ...
            }
        }
}

extension UIImage {
    func resized(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

The image is clear and properly resized at runtime with this workaround, but it feels like a bit of a hack.

I've looked everywhere online for a different solution or anyone else having this issue specifically with SwiftUI, but haven't found anything at all.

Has anyone else had this issue or does anyone have a better solution?

Upvotes: 20

Views: 6828

Answers (2)

Matt54
Matt54

Reputation: 144

I put together a cross-platform framework called ResizableVector which performs the same resizing method.

extension PlatformImage {
    func resized(to size: CGSize) -> PlatformImage {
        return GraphicsImageRenderer(size: size).image { _ in
            self.draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

Where PlatformImage is simply a typealias for UIImage or NSImage and GraphicsImageRenderer is a typealias for the UIGraphicsImageRenderer or MacGraphicsImageRenderer.

The framework provides a SwiftUI View named ResizableVector to use in place of Image. It can also respect the original aspect ratio, if desired.

You can add this using SPM - check it out on GitHub: https://github.com/Matt54/ResizableVector

Upvotes: 1

user12532341
user12532341

Reputation: 49

try enabling "IPreserve Vector Data" on each pdf image asset (select image in "Assets.xcassets" folder, then in "Attributes inspector > Image Set > Resizing")

Upvotes: 4

Related Questions