A orientação da imagem do iOS tem comportamento estranho

94

Nas últimas semanas, tenho trabalhado com imagens em objetiva-c e percebido muitos comportamentos estranhos. Primeiro, como muitas outras pessoas, tenho tido esse problema onde as imagens tiradas com a câmera (ou tiradas com a câmera de outra pessoa e MMS para mim) são giradas em 90 graus. Eu não tinha certeza de por que isso estava acontecendo (daí minha pergunta ), mas consegui encontrar uma solução barata.

Minha pergunta desta vez é por que isso está acontecendo ? Por que a Apple está girando as imagens? Quando tiro uma foto com a câmera voltada para cima, a menos que execute o código mencionado acima, quando salvo a foto, ela é salva girada. Agora, minha solução alternativa estava bem até alguns dias atrás.

Meu aplicativo modifica pixels individuais de uma imagem, especificamente o canal alfa de um PNG (para que qualquer conversão JPEG seja jogada fora da janela para o meu cenário). Há alguns dias, percebi que, embora a imagem seja exibida corretamente em meu aplicativo graças ao meu código de solução alternativa, quando meu algoritmo modifica os pixels individuais da imagem, ele pensa que a imagem está girada. Então, ao invés de modificar os pixels na parte superior da imagem, ele modifica os pixels na lateral da imagem (porque ele acha que deveria ser girado)! Não consigo descobrir como girar a imagem na memória - o ideal é que eu prefira simplesmente apagar imageOrientationtoda essa bandeira.

Aqui está outra coisa que também está me confundindo ... Quando eu tiro a foto, o imageOrientationé definido como 3. Meu código de solução alternativa é inteligente o suficiente para perceber isso e virá-lo para que o usuário nunca perceba. Além disso, meu código para salvar a imagem na biblioteca percebe isso, vira e salva para que apareça no rolo da câmera corretamente.

Esse código é assim:

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

Quando eu carrego essa imagem recém-salva em meu aplicativo, o imageOrientationé 0 - exatamente o que eu quero ver, e minha solução alternativa de rotação nem precisa ser executada (nota: ao carregar imagens da internet em oposição a imagens tiradas com uma câmera , o imageOrientationé sempre 0, resultando em comportamento perfeito). Por algum motivo, meu código de salvamento parece apagar esse imageOrientationsinalizador. Eu esperava apenas roubar esse código e usá-lo para limpar minha imageOrientation assim que o usuário tirar uma foto e adicioná-la ao aplicativo, mas não parece funcionar. Faz UIImageWriteToSavedPhotosAlbumalgo especial com imageOrientation?

A melhor solução para esse problema seria simplesmente explodir imageOrientationassim que o usuário terminar de tirar uma imagem. Presumo que a Apple tenha o comportamento de rotação feito por um motivo, certo? Algumas pessoas sugeriram que este é um defeito da Apple.

(... se você ainda não está perdido ... Obs2: Quando tiro uma foto horizontal, tudo parece funcionar perfeitamente, assim como as fotos tiradas da internet)

EDITAR:

Aqui estão algumas das imagens e cenários reais. Com base nos comentários até agora, parece que esse comportamento estranho é mais do que apenas um comportamento do iPhone, o que eu acho bom.

Esta é uma foto da foto que tirei com meu telefone (observe a orientação correta), ela aparece exatamente como no meu telefone quando tirei a foto:

Foto real tirada no iPhone

Esta é a aparência da imagem no Gmail depois que eu a enviei por e-mail para mim mesmo (parece que o Gmail a lida corretamente):

Foto como aparece no Gmail

Aqui está a aparência da imagem como uma miniatura no Windows (não parece que foi tratada corretamente):

Miniatura do Windows

E aqui está a aparência da imagem real quando aberta com o Windows Photo Viewer (ainda não tratada corretamente):

Versão do Windows Photo Viewer

Depois de todos os comentários sobre esta questão, eis o que estou pensando ... O iPhone pega uma imagem e diz "para exibir isso corretamente, ela precisa ser girada 90 graus". Essas informações estariam nos dados EXIF. (Por que ele precisa ser girado 90 graus, em vez de padronizar para a vertical, eu não sei). A partir daqui, o Gmail é inteligente o suficiente para ler e analisar os dados EXIF ​​e exibi-los corretamente. O Windows, entretanto, não é inteligente o suficiente para ler os dados EXIF ​​e, portanto, exibe a imagem incorretamente . Minhas suposições estão corretas?

Boeckm
fonte
Interessante ... se for verdade, por que as imagens tiradas estão em ângulo reto? Eu sei que isso não é um defeito do iPhone, porque notei um comportamento semelhante quando um amigo (com um BlackBerry) pega uma imagem e manda por MMS para mim.
Boeckm
Veja sua câmera grava metadados para girá-la em 90 graus, alguns sistemas operacionais leem esses metadados e outros não.
HarshIT de
Leitura muito boa (veja a resposta de @ Hadley abaixo - costumava estar em um comentário). Portanto, meu aplicativo claramente precisa ser inteligente o suficiente para lidar com imagens que contêm dados EXIF, bem como imagens que não os contêm ... Ainda não entendo por que, quando tiro uma foto do lado direito para cima, o sinalizador de orientação diz que deve ser girado 90 graus?
Boeckm
Você define o modo de foto como Retrato e não gira a câmera no ângulo reto ou o modo Paisagem está definido e a câmera capturou a imagem em ângulo reto, o sensor definirá automaticamente a orientação adequada. Confira
HarshIT
1
A solução mais provável é que seu aplicativo precise ler os metadados e girar a imagem e / ou modificar os metadados conforme a necessidade.
HarshIT

Respostas:

50

Eu fiz P&D nele e descobri que todo arquivo de imagem tem propriedade de metadados. Se os metadados especificam a orientação da imagem, que geralmente é ignorada por outros sistemas operacionais, exceto Mac. A maioria das imagens tiradas tem suas propriedades de metadados configuradas em ângulo reto. Então Mac mostra a maneira girada de 90 graus. Você pode ver a mesma imagem de maneira adequada no sistema operacional Windows.

Para mais detalhes, leia esta resposta http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

tente ler o exif de sua imagem aqui http://www.exifviewer.org/ , ou http://regex.info/exif.cgi ou http://www.addictivetips.com/internet-tips/view-complete-exif -metadata-information-of-any-jpeg-image-online /

HarshIT
fonte
1
UAU! Eu não tinha ideia que havia MUITA informação nos dados EXIF! regex.info/exif.cgi é um site incrível! Certamente estarei brincando com imagens esta noite neste site. Terei que testar todos os cenários, imagens tiradas direto, imagens tiradas da internet, imagens tiradas giradas, etc. Muito obrigado!
Boeckm
O primeiro link exif está quebrado agora, e o segundo foi atualizado para exif.regex.info/exif.cgi Tentei editar a resposta, mas @ cj-dennis rejeitou por algum motivo.
Ryan
55

Tive o mesmo problema ao obter a imagem da Camera, coloquei o seguinte código para corrigi-lo .. Adicionado o método scaleAndRotateImage a partir daqui

- (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
fonte
3
Qual é a aparência do seu código scaleAndRotateImage? Depois de fazer um google, é igual ao daqui? discussões.apple.com
thread
2
WOW ... Haha! Isso funcionou extremamente bem! Usei o código em meu comentário acima. Eu tenho duas respostas incríveis para minha pergunta! Acho que isso significa que fiz uma pergunta muito grande ... Muito obrigado. Vou ter que fazer alguns testes em profundidade, mas até agora o problema de orientação funciona muito bem com fotos tiradas verticalmente e horizontalmente.
Boeckm
3
Acho que falta uma parte do seu método, mas isso e o link ainda foram suficientes para eu resolver o resto e finalmente fazer minha visualização de recorte de imagem funcionar corretamente, então obrigado :)
Vic Smith
Estou feliz que tenha ajudado .. :)
Dilip Rajkumar
este bloco de código preserva a aparência da imagem original, mas altera a orientação para cima?
Junchao Gu
18

Copie / cole rápida tradução rápida da excelente resposta de Dilip .

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
fonte
1
Obrigado, mas o que é "deixar proporção = largura / altura;" usando para? Não consigo ver nenhum lugar usando proporção naquele {}
Pengzhi Zhou
18

Minha pergunta desta vez é por que isso está acontecendo? Por que a Apple está girando as imagens?

A resposta para isso é muito simples. A Apple NÃO está girando a imagem. É aí que reside a confusão.

A câmera CCD não gira, por isso está sempre tirando a foto no modo paisagem.

A Apple fez uma coisa muito inteligente - em vez de gastar todo o tempo girando a imagem - misturando megabytes de dados - apenas marque COMO a foto foi tirada.

OpenGL faz traduções muito facilmente - para que os DADOS nunca sejam embaralhados - apenas COMO SEUS DESENHADOS.

Daí os metadados de orientação.

Isso se torna um problema se você deseja cortar, redimensionar etc - mas uma vez que você sabe o que está acontecendo, você apenas define sua matriz e tudo funciona.

Roy
fonte
1
Obrigado por esta explicação. Uma vez que você pensa sobre isso, tem bom senso, mas nenhum outro resultado pesquisado o explicou.
Dakine83
16

Versão do Swift 4 com verificações de segurança da resposta de Dilip .

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
fonte
Você também pode fazer (bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)sem criar variáveis ​​como armazenamento.
Almas Sapargali
Às vezes eu tinha o problema de que uma linha branca aparecia na parte inferior da imagem após dimensioná-la. Isso ocorre porque CGFloat parece não ser preciso o suficiente. bounds.size.height.round()bounds.size.width.round()
Corrigi
13

Qualquer imagem gerada pelo iPhone / iPad é salva como Paisagem Esquerda com a tag de Orientação EXIF ​​(Exif.Image.Orientation) especificando a orientação real.

Tem os seguintes valores: 1: Paisagem Esquerda 6: Retrato Normal 3: Paisagem Direita 4: Retrato De cabeça para baixo

No IOS, as informações EXIF ​​são lidas corretamente e as imagens são exibidas da mesma forma que foram tiradas. Mas no Windows, a informação EXIF ​​NÃO é usada.

Se você abrir uma dessas imagens no GIMP, ela dirá que a imagem tem informações de rotação.

ATOzTOA
fonte
8

Para qualquer pessoa que use o Xamarin, aqui está uma tradução em C # de Dilip ótima resposta e um agradecimento a thattyson pela tradução do 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
fonte
Isso ajudou a resolver meu problema depois de passar muitas horas brincando com isso! Inacreditável que o Xamarin não tenha algum suporte embutido para isso, visto que agora é um produto da Microsoft.
Sami.C de
4

Eu me deparei com essa pergunta porque estava tendo um problema semelhante, mas usando o Swift. Só queria fazer um link para a resposta que funcionou para mim para qualquer outro desenvolvedor Swift: https://stackoverflow.com/a/26676578/3904581

Aqui está um snippet do Swift que corrige o problema de forma eficiente:

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

Super simples. Uma linha de código. Problema resolvido.

Melly
fonte
Isso não funcionou para mim, usei esta solução: stackoverflow.com/a/27775741/945247
Leon
0

Eu sei exatamente qual é o seu problema. Você está usando o UIImagePicker, o que é estranho em todos os sentidos. Eu sugiro que você use AVFoundation para a câmera, que oferece flexibilidade na orientação e também na qualidade. Use AVCaptureSession. Você pode obter o código aqui. Como salvar fotos tiradas com AVFoundation no álbum de fotos?

Gautam Jain
fonte
0

Refatorado rapidamente para Swift 3 (alguém pode testá-lo e confirmar se tudo está funcionando bem?):

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!
}
Sabilândia
fonte
0

Aqui está a versão Swift3 da resposta incrível de Dilip

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
fonte
-3

Tente alterar o formato da imagem para .jpeg. Isso funcionou para mim

Victor Rius
fonte