Orientacja obrazu iOS ma dziwne zachowanie

95

Przez ostatnie kilka tygodni pracowałem z obrazami w obiektyw-c i zauważyłem wiele dziwnych zachowań. Po pierwsze, podobnie jak wiele innych osób, mam problem polegający na tym, że zdjęcia zrobione aparatem (lub zrobione innym aparatem i wysłane do mnie w wiadomości MMS) są obrócone o 90 stopni. Nie byłem pewien, dlaczego tak się dzieje na świecie (stąd moje pytanie ), ale udało mi się wymyślić tanią pracę.

Moje pytanie tym razem brzmi: dlaczego tak się dzieje ? Dlaczego Apple obraca obrazy? Kiedy robię zdjęcie aparatem prawą stroną do góry, o ile nie wykonuję powyższego kodu, kiedy zapisuję zdjęcie, zostaje ono zapisane jako obrócone. Aż do kilku dni temu moje obejście było w porządku.

Moja aplikacja modyfikuje poszczególne piksele obrazu, w szczególności kanał alfa pliku PNG (więc każda konwersja JPEG jest wyrzucana z okna w moim scenariuszu). Kilka dni temu zauważyłem, że chociaż obraz jest wyświetlany poprawnie w mojej aplikacji dzięki kodowi obejścia, kiedy mój algorytm modyfikuje poszczególne piksele obrazu, uważa, że ​​obraz jest obrócony. Więc zamiast modyfikować piksele na górze obrazu, modyfikuje piksele z boku obrazu (ponieważ uważa, że ​​powinien być obrócony)! Nie potrafię wymyślić, jak obrócić obraz w pamięci - najlepiej byłoby, gdybyśmy po prostu usunęli tę imageOrientationflagę razem.

Jest jeszcze coś, co mnie zaskoczyło ... Kiedy robię zdjęcie, imageOrientationjest ustawiony na 3. Mój kod obejścia jest wystarczająco inteligentny, aby to zrealizować i odwrócić go, aby użytkownik nigdy tego nie zauważył. Dodatkowo mój kod zapisujący obraz w bibliotece zdaje sobie z tego sprawę, odwraca go, a następnie zapisuje, aby był prawidłowo wyświetlany w rolce aparatu.

Ten kod wygląda tak:

NSData* pngdata = UIImagePNGRepresentation (self.workingImage); //PNG wrap 
UIImage* img = [self rotateImageAppropriately:[UIImage imageWithData:pngdata]];   
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);

Kiedy ładuję ten nowo zapisany obraz do mojej aplikacji, imageOrientationjest 0 - dokładnie to, co chcę zobaczyć, a moje obejście nie musi nawet uruchamiać (uwaga: podczas ładowania obrazów z Internetu w przeciwieństwie do zdjęć zrobionych aparatem , imageOrientationzawsze wynosi 0, co daje doskonałe zachowanie). Z jakiegoś powodu mój kod zapisu wydaje się usuwać tę imageOrientationflagę. Miałem nadzieję, że po prostu wykradnę ten kod i użyję go do usunięcia mojej orientacji obrazu, gdy tylko użytkownik zrobi zdjęcie i doda je do aplikacji, ale wydaje się, że nie działa. Robi UIImageWriteToSavedPhotosAlbumcoś specjalnego imageOrientation?

Najlepszym rozwiązaniem tego problemu byłoby po prostu zdmuchnięcie, imageOrientationgdy tylko użytkownik skończy robić zdjęcie. Zakładam, że Apple ma jakieś zachowanie związane z rotacją, prawda? Kilka osób zasugerowało, że to wada Apple.

(... jeśli jeszcze się nie zgubiłeś ... Uwaga 2: Kiedy robię poziome zdjęcie, wszystko wydaje się działać idealnie, tak jak zdjęcia zrobione z internetu)

EDYTOWAĆ:

Oto, jak faktycznie wyglądają niektóre obrazy i scenariusze. Na podstawie dotychczasowych komentarzy wygląda na to, że to dziwne zachowanie jest czymś więcej niż tylko zachowaniem iPhone'a, co moim zdaniem jest dobre.

To jest zdjęcie zdjęcia, które zrobiłem telefonem (zwróć uwagę na właściwą orientację), wygląda dokładnie tak, jak na moim telefonie, kiedy zrobiłem zdjęcie:

Rzeczywiste zdjęcie zrobione iPhonem

Oto, jak wygląda obraz w Gmailu po wysłaniu go do siebie e-mailem (wygląda na to, że Gmail obsługuje go poprawnie):

Zdjęcie widoczne w Gmailu

Oto jak obraz wygląda jako miniatura w oknach (nie wygląda na to, że jest prawidłowo obsługiwany):

Miniatura systemu Windows

A oto, jak wygląda rzeczywisty obraz po otwarciu za pomocą przeglądarki fotografii systemu Windows (nadal nie jest obsługiwany prawidłowo):

Wersja przeglądarki fotografii systemu Windows

Po wszystkich komentarzach do tego pytania, oto, co myślę ... iPhone robi zdjęcie i mówi „aby wyświetlić go poprawnie, należy go obrócić o 90 stopni”. Ta informacja byłaby w danych EXIF. (Dlaczego należy go obrócić o 90 stopni, zamiast domyślnie ustawiać go na prostą pionową, nie wiem). Stąd Gmail jest wystarczająco inteligentny, aby odczytywać i analizować dane EXIF ​​oraz prawidłowo je wyświetlać. Jednak system Windows nie jest wystarczająco inteligentny, aby odczytać dane EXIF, a zatem wyświetla obraz nieprawidłowo . Czy moje przypuszczenia są prawidłowe?

Boeckm
źródło
Ciekawe ... jeśli to prawda, dlaczego robione zdjęcia są ustawione pod odpowiednim kątem? Wiem, że to nie jest wada iPhone'a, ponieważ zauważyłem podobne zachowanie, gdy znajomy (z BlackBerry) robi zdjęcie i MMS to do mnie.
Boeckm
Zobacz, jak aparat zapisuje metadane, aby obrócić go o 90 stopni, niektóre systemy operacyjne odczytują te metadane, a reszta nie.
HarshIT
Całkiem dobra lektura (patrz odpowiedź @ Hadley poniżej - była w komentarzu). Dlatego moja aplikacja musi być wystarczająco inteligentna, aby obsługiwać obrazy zawierające dane EXIF, a także obrazy, które ich nie zawierają ... Nadal nie rozumiem, dlaczego robiąc zdjęcie prawą stroną do góry, flaga orientacji mówi, że powinien być obrócony o 90 stopni?
Boeckm
Ustawiasz tryb fotograficzny na Portret i nie obracasz aparatu pod kątem prostym lub ustawiony jest tryb Krajobraz i aparat przechwycił obraz w pozycji pod kątem prostym, czujnik automatycznie ustawi orientację na właściwą. Sprawdź to
HarshIT
1
Rozwiązaniem jest najprawdopodobniej Twoja aplikacja musi odczytać metadane i obrócić obraz i / lub zmodyfikować metadane zgodnie z wymaganiami.
HarshIT

Odpowiedzi:

50

Przeprowadziłem badania i odkryłem, że każdy plik obrazu ma właściwość metadanych. Jeśli metadane określają orientację obrazu, która jest zwykle ignorowana przez inne systemy operacyjne oprócz Mac. Większość wykonanych zdjęć ma właściwość metadanych ustawioną pod kątem prostym. Więc Mac pokazuje to w sposób obrócony o 90 stopni. Możesz zobaczyć ten sam obraz we właściwy sposób w systemie operacyjnym Windows.

Aby uzyskać więcej informacji, przeczytaj tę odpowiedź http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

spróbuj przeczytać plik exif swojego obrazu tutaj http://www.exifviewer.org/ , http://regex.info/exif.cgi lub http://www.addictivetips.com/internet-tips/view-complete-exif -metadata-information-of-any-jpeg-image-online /

HarshIT
źródło
1
ŁAŁ! Nie miałem pojęcia, że ​​w danych EXIF ​​jest TAK DUŻO informacji! regex.info/exif.cgi to niesamowita strona! Z pewnością będę dziś wieczorem bawić się obrazami na tej stronie. Będę musiał przetestować każdy scenariusz, zdjęcia zrobione prosto, zdjęcia z internetu, zdjęcia obrócone itp. Dzięki wielkie!
Boeckm
Pierwszy link exif jest teraz uszkodzony, a drugi został zaktualizowany do exif.regex.info/exif.cgi. Próbowałem edytować odpowiedź, ale @ cj-dennis odrzucił ją z jakiegoś powodu.
Ryan
55

Miałem ten sam problem, gdy otrzymałem obraz z aparatu, wstawiłem następujący kod, aby to naprawić .. Dodano metodę scaleAndRotateImage stąd

- (void) imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)imageInfo {
            // Images from the camera are always in landscape, so rotate
                    UIImage *image = [self scaleAndRotateImage: [imageInfo objectForKey:UIImagePickerControllerOriginalImage]];
    //then save the image to photo gallery or wherever  
        }


- (UIImage *)scaleAndRotateImage:(UIImage *) image {
    int kMaxResolution = 320;

    CGImageRef imgRef = image.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);


    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}
Dilip Rajkumar
źródło
3
Jak wygląda Twój kod scaleAndRotateImage? Czy po zrobieniu google jest to to samo, co tutaj? discussions.apple.com/thread/1537011?start=0&tstart=0
Boeckm
2
WOW ... Haha! To zadziałało bardzo dobrze! Użyłem kodu w moim komentarzu powyżej. Mam dwie niesamowite odpowiedzi na moje pytanie! Myślę, że to oznacza, że ​​zadałem zbyt duże pytanie ... Wielkie dzięki. Muszę przeprowadzić szczegółowe testy, ale jak dotąd problem z orientacją działa świetnie w przypadku zdjęć zrobionych w pionie i poziomie.
Boeckm
3
Myślę, że brakuje części twojej metody, ale to i link wciąż wystarczał mi, abym dopracował resztę i wreszcie sprawił, że mój widok kadrowania obrazu działał poprawnie, więc dzięki :)
Vic Smith
Cieszę się, że pomogło .. :)
Dilip Rajkumar
czy ten blok kodu zachowuje wygląd oryginalnego obrazu, ale zmienia orientację na górę?
Junchao Gu
19

Moje pytanie tym razem brzmi: dlaczego tak się dzieje? Dlaczego Apple obraca obrazy?

Odpowiedź na to jest bardzo prosta. Apple NIE obraca obrazu. W tym tkwi zamieszanie.

Kamera CCD nie obraca się, więc zawsze robi zdjęcie w trybie poziomym.

Apple zrobił bardzo sprytną rzecz - zamiast spędzać cały czas na obracaniu obrazu - tasowaniu megabajtów danych - po prostu otaguj go, JAK to zdjęcie zostało zrobione.

OpenGL bardzo łatwo wykonuje tłumaczenia - dzięki czemu DANE nigdy nie są tasowane - po prostu JAK JEST RYSOWANE.

Stąd orientacja metadanych.

Staje się to problemem, jeśli chcesz przyciąć, zmienić rozmiar itp. - ale kiedy już wiesz, co się dzieje, po prostu definiujesz swoją macierz i wszystko działa.

Roy
źródło
1
Dziękuję za to wyjaśnienie. Zdrowy rozsądek, gdy się nad tym zastanowić, ale żaden inny wynik Google tego nie wyjaśnił.
Dakine83
ładne wyjaśnienie jak profesor. dzięki!
vkGunasekaran
18

Szybkie kopiowanie / wklejanie Szybkie tłumaczenie doskonałej odpowiedzi Dilipa .

import Darwin

class func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {

    let imgRef = imageSource.CGImage;

    let width = CGFloat(CGImageGetWidth(imgRef));
    let height = CGFloat(CGImageGetHeight(imgRef));

    var bounds = CGRectMake(0, 0, width, height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransformIdentity
    let orient = imageSource.imageOrientation
    let imageSize = CGSizeMake(CGFloat(CGImageGetWidth(imgRef)), CGFloat(CGImageGetHeight(imgRef)))


    switch(imageSource.imageOrientation) {
    case .Up :
        transform = CGAffineTransformIdentity

    case .UpMirrored :
        transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);

    case .Down :
        transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI));

    case .DownMirrored :
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
        transform = CGAffineTransformScale(transform, 1.0, -1.0);

    case .Left :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);

    case .LeftMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
        transform = CGAffineTransformScale(transform, -1.0, 1.0);
        transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);

    case .Right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);

    case .RightMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransformMakeScale(-1.0, 1.0);
        transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);

    default : ()
    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()

    if orient == .Right || orient == .Left {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    } else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);
    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}
thattyson
źródło
1
Dzięki, ale co to jest „niech stosunek = szerokość / wysokość;” używając do? Nie widzę żadnego miejsca używającego współczynnika w tym {}
Pengzhi Zhou,
16

Wersja Swift 4 z kontrolą bezpieczeństwa odpowiedzi Dilipa .

public static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat = 320) -> UIImage? {

    guard let imgRef = imageSource.cgImage else {
        return nil
    }

    let width = CGFloat(imgRef.width)
    let height = CGFloat(imgRef.height)

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))

    switch(imageSource.imageOrientation) {
    case .up:
        transform = .identity
    case .upMirrored:
        transform = CGAffineTransform
            .init(translationX: imageSize.width, y: 0)
            .scaledBy(x: -1.0, y: 1.0)
    case .down:
        transform = CGAffineTransform
            .init(translationX: imageSize.width, y: imageSize.height)
            .rotated(by: CGFloat.pi)
    case .downMirrored:
        transform = CGAffineTransform
            .init(translationX: 0, y: imageSize.height)
            .scaledBy(x: 1.0, y: -1.0)
    case .left:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: 0, y: imageSize.width)
            .rotated(by: 3.0 * CGFloat.pi / 2.0)
    case .leftMirrored:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: imageSize.height, y: imageSize.width)
            .scaledBy(x: -1.0, y: 1.0)
            .rotated(by: 3.0 * CGFloat.pi / 2.0)
    case .right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(translationX: imageSize.height, y: 0)
            .rotated(by: CGFloat.pi / 2.0)
    case .rightMirrored:
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width;
        bounds.size.width = storedHeight;
        transform = CGAffineTransform
            .init(scaleX: -1.0, y: 1.0)
            .rotated(by: CGFloat.pi / 2.0)
    }

    UIGraphicsBeginImageContext(bounds.size)
    if let context = UIGraphicsGetCurrentContext() {
        if orient == .right || orient == .left {
            context.scaleBy(x: -scaleRatio, y: scaleRatio)
            context.translateBy(x: -height, y: 0)
        } else {
            context.scaleBy(x: scaleRatio, y: -scaleRatio)
            context.translateBy(x: 0, y: -height)
        }

        context.concatenate(transform)
        context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))
    }

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return imageCopy
}
Dávid Tímár
źródło
Możesz także obejść się (bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)bez tworzenia zmiennej jako magazynu.
Almas Sapargali
Czasami miałem problem, że po przeskalowaniu u dołu obrazu pojawiała się biała linia. Dzieje się tak, ponieważ CGFloat wydaje się nie być wystarczająco precyzyjny. Naprawiłem to za pomocą bounds.size.height.round()ibounds.size.width.round()
ndreisg
13

Każdy obraz wygenerowany przez iPhone'a / iPada jest zapisywany jako Poziomo lewy ze znacznikiem EXIF ​​Orientation (Exif.Image.Orientation) określającym aktualną orientację.

Ma następujące wartości: 1: Poziomo Lewo 6: Pionowo Normalnie 3: Poziomo Prawo 4: Pionowo do góry nogami

W systemie IOS informacje EXIF ​​są poprawnie odczytywane, a obrazy są wyświetlane w taki sam sposób, w jaki zostały zrobione. Ale w systemie Windows informacje EXIF ​​NIE są używane.

Jeśli otworzysz jeden z tych obrazów w GIMP-ie, powie, że obraz ma informacje o obrocie.

ATOzTOA
źródło
8

Dla każdego, kto korzysta z platformy Xamarin, oto tłumaczenie C # doskonałej odpowiedzi Dilipa oraz podziękowania dla thattyson za tłumaczenie w języku Swift .

public static UIImage RotateCameraImageToProperOrientation(UIImage imageSource, nfloat maxResolution) {

    var imgRef = imageSource.CGImage;

    var width = (nfloat)imgRef.Width;
    var height = (nfloat)imgRef.Height;

    var bounds = new CGRect(0, 0, width, height);

    nfloat scaleRatio = 1;

    if (width > maxResolution || height > maxResolution) 
    {
        scaleRatio = (nfloat)Math.Min(maxResolution / bounds.Width, maxResolution / bounds.Height);
        bounds.Height = bounds.Height * scaleRatio;
        bounds.Width = bounds.Width * scaleRatio;
    }

    var transform = CGAffineTransform.MakeIdentity();
    var orient = imageSource.Orientation;
    var imageSize = new CGSize(imgRef.Width, imgRef.Height);
    nfloat storedHeight;

    switch(imageSource.Orientation) {
        case UIImageOrientation.Up:
            transform = CGAffineTransform.MakeIdentity();
            break;

        case UIImageOrientation.UpMirrored :
            transform = CGAffineTransform.MakeTranslation(imageSize.Width, 0.0f);
            transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
            break;

        case UIImageOrientation.Down :
            transform = CGAffineTransform.MakeTranslation(imageSize.Width, imageSize.Height);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI);
            break;

        case UIImageOrientation.DownMirrored :
            transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Height);
            transform = CGAffineTransform.Scale(transform, 1.0f, -1.0f);
            break;

        case UIImageOrientation.Left:
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Width);
            transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.LeftMirrored :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(imageSize.Height, imageSize.Width);
            transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
            transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.Right :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeTranslation(imageSize.Height, 0.0f);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
            break;

        case UIImageOrientation.RightMirrored :
            storedHeight = bounds.Height;
            bounds.Height = bounds.Width;
            bounds.Width = storedHeight;
            transform = CGAffineTransform.MakeScale(-1.0f, 1.0f);
            transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
            break;

        default :
            break;
    }

    UIGraphics.BeginImageContext(bounds.Size);
    var context = UIGraphics.GetCurrentContext();

    if (orient == UIImageOrientation.Right || orient == UIImageOrientation.Left) {
        context.ScaleCTM(-scaleRatio, scaleRatio);
        context.TranslateCTM(-height, 0);
    } else {
        context.ScaleCTM(scaleRatio, -scaleRatio);
        context.TranslateCTM(0, -height);
    }

    context.ConcatCTM(transform);
    context.DrawImage(new CGRect(0, 0, width, height), imgRef);

    var imageCopy = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();

    return imageCopy;
}
tetowill
źródło
Pomogło to rozwiązać mój problem po spędzeniu wielu godzin na tej zabawie! Niewiarygodne, że Xamarin nie ma wbudowanej obsługi tego rozwiązania, biorąc pod uwagę, że jest teraz produktem firmy Microsoft.
Sami.C,
4

Trafiłem na to pytanie, ponieważ miałem podobny problem, ale używam Swift. Chciałem tylko podać link do odpowiedzi, która działała dla mnie w przypadku innych programistów Swift: https://stackoverflow.com/a/26676578/3904581

Oto fragment kodu Swift, który skutecznie rozwiązuje problem:

let orientedImage = UIImage(CGImage: initialImage.CGImage, scale: 1, orientation: initialImage.imageOrientation)!

Super proste. Jedna linia kodu. Problem rozwiązany.

Melly
źródło
To nie zadziałało, użyłem tego rozwiązania: stackoverflow.com/a/27775741/945247
Leon.
0

Szybka refaktoryzacja dla Swift 3 (czy ktoś może to przetestować i potwierdzić, że wszystko działa dobrze?):

static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
    let imgRef = imageSource.cgImage

    let width = CGFloat(imgRef!.width)
    let height = CGFloat(imgRef!.height)

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if width > maxResolution || height > maxResolution {

        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: imgRef!.width, height: imgRef!.height)

    switch imageSource.imageOrientation {
    case .up :
        transform = CGAffineTransform.identity

    case .upMirrored :
        transform = CGAffineTransform(translationX: imageSize.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)

    case .down :
        transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height)
        transform = transform.rotated(by: CGFloat.pi)

    case .downMirrored :
        transform = CGAffineTransform(translationX: 0, y: imageSize.height)
        transform = transform.scaledBy(x: 1, y: -1)

    case .left :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: 0, y: imageSize.width)
        transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)

    case .leftMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width)
        transform = transform.scaledBy(x: -1, y: 1)
        transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)

    case .right :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: 0)
        transform = transform.rotated(by: CGFloat.pi / 2.0)

    case .rightMirrored :
        let storedHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = storedHeight
        transform = CGAffineTransform(scaleX: -1, y: 1)
        transform = transform.rotated(by: CGFloat.pi / 2.0)

    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()

    if orient == .right || orient == .left {

        context!.scaleBy(x: -scaleRatio, y: scaleRatio)
        context!.translateBy(x: -height, y: 0)
    } else {
        context!.scaleBy(x: scaleRatio, y: -scaleRatio)
        context!.translateBy(x: 0, y: -height)
    }

    context!.concatenate(transform)
    context!.draw(imgRef!, in: CGRect(x: 0, y: 0, width: width, height: height))

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return imageCopy!
}
sabiland
źródło
0

Oto niesamowita odpowiedź Dilipa w wersji Swift3

func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
    let imgRef = imageSource.cgImage!;

    let width = CGFloat(imgRef.width);
    let height = CGFloat(imgRef.height);

    var bounds = CGRect(x: 0, y: 0, width: width, height: height)

    var scaleRatio : CGFloat = 1
    if (width > maxResolution || height > maxResolution) {
        scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
        bounds.size.height = bounds.size.height * scaleRatio
        bounds.size.width = bounds.size.width * scaleRatio
    }

    var transform = CGAffineTransform.identity
    let orient = imageSource.imageOrientation
    let imageSize = CGSize(width: width, height: height)


    switch(imageSource.imageOrientation) {
        case .up :
            transform = CGAffineTransform.identity

        case .upMirrored :
            transform = CGAffineTransform(translationX: imageSize.width, y: 0.0);
            transform = transform.scaledBy(x: -1, y: 1);

        case .down :
            transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height);
            transform = transform.rotated(by: CGFloat(Double.pi));

        case .downMirrored :
            transform = CGAffineTransform(translationX: 0.0, y: imageSize.height);
            transform = transform.scaledBy(x: 1, y: -1);

        case .left :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: 0.0, y: imageSize.width);
            transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);

        case .leftMirrored :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width);
            transform = transform.scaledBy(x: -1, y: 1);
            transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);

        case .right :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(translationX: imageSize.height, y: 0.0);
            transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);

        case .rightMirrored :
            let storedHeight = bounds.size.height
            bounds.size.height = bounds.size.width;
            bounds.size.width = storedHeight;
            transform = CGAffineTransform(scaleX: -1.0, y: 1.0);
            transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);
    }

    UIGraphicsBeginImageContext(bounds.size)
    let context = UIGraphicsGetCurrentContext()!

    if orient == .right || orient == .left {
        context.scaleBy(x: -scaleRatio, y: scaleRatio);
        context.translateBy(x: -height, y: 0);
    } else {
        context.scaleBy(x: scaleRatio, y: -scaleRatio);
        context.translateBy(x: 0, y: -height);
    }

    context.concatenate(transform);
    context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))

    let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy!;
}
Sandip Mane
źródło
-3

Spróbuj zmienić format obrazu na .jpeg. To zadziałało dla mnie

Victor Rius
źródło