为什么在 SwiftUI 中调整 PDF 的大小会变得锐利?

Sim*_*men 11 pdf vector-graphics image-resizing swiftui

我尝试使用 Xcode 11.4 和 iOS 13.4 在支持 SwiftUI 的应用程序中包含 pdf。但是,当我调整 pdf 大小时,它的边缘会变得粗糙。我已经包含了 pdf 的两个版本:一个大 pdf ( icon.pdf) 和一个小 pdf ( icon_small.pdf)。当我调整大小时,icon.pdf它会开始边缘,而icon_small.pdf边缘会变得平滑。该问题也适用于我尝试过的所有其他 pdf。

在此处输入图片说明

这是我的代码:

struct ContentView: View {
    var body: some View {
        VStack {
            Spacer()
            Text("icon.pdf:")
            Image("icon")
                .resizable()
                .renderingMode(.template)
                .aspectRatio(contentMode: .fit)
                .frame(width: 27.0, height: 27.0)
            Spacer()
            Text("icon_small.pdf:")
            Image("icon_small")
            Spacer()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

双方icon.pdficon_small.pdf具有下列资产设置:

  • 渲染为:模板图像
  • 调整大小:保留矢量数据
  • 设备:通用
  • 秤:单秤

pdf 可在此处获得:

sta*_*Man 29

我使用您提供的矢量图像对两个矢量图像进行了并排比较:

起初,我使用了SwiftUI's inbuiltImage并且如前所述,两者在极端情况下都表现不佳:

  • 大图像在按比例缩小时有锐利的边缘
  • 小图像在放大时变得模糊

起初我认为这可能是你的 pdf 向量,所以我使用了我知道在我以前的项目中运行良好的向量,但我遇到了同样的问题。
认为这是一个UIImage问题,我使用了SwiftUIsImage(uiImage:)但同样的问题。

最后猜测是图像容器,并且知道它UIImageView已经很好地处理了矢量图像,UIViewRepresentable开始包装UIImageView似乎可以解决这个问题。现在它看起来像是一种可能的解决方法。

解决方法:

struct MyImageView: UIViewRepresentable {
  var name: String
  var contentMode: UIView.ContentMode = .scaleAspectFit
  var tintColor: UIColor = .black

  func makeUIView(context: Context) -> UIImageView {
    let imageView = UIImageView()
    imageView.setContentCompressionResistancePriority(.fittingSizeLevel, 
                                                      for: .vertical)
    return imageView
  }

  func updateUIView(_ uiView: UIImageView, context: Context) {
    uiView.contentMode = contentMode
    uiView.tintColor = tintColor
    if let image = UIImage(named: name) {
      uiView.image = image
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这会丢失一些SwiftUI Image修饰符(您仍然拥有普通View修饰符),但您始终可以传入一些参数,例如contentMode和 ,tintColor如上所示。如果需要,添加更多并进行相应处理。


用法示例:

struct ContentView: View {
  var body: some View {
    VStack {
      MyImageView(name: "icon", //REQUIRED
                  contentMode: .scaleAspectFit, //OPTIONAL
                  tintColor: .black /*OPTIONAL*/)
        .frame(width: 27, height: 27)
      MyImageView(name: "icon_small", //REQUIRED
                  contentMode: .scaleAspectFit, //OPTIONAL
                  tintColor: .black /*OPTIONAL*/)
        .frame(width: 27, height: 27)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在这都是推测,但看起来好像SwiftUI将矢量图像视为PNG.

以下示例是在UIKit'sUIImageViewSwiftUI's 中呈现的大小矢量图像的简单并排比较Image

比较:

struct ContentView: View {
  let (largeImage, smallImage) = ("icon", "icon_small")
  let range = stride(from: 20, to: 320, by: 40).map { CGFloat($0) }

  var body: some View {
    List(range, id: \.self) { (side) in
      ScrollView(.horizontal) {
        VStack(alignment: .leading) {
          Text(String(format: "%gx%g", side, side))
          HStack {
            VStack {
              Text("UIKit")
              MyImageView(name: self.smallImage)
                .frame(width: side, height: side)
              MyImageView(name: self.largeImage)
                .frame(width: side, height: side)
            }
            VStack {
              Text("SwiftUI")
              Image(self.smallImage)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: side)
              Image(self.largeImage)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: side)
            }
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

结果:

  1. 顶行;左:小图像输入UIImageView
  2. 顶行;右:小图像SwiftUI Image
  3. 底排;左:大图像输入UIImageView
  4. 底排;右:大图像SwiftUI Image

UIKit'sUIImageView具有一致的性能,而SwiftUI'sImage有问题。

20x20


60x60


100x100


180x180