Фотографии из средства выбора изображений (UIImagePickerController), сделанные в портретном режиме, отображаются растянутыми - Xcode 11 / SwiftUI - PullRequest
2 голосов
/ 10 октября 2019

Я использую UIImagePickerController, чтобы сделать снимок с камеры или выбрать из библиотеки фотографий, а затем отобразить изображение. Это прекрасно работает для пейзажных / горизонтальных фотографий, но фотографии в портретной / вертикальной ориентации отображаются растянутыми по горизонтали.

Я пробовал .scaledToFit () и .aspectRatio (contentMode: .fit), но этовсе еще показывает растянутый. Любая помощь очень ценится.

Смотрите растянутое фото

Код для отображения изображения:

struct AddNewItem: View     {

@State private var showImagePicker: Bool = true
@State private var image: UIImage = nil
@State var showCamera: Bool = false
@State private var showImageEditor: Bool = false


var body: some View {
    VStack {

        Image(uiImage: image ?? UIImage(named: "placeholder")!)
            .resizable()
            .scaledToFit()
            .aspectRatio(contentMode: .fit)

    }
    //Show the photo capture view
    .sheet(isPresented: self.$showImagePicker) {
        PhotoCaptureView(showImagePicker: self.$showImagePicker, image: self.$image, showImageEditor: self.$showImageEditor, showCamera: self.$showCamera)
    }
}

}

ИзображениеКоординатор выбора:

class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

@Binding var isShown: Bool
@Binding var image: UIImage?
@Binding var showEditor: Bool

init(isShown: Binding<Bool>, image: Binding<UIImage?>, showEditor: Binding<Bool>) {
    _isShown = isShown
    _image = image
    _showEditor = showEditor
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
    image = uiImage
    isShown = false
    showEditor = true
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    isShown = false
}

}

Выбор изображения:

struct ImagePicker: UIViewControllerRepresentable {

@Binding var pickerIsShown: Bool
@Binding var image: UIImage?
@Binding var showImageEditor: Bool
@Binding var showCamera: Bool

func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

}

func makeCoordinator() -> ImagePickerCoordinator {
    return ImagePickerCoordinator(isShown: $pickerIsShown, image: $image, showEditor: $showImageEditor)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {

    let picker = UIImagePickerController()

    if showCamera {
        picker.sourceType = .camera
    } else {
        picker.sourceType = .photoLibrary
    }

    picker.delegate = context.coordinator

    return picker
}

} ​​

Просмотр захвата фотографий:

struct PhotoCaptureView: View {

@Binding var showImagePicker: Bool
@Binding var image: UIImage?
@Binding var showImageEditor: Bool
@Binding var showCamera: Bool

var body: some View {
    ImagePicker(pickerIsShown: $showImagePicker, image: $image, showImageEditor: $showImageEditor, showCamera: $showCamera)
}

}

Ответы [ 3 ]

1 голос
/ 13 октября 2019

У меня та же проблема. Мне удалось избежать этого, установив editMode в true внутри функции makeUIViewController:

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
    let imagePicker = UIImagePickerController()
    imagePicker.allowsEditing = true
    imagePicker.delegate = context.coordinator
    return imagePicker
}

И используя отредактированное изображение вместо исходного внутри didFinishPickingMedia с функцией info:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard let image = info[.editedImage] as? UIImage else {
            print("No image found")
            return
        }
        parent.imageController.originalImage = image
        parent.showImagePicker = false
    }

Это предотвращает растяжение изображения. Однако пользователь может выбрать только фотографию, которая будет обрезана как квадрат. Я работаю над обходным путем ..

0 голосов
/ 18 октября 2019

Решил проблему, перерисовав изображение в графическом контексте перед отображением:

func redraw(image: UIImage) -> UIImage? {
  let renderer = UIGraphicsImageRenderer(size: image.size)
  return renderer.image { (context) in
      image.draw(in: CGRect(origin: .zero, size: image.size))
  }
}

С обернутым UIImagePickerController:

struct ImagePickerController: UIViewControllerRepresentable {
  @Binding var image: UIImage?

  func makeCoordinator() -> ImagePickerController.Coordinator {
    Coordinator(self)
  }

  func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerController>) -> UIImagePickerController {
    let imagePicker = UIImagePickerController()
    imagePicker.delegate = context.coordinator
    imagePicker.sourceType = .camera

    return imagePicker
  }

  func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePickerController>) {

  }

  class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    var controller: ImagePickerController

    init(_ controller: ImagePickerController) {
      self.controller = controller
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
      picker.dismiss(animated: true, completion: nil)

      guard let image = info[.originalImage] as? UIImage else {
        return
      }

      // Need to draw in Graphics Context to fix SwiftUI aspect ratio issue
      let redrawnImage = redraw(image: image)!

      controller.image = redrawnImage
    }
  }
}

Представлено в представлении SwiftUI в виде листа:

struct CameraPicker: View {
  @State var isOpen = false
  @State var image: UIImage?

  var body: some View {
    VStack {
      if image != nil {
        Image(uiImage: image!)
          .resizable()
          .scaledToFit()
          .frame(width: 60, height: 60, alignment: .center)
      }

      Button(action: {
        self.isOpen = true
      }) { Text("Take Photo") }
    }
  }.sheet(isPresented: $isOpen, onDismiss: {
    self.isOpen = false
  }, content: {
    ImagePickerController(image: self.$image)
  })
}
0 голосов
/ 17 октября 2019

Я закончил работу, получив размеры каждого изображения для вычисления соотношения сторон, а затем применив соотношение сторон вручную с помощью .aspectRatio (self.imageAspectRatio, contentMode: .fit)

   func calculateAspectRatio(image: UIImage) -> CGFloat {
    let imageW = image.size.width
    let imageH = image.size.height
    let imageAspectRatio = imageW/imageH
    return imageAspectRatio
} 



Image(uiImage: image ?? UIImage(named: "placeholder")!)
     .aspectRatio(self.imageAspectRatio, contentMode: .fit)
...