Почему PDF-файлы с измененным размером в SwiftUI получают острые края? - PullRequest
2 голосов
/ 12 апреля 2020

Я пытаюсь включить PDF в мое приложение с поддержкой SwiftUI, используя Xcode 11.4 и iOS 13.4. Тем не менее, когда я изменяю размер PDF-файла, он получает крутые края. Я включил две версии PDF: один большой PDF (icon.pdf) и один маленький PDF (icon_small.pdf). Когда я изменяю размер icon.pdf, он получает начальные края, а icon_small.pdf - гладкие. Эта проблема относится ко всем другим PDF-файлам, которые я пробовал.

enter image description here

Это мой код:

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()
        }
    }
}

Оба icon.pdf и icon_small.pdf имеют следующие настройки активов:

  • Отображать как: шаблон изображения
  • Изменение размера: Сохранить векторные данные
  • Устройства: универсальные
  • Весы: один масштаб

PDF-файлы доступны здесь:

Ответы [ 2 ]

2 голосов
/ 13 апреля 2020

Я провел параллельное сравнение для обоих векторных изображений, используя предоставленные вами:

Сначала я использовал встроенный SwiftUI Image и, как уже упоминалось, оба плохо работали на своих крайних концах:

  • Большое изображение получило четкие края при уменьшении
  • Маленькое изображение было размыто при увеличении

Сначала я подумал, что это могут быть ваши векторы pdf, поэтому я использовал те, которые Я знаю, что хорошо работал в моих предыдущих проектах, но у меня были те же проблемы.
Думая, что это проблема UIImage, я использовал SwiftUI s Image(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
    }
  }
}

Это теряет некоторые 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)
    }
  }
}

Теперь это все предположение, но похоже, что SwiftUI рассматривает векторные изображения как PNG.

Следующий пример представляет собой простое параллельное сравнение малых и больших векторных изображений, отображаемых в UIKit * UIImageView и SwiftUI * 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)
            }
          }
        }
      }
    }
  }
}

Результаты:

  1. Верхний ряд; Слева: маленькое изображение в UIImageView
  2. Верхний ряд; Справа: маленькое изображение в SwiftUI Image
  3. Нижний ряд; Слева: большое изображение в UIImageView
  4. Нижний ряд; Справа: большое изображение в SwiftUI Image

UIKit UIImageView имеет стабильную производительность, в то время как SwiftUI * Image имеет проблемы.

20x20


60x60


100x100


180x180

0 голосов
/ 12 апреля 2020

По существу нет различий между двумя файлами PDF, за исключением того факта, что в одном случае координаты содержимого масштабируются с коэффициентом ~ 14,2.

Я бы предположил, что эта разница не в файлах PDF, а в механизме рендеринга, который вы используете для рисования содержимого. Обратите внимание, что PDF-файл использует прозрачность (он имеет постоянную альфа-сторону 0,4), поэтому расчеты смешивания могут привести к слегка отличающимся результатам на краях.

Глядя на два файла в Adobe Acrobat, масштабируется так, чтобы они были одинаковыми Размер на экране, между ними нет видимой разницы.

Увеличение вашего файла PNG Я вижу, что icon_small.pdf имеет сглаженные края, а icon.pdf - нет. Вы не говорите, что используете для рендеринга PDF-файлов в PNG, но я думаю, что вам придется обсудить это с авторами любого инструмента, который есть.

...