2015-02-12 14 views
6

Mam do czynienia z problemem orientacji obrazu podczas przycinania kwadratowej części obrazu z prostokątnego oryginalnego obrazu. Gdy zdjęcie jest w krajobrazie, jest w porządku. Ale kiedy jest w układzie pionowym, wydaje się, że orientacja obrazu nie jest zachowana, które wynikają w obrazie z niewłaściwej orientacji i złe upraw:Utrata orientacji obrazu podczas konwertowania obrazu na obraz CGImage

func cropImage(cropRectangleCoordinates: CGRect) { 

     let croppedImage = originalImage 

     let finalCroppedImage : CGImageRef = CGImageCreateWithImageInRect(croppedImage.CGImage, cropRectangleCoordinates) 

     finalImage = UIImage(CGImage: finalCroppedImage)! 


    } 

Myślę, że problem jest z croppedImage.CGImage. Obraz zostanie przekonwertowany na CGImage, ale wydaje się, że nie zachowuje on orientacji. Łatwo jest zachować orientację, używając tylko UIImage, ale aby wykonać przycięcie, obraz musi być tymczasowo oznaczony jako CGImage i na tym polega problem. Nawet jeśli zmienię orientację obrazu po konwersji z powrotem na UIImage, może to być poprawna orientacja, ale uszkodzenie jest już zrobione podczas przycinania CGImage.

To jest szybkie pytanie, więc proszę odpowiedzieć szybko, ponieważ rozwiązanie może być inne w Objective-C.

Odpowiedz

5

Znalazłem rozwiązanie ... czas pokaże, czy jest wystarczająco solidny, ale wydaje się działać we wszystkich sytuacjach. To był błędny błąd do naprawienia.

Problem polega na tym, że UIImage, w niektórych przypadkach, traci orientację po konwersji na CGImage. Wpływa na obraz portretów, które są automatycznie umieszczane w trybie poziomym. Dlatego domyślny obraz, który jest krajobrazem, nie jest naruszony. Ale jeśli błąd jest błędny, to nie ma wpływu na WSZYSTKIE zdjęcia portretowe !! Również wartość orientacji obrazu nie pomoże niektórym obrazom. Te problematyczne obrazy to obrazy, które użytkownik ma w swojej bibliotece, które dostał z wiadomości e-mail, wiadomości lub zapisane w Internecie, więc nie zostały zrobione aparatem. Obrazy te prawdopodobnie nie mają informacji o orientacji, a zatem w niektórych przypadkach zdjęcie w pionie .... POZOSTAŁO w pionie po przekonwertowaniu na obraz CGImage. Naprawdę utknąłem w tym momencie, dopóki nie zorientowałem się, że część mojego obrazu w mojej bibliotece urządzenia została zapisana z wiadomości lub e-maili.

Tak więc jedynym niezawodnym sposobem na odgadnięcie, który obraz zostanie zmieniony, jest utworzenie obu wersji danego obrazu: UIImage i CGImage oraz porównanie ich wartości wysokości. Jeśli są równe, wersja CGImage nie zostanie obrócona i można pracować z nią zgodnie z oczekiwaniami. Ale jeśli wysokość jest różna, możesz być pewien, że konwersja CGImage z CGImageCreateWithImageInRect spowoduje wyrównanie obrazu. W tym przypadku zamieniam współrzędną x/y pochodzenia, którą przekazuję jako współrzędną prostokąta, aby przyciąć i poprawnie traktuje te specjalne obrazy.

To był długi post, ale głównym pomysłem jest porównanie wysokości CGImage do szerokości UIImage, a jeśli są różne, należy oczekiwać odwrócenia punktu początkowego.

+2

Ale jeśli obraz był podniesiony do kwadratu, będzie to poważny problem dla rozwiązania: [] – Husam

+0

Po prostu umieść ścieżkę obrazu podobną do poniższego widoku i prześlij obraz UIImageView * imgViewTemp = [[UIImageView alloc] init]; [imgViewTemp setImage: [UIImage imageWithCGImage: [rep fullScreenImage]]]; UIImage * compressedImage = [mYGlobal funResizing: imgViewTemp.image]; Mam ten sam problem, ale napraw jak powyżej. – chetu

3

Zmień swoje wezwanie do utworzenia UIImage:

finalImage = UIImage(CGImage:finalCroppedImage, scale:originalImage.scale, orientation:originalImage.orientation) 

aby zachować pierwotną orientację (i skala) obrazu.

+0

Próbowałem, ale problem jest bardziej zjadliwy: finalimage jest już przycięty, utrata orientacji następuje na wcześniejszym etapie: croppedImage.CGImage. Co sugerujesz, możesz poprawnie obrócić obraz, ale po jego uszkodzeniu. –

+0

Wielkie dzięki. To mi pomoże. –

4

Oto rozszerzenie UIImage, które napisałem po obejrzeniu kilku starszych fragmentów kodu napisanych przez innych. Jest napisany w Swift 3 i używa właściwości orientacji iOS plus CGAffineTransform, aby ponownie narysować obraz w prawidłowej orientacji.

SWIFT 3:

public extension UIImage { 

    /// Extension to fix orientation of an UIImage without EXIF 
    func fixOrientation() -> UIImage { 

     guard let cgImage = cgImage else { return self } 

     if imageOrientation == .up { return self } 

     var transform = CGAffineTransform.identity 

     switch imageOrientation { 

     case .down, .downMirrored: 
      transform = transform.translatedBy(x: size.width, y: size.height) 
      transform = transform.rotated(by: CGFloat(M_PI)) 

     case .left, .leftMirrored: 
      transform = transform.translatedBy(x: size.width, y: 0) 
      transform = transform.rotated(by: CGFloat(M_PI_2)) 

     case .right, .rightMirrored: 
      transform = transform.translatedBy(x: 0, y: size.height) 
      transform = transform.rotated(by: CGFloat(-M_PI_2)) 

     case .up, .upMirrored: 
      break 
     } 

     switch imageOrientation { 

     case .upMirrored, .downMirrored: 
      transform.translatedBy(x: size.width, y: 0) 
      transform.scaledBy(x: -1, y: 1) 

     case .leftMirrored, .rightMirrored: 
      transform.translatedBy(x: size.height, y: 0) 
      transform.scaledBy(x: -1, y: 1) 

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

     if let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: cgImage.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) { 

      ctx.concatenate(transform) 

      switch imageOrientation { 

      case .left, .leftMirrored, .right, .rightMirrored: 
       ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width)) 

      default: 
       ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) 
      } 

      if let finalImage = ctx.makeImage() { 
       return (UIImage(cgImage: finalImage)) 
      } 
     } 

     // something failed -- return original 
     return self 
    } 
} 
+0

nazywając to przed konwersją na wywołanie image.cgImage worked – Cjay

8

SWIFT 3:

przeliczyć obracany cgImage do UIImage tą metodą

UIImage(cgImage:croppedCGImage, scale:originalImage.scale, orientation:originalImage.imageOrientation) 

Źródło @David Berry odpowiedzieć

+0

Dziękuję :) Jest to o wiele lepsze niż kod 100 wierszy rotacji, jaki widziałem w innych odpowiedziach: D –

0

To jest odpowiedź, zasługa @awolf (Cropping an UIImage). Doskonale radzi sobie z skalą i orientacją. Po prostu wywołaj tę metodę na obrazie, który chcesz przyciąć, i przepuść przycięcie CGRect bez obawy o skalę lub orientację. Możesz sprawdzić, czy numer cgImage jest zerowy, zamiast wymuszać jego rozpakowanie tak jak tutaj.

extension UIImage { 
    func croppedInRect(rect: CGRect) -> UIImage { 
     func rad(_ degree: Double) -> CGFloat { 
      return CGFloat(degree/180.0 * .pi) 
     } 

     var rectTransform: CGAffineTransform 
     switch imageOrientation { 
     case .left: 
      rectTransform = CGAffineTransform(rotationAngle: rad(90)).translatedBy(x: 0, y: -self.size.height) 
     case .right: 
      rectTransform = CGAffineTransform(rotationAngle: rad(-90)).translatedBy(x: -self.size.width, y: 0) 
     case .down: 
      rectTransform = CGAffineTransform(rotationAngle: rad(-180)).translatedBy(x: -self.size.width, y: -self.size.height) 
     default: 
      rectTransform = .identity 
     } 
     rectTransform = rectTransform.scaledBy(x: self.scale, y: self.scale) 

     let imageRef = self.cgImage!.cropping(to: rect.applying(rectTransform)) 
     let result = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation) 
     return result 
    } 
} 

Inna uwaga: jeśli pracujesz z imageView osadzony w scrollView, jest jeden dodatkowy krok, trzeba wziąć pod uwagę współczynnik powiększenia. Zakładając, że imageView obejmuje całą zawartość widoku z scrollView, i użyć Granice scrollView jako ramki kadrowania, przycięty obraz można otrzymać jako

let ratio = imageView.image!.size.height/scrollView.contentSize.height 
let origin = CGPoint(x: scrollView.contentOffset.x * ratio, y: scrollView.contentOffset.y * ratio) 
let size = CGSize(width: scrollView.bounds.size.width * ratio, let height: scrollView.bounds.size.height * ratio) 
let cropFrame = CGRect(origin: origin, size: size) 
let croppedImage = imageView.image!.croppedInRect(rect: cropFrame) 
Powiązane problemy