2017-01-15 15 views
6

Pracuję nad dodaniem obsługi zdjęć kolorowych w iOS 10. Gdy użytkownik robi zdjęcie z aparatu, muszę użyć nowego interfejsu API obsługującego nową przestrzeń kolorów, aby zapisać dane zdjęć - UIGraphicsImageRenderer 's jpegData zamiast UIImageJPEGRepresentation.Zastępowanie UIImageJPEGReprezentacja za pomocą jpegData UIGraphicsImageRenderer

Występują pewne problemy z orientacją obrazu. Wykonując zdjęcie na moim iPadzie w pozycji pionowej, obraz nie jest prawidłowo rysowany. Zobacz komentarze poniżej:

Starego API:

let image = info[UIImagePickerControllerOriginalImage] as! UIImage 
let imageData = UIImageJPEGRepresentation(image, 1) 

Nowe API:

let image = info[UIImagePickerControllerOriginalImage] as! UIImage 
let cgImage = image.cgImage! 
let ciImage = CIImage(cgImage: cgImage) 

let format = UIGraphicsImageRendererFormat() 
format.scale = 1 
format.prefersExtendedRange = true 

let renderer = UIGraphicsImageRenderer(bounds: ciImage.extent, format: format) 
let imageData = renderer.jpegData(withCompressionQuality: 1, actions: { context in 
    context.cgContext.draw(cgImage, in: ciImage.extent) //draws flipped horizontally 
    //image.draw(at: .zero) //draws rotated 90 degrees leaving black at bottom 
    //image.draw(in: ciImage.extent) //draws rotated 90 degrees stretching and compressing the image to fill the rect 
}) 

Co znajduje się w poprawny sposób zastąpić UIImageJPEGRepresentation z UIGraphicsImageRenderer „s jpegData?

+0

Czy to naprawdę cały kod, którego użyłeś? Metoda 'image.draw' powinna" rysować cały obraz w aktualnym kontekście graficznym, z zachowaniem ustawienia orientacji obrazu ". Z mojego doświadczenia wynika, że ​​obrazy wejściowe zorientowane na działanie inne niż Up są zawsze ponownie renderowane do danych obrazu zorientowanego na Up przy użyciu renderera bez dodatkowej transformacji współrzędnych. – HuaTham

Odpowiedz

2

UIImage może mieć różną orientację w zależności od obrotu kamery. Można dynamicznie rozwiązać transformacji potrzebnego do zastosowania się do obrazu w zależności od tej orientacji, na przykład:

let renderer = UIGraphicsImageRenderer(size: image.size, format: format) 
let imageData = renderer.jpegData(withCompressionQuality: 1, actions: { context in 
    var workSize = image.size; 
    workSize.width = floor(workSize.width/image.scale) 
    workSize.height = floor(workSize.height/image.scale) 
    // No-op if the orientation is already correct 
    // if image.imageOrientation == .up { draw image } 

    // We need to calculate the proper transformation to make the image upright. 
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 

    var transform = CGAffineTransform.identity 

    switch image.imageOrientation 
    { 
     case .down, .downMirrored: 
      transform = transform.translatedBy(x: workSize.width, y: workSize.height) 
      transform = transform.rotated(by: CGFloat(Double.pi)) 
      break 

     case .left, .leftMirrored: 
      transform = transform.translatedBy(x: workSize.width, y: 0.0) 
      transform = transform.rotated(by: CGFloat(Double.pi/2.0)) 
      break 

     case .right, .rightMirrored: 
      transform = transform.translatedBy(x: 0.0, y: workSize.height) 
      transform = transform.rotated(by: CGFloat(-Double.pi/2.0)) 
      break 

     case .up, .upMirrored: 
      break 
    } 

    switch image.imageOrientation 
    { 
     case .upMirrored, .downMirrored: 
      transform = transform.translatedBy(x: workSize.width, y: 0.0) 
      transform = transform.scaledBy(x: -1.0, y: 1.0) 
      break 

     case .leftMirrored, .rightMirrored: 
      transform = transform.translatedBy(x: workSize.height, y: 0.0); 
      transform = transform.scaledBy(x: -1.0, y: 1.0); 
      break 

     case .up, .down, .left, .right: 
      break 
    } 

    // Now we draw the underlying CGImage into a new context, applying the transform 
    // calculated above. 

    let ctx = context.cgContext 

    ctx.concatenate(transform) 

    switch image.imageOrientation { 
     case .left, .leftMirrored, .right, .rightMirrored: 
      ctx.draw(image.cgImage!, in: CGRect(x: 0.0, y:0.0, width: workSize.height, height: workSize.width)) 
      break; 

     default: 
      ctx.draw(image.cgImage!, in: CGRect(origin: .zero, size: workSize)) 
      break; 
    } 
}) 

Odbierz oparciu o UIImage+fixOrientation

0

Sposób image.draw() powinny correct the orientation automatically dla Ciebie:

Ta metoda rysuje cały obraz w bieżącym kontekście graficznym, z poszanowaniem orientacji obrazu. W domyślnym układzie współrzędnych obrazy znajdują się w dół i na prawo od początku określonego prostokąta. Ta metoda respektuje jednak wszelkie transformacje zastosowane do bieżącego kontekstu graficznego.

Nie jestem pewien, dlaczego musisz użyć ci.extent. Wydaje się, że extent (nie rości sobie pretensji do bycia ekspertem od Core Image API) wymiarów "surowych" danych obrazu, które są przechowywane bez korekty orientacji obrazu. Jeśli surowe dane wymagają rotacji (orientacje inne niż Up, takie jak Left, Right), zasięg będzie nadal oryginalny, jeśli dane są przechowywane.

Używam następującego kodu dla obrazu z imageOrientation.rawValue = 3, a moje dane okazują się idealnie dokładne w odpowiednim rozmiarze z "poprawionym" imageOrientation.rawValue = 0 po ponownym załadowaniu.

let imageSize = image.Size 
let renderer = UIGraphicsImageRenderer(size: renderedSize, format: UIGraphicsImageRendererFormat()) 
return renderer.jpegData(withCompressionQuality: 0.95) { (rendererContext) in 
    let rect = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height) 
    image.draw(in: rect) 
} 

Moje wejście obrazu „renderuje” swoje dane prawidłowo z mojego kodu, biorąc pod uwagę orientację obrazu. Po prawej stronie używam draw(in: extent). Obraz nie jest jednak obrócony. Po prostu rozciągnięty.

enter image description here

Powiązane problemy