iOS PNG Изображение повернуто на 90 градусов

В моем приложении для iOS, которое я пишу, я имею дело с PNG, потому что я имею дело с альфа-каналом. По какой-то причине я могу нормально загрузить PNG в свой imageView, но когда приходит время либо скопировать изображение из моего приложения (на PasteBoard), либо сохранить изображение в фотопленку, изображение поворачивается на 90 градусов.

Я искал об этом везде, и одна из вещей, которые я узнал, заключается в том, что если бы я использовал JPEG, у меня не было бы этой проблемы (это звучит) из-за информации EXIF.

Мое приложение имеет полную функциональность копирования/вставки, и вот кикер (я напишу это по шагам, чтобы было легче следовать):

  1. Перейдите к моей фотопленке и скопируйте изображение
  2. Зайдите в мое приложение и нажмите «Вставить», изображение отлично вставляется, и я могу делать это весь день.
  3. Щелкните функцию копирования, которую я реализовал, а затем нажмите «Вставить», и изображение вставится, но будет повернуто.

Я на 100% уверен, что мой код копирования и вставки не является ошибкой, потому что, если я вернусь к шагу 2 выше и нажму «сохранить», фотография сохранится в моей библиотеке, но будет повернута на 90 градусов!

Что еще более странно, так это то, что он, кажется, отлично работает с изображениями, загруженными из Интернета, но очень плохо работает с изображениями, которые я сделал вручную с помощью телефона. У кого-то работает, у кого-то нет...

У кого-нибудь есть мысли по этому поводу? Любые возможные обходные пути, которые я могу использовать? Я вполне уверен, что код работает примерно для 75% моих изображений. Я могу опубликовать код по запросу.


person Boeckm    schedule 24.04.2012    source источник
comment
Попробуйте отобразить ссылку imageOrientation ваших изображений. Те, которые кажутся повернутыми, имеют значение, отличное от UIImageOrientationUp?   -  person Dondragmer    schedule 25.04.2012
comment
У PNG нет четко определенного стандарта для метаданных EXIF, но он включает в себя саму информацию о метаданных, поэтому, вероятно, ориентация в этих метаданных дает вам нежелательные результаты.   -  person Pochi    schedule 25.04.2012
comment
Просто добавил NSLogs в методы копирования, вставки, сохранения и фотографирования... Хорошая новость заключается в том, что все методы согласованы, плохая новость заключается в том, что изображения, которые имеют эту странную проблему с поворотом, имеют imageOrientation of Right (90 градусов по часовой стрелке). Примерно то, что я понял, вопрос в том, как это исправить? Я был бы не против просто сдуть этот атрибут, если бы это было разумно.   -  person Boeckm    schedule 25.04.2012
comment
Хммм... Только что кое-что проверил, если я перевожу свой телефон в режим полета и использую функцию "Сделать фото" в своем приложении, все работает нормально. Это связано с тем, что в режиме полета телефон не может использовать геотеги и, следовательно, не записывает метаданные EXIF ​​в изображение??   -  person Boeckm    schedule 25.04.2012
comment
возможный дубликат ориентации изображения результата UIImagePickerController iOS после загрузки   -  person Axel Guilmin    schedule 03.04.2015


Ответы (6)


Для тех, кому нужно решение Swift, создайте расширение UIImage и добавьте следующий метод:

func correctlyOrientedImage() -> UIImage {
    if self.imageOrientation == .up {
        return self
    }

    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return normalizedImage ?? self;
}
person Tom J    schedule 27.10.2014

Если у вас возникли проблемы из-за существующего свойства изображения imageOrientation, вы можете создать в остальном идентичное изображение с другой ориентацией следующим образом:

CGImageRef imageRef = [sourceImage CGImage];

UIImage *rotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationUp];

Возможно, вам придется поэкспериментировать с тем, какую ориентацию установить для замещающих изображений, возможно, переключаясь в зависимости от ориентации, с которой вы начали.

Также следите за использованием памяти. Приложения для фотографии часто заканчиваются, и это удваивает объем хранилища для каждого изображения, пока вы не опубликуете исходное изображение.

person Dondragmer    schedule 25.04.2012
comment
Я могу сделать это сегодня вечером, хороший звонок с проблемой использования памяти. Я до сих пор не понимаю, почему для свойства imageOrientation установлено значение 3 (90 градусов по часовой стрелке) на всех изображениях, сделанных с помощью моего iPhone?! Если возможно, я хотел бы просто принудительно установить ориентацию на ВВЕРХ на всех изображениях. - person Boeckm; 25.04.2012
comment
Недостатком этого является то, что мне нужно иметь этот код везде. Мне нужно будет добавить этот код в мой метод вставки, в мой метод выбора изображения и в мой метод получения изображения. Конечно, я мог бы сделать что-то умное с этим, я все еще не очень фанат этого. - person Boeckm; 25.04.2012
comment
Это тоже не работает. В моем методе вставки я устанавливаю imageRef = в pasteboard.image, а затем поворачиваю изображение, используя вторую строку кода, которую вы предоставили, и устанавливаю представление моего изображения на это изображение, но оно все равно не работает... - person Boeckm; 26.04.2012
comment
В моем примере я жестко запрограммировал UIImageOrientationUp. Вам, вероятно, придется поэкспериментировать с тем, какую новую ориентацию использовать, учитывая некоторые существующие ориентации. - person Dondragmer; 26.04.2012

Потребовалось несколько дней, но я, наконец, понял это благодаря ответу, опубликованному @Dondragmer. Но я решил опубликовать свое полное решение.

Так что в основном мне пришлось написать метод для интеллектуального автоматического поворота моих изображений. Недостатком является то, что мне приходится вызывать этот метод повсюду в моем коде, и он довольно интенсивно использует процессор, особенно при работе на мобильных устройствах, но плюсом является то, что я могу брать изображения, копировать изображения, вставлять изображения и сохранять изображения и все правильно вращаются. Вот код, который я в итоге использовал (метод еще не завершен на 100%, все еще нужно отредактировать утечки памяти, а что нет).

В итоге я узнал, что в самый первый раз, когда изображение было вставлено в мое приложение (независимо от того, было ли это из-за того, что пользователь нажал «снять изображение», «вставить изображение» или «выбрать изображение», по какой-то причине оно вставляется просто отлично без автоматического В этот момент я сохранил любое значение поворота в глобальной переменной с именем imageOrientationWhenAddedToScreen. Это облегчило мою жизнь, потому что, когда пришло время манипулировать изображением и сохранить изображение из программы, я просто проверил эту кешированную глобальную переменную и определил, нужно ли мне правильно повернуть изображение.

    - (UIImage*) rotateImageAppropriately:(UIImage*) imageToRotate {
    //This method will properly rotate our image, we need to make sure that
    //We call this method everywhere pretty much...

    CGImageRef imageRef = [imageToRotate CGImage];
    UIImage* properlyRotatedImage;

    if (imageOrientationWhenAddedToScreen == 0) {
       //Don't rotate the image
        properlyRotatedImage = imageToRotate;

    } else if (imageOrientationWhenAddedToScreen == 3) {

        //We need to rotate the image back to a 3
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:3];

    } else if (imageOrientationWhenAddedToScreen == 1) {

        //We need to rotate the image back to a 1
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:1];        

    }

    return properlyRotatedImage;

}

Я до сих пор не уверен на 100%, почему у Apple такое странное поведение поворота изображения (попробуйте это... Возьмите свой телефон, переверните его и сделайте снимок, вы заметите, что финальное изображение получается правильной стороной - возможно, это почему у Apple есть такая функциональность?).

Я знаю, что потратил много времени на выяснение этого, поэтому я надеюсь, что это поможет другим людям!

person Boeckm    schedule 29.04.2012

Это «странное вращение» на самом деле вовсе не такое уж и странное. Он умный, и под умным я подразумеваю эффективное использование памяти. Когда вы поворачиваете устройство iOS, оборудование камеры вращается вместе с ним. Когда вы делаете снимок, этот снимок будет сделан независимо от ориентации камеры. UIImage может использовать эти необработанные данные изображения без копирования, просто отслеживая ориентацию, в которой они должны быть. Когда вы используете UIImagePNGRepresentation() вы потеряете эти данные об ориентации и получите лежащее в основе изображение PNG в том виде, в каком оно было снято камерой. Чтобы исправить это, вместо поворота вы можете указать исходному изображению рисовать себя в новом контексте и получить правильно ориентированный UIImage из этого контекста.

UIImage *image = ...;

//Have the image draw itself in the correct orientation if necessary
if(!(image.imageOrientation == UIImageOrientationUp ||
    image.imageOrientation == UIImageOrientationUpMirrored))
{
    CGSize imgsize = image.size;
    UIGraphicsBeginImageContext(imgsize);
    [image drawInRect:CGRectMake(0.0, 0.0, imgsize.width, imgsize.height)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

NSData *png = UIImagePNGRepresentation(image);
person Joe    schedule 05.02.2014

Вот еще один способ добиться этого:

@IBAction func rightRotateAction(sender: AnyObject) {

    let imgToRotate = CIImage(CGImage: sourceImageView.image?.CGImage)
    let transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
    let rotatedImage = imgToRotate.imageByApplyingTransform(transform)
    let extent = rotatedImage.extent()
    let contex = CIContext(options: [kCIContextUseSoftwareRenderer: false])
    let cgImage = contex.createCGImage(rotatedImage, fromRect: extent)
    adjustedImage = UIImage(CGImage: cgImage)!
    UIView.transitionWithView(sourceImageView, duration: 0.5, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
            self.sourceImageView.image = self.adjustedImage
        }, completion: nil)
}
person Dharmesh Kheni    schedule 13.08.2015
comment
Внимание, создание CIContext очень дорого - person Andrea; 28.10.2015

Вы можете использовать ввод-вывод изображения для сохранения изображения PNG в файл (или NSMutableData) с учетом ориентации изображения. В приведенном ниже примере я сохраняю изображение PNG в файл по адресу path.

- (BOOL)savePngFile:(UIImage *)image toPath:(NSString *)path {
    NSData *data = UIImagePNGRepresentation(image);
    int exifOrientation = [UIImage cc_iOSOrientationToExifOrientation:image.imageOrientation];
    NSDictionary *metadata = @{(__bridge id)kCGImagePropertyOrientation:@(exifOrientation)};
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    if (!source) {
        return NO;
    }
    CFStringRef UTI = CGImageSourceGetType(source);
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, UTI, 1, NULL);
    if (!destination) {
        CFRelease(source);
        return NO;
    }
    CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef)metadata);
    BOOL success = CGImageDestinationFinalize(destination);
    CFRelease(destination);
    CFRelease(source);
    return success;
}

cc_iOSOrientationToExifOrientation: — метод категории UIImage.

+ (int)cc_iOSOrientationToExifOrientation:(UIImageOrientation)iOSOrientation {
    int exifOrientation = -1;
    switch (iOSOrientation) {
        case UIImageOrientationUp:
            exifOrientation = 1;
            break;

        case UIImageOrientationDown:
            exifOrientation = 3;
            break;

        case UIImageOrientationLeft:
            exifOrientation = 8;
            break;

        case UIImageOrientationRight:
            exifOrientation = 6;
            break;

        case UIImageOrientationUpMirrored:
            exifOrientation = 2;
            break;

        case UIImageOrientationDownMirrored:
            exifOrientation = 4;
            break;

        case UIImageOrientationLeftMirrored:
            exifOrientation = 5;
            break;

        case UIImageOrientationRightMirrored:
            exifOrientation = 7;
            break;

        default:
            exifOrientation = -1;
    }
    return exifOrientation;
}

В качестве альтернативы вы можете сохранить изображение в NSData, используя CGImageDestinationCreateWithData, и передать NSMutableData вместо NSURL в CGImageDestinationCreateWithURL.

person KudoCC    schedule 17.05.2016