iOS PNG Obraz obrócony o 90 stopni

W mojej aplikacji na iOS, którą piszę, zajmuję się PNGs, ponieważ zajmuję się kanałem alfa. Z jakiegoś powodu mogę załadować PNG do mojej imageView, ale kiedy przychodzi czas, aby albo skopiować obraz z mojej aplikacji (na planszę) lub zapisać obraz do mojej rolki aparatu, obraz obraca się o 90 stopni.

Szukałem wszędzie na ten temat i jedną z rzeczy, których się nauczyłem, jest to, że gdybym używał JPEG, nie miałbym tego problemu( brzmi), ze względu na informacje EXIF.

Moja aplikacja ma pełną funkcję kopiowania/wklejania, a oto kicker (napiszę to w krokach, aby było łatwiej śledzić):

  1. przejdź do rolki mojego aparatu i Skopiuj obraz
  2. wejdź do mojej aplikacji i naciśnij "Wklej", obraz pasty dobrze, I mogę to zrobić cały dzień
  3. Kliknij zaimplementowaną funkcję kopiowania, a następnie kliknij "Wklej", a obraz zostanie wklejony, ale zostanie obrócony.

Jestem w 100% pewien, że mój kod do kopiowania i wklejania nie jest tym, co jest tutaj nie tak, ponieważ jeśli wrócę do Krok 2 powyżej i kliknij "Zapisz", zdjęcie zapisuje się w mojej bibliotece, ale jest obracane o 90 stopni!

Jeszcze bardziej dziwne jest to, że wydaje się, że działa dobrze z obrazami pobranymi z internetu, ale jest bardzo hit lub miss z obrazami, które ręcznie zrobiłem telefonem. Niektóre działają, inne nie...

Czy ktoś ma jakieś przemyślenia na ten temat? Jakieś możliwości pracy w okolicy, które mogę wykorzystać? Jestem całkiem pewien, że kod działa dla około 75% moich obrazów. Mogę wysłać kod po ale proszę.
Author: Boeckm, 2012-04-25

6 answers

Dla tych, którzy chcą szybkiego rozwiązania, Utwórz rozszerzenie UIImage i dodaj następującą metodę:

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;
}
 25
Author: Tom J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 12:43:08

Jeśli masz problemy z istniejącą właściwością image imageOrientation, możesz skonstruować identyczny obraz o innej orientacji w następujący sposób:

CGImageRef imageRef = [sourceImage CGImage];

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

Być może będziesz musiał poeksperymentować z tym, jaką orientację ustawić na obrazach zastępczych, ewentualnie przełączając się na podstawie orientacji, od której zacząłeś.

Miej również oko na zużycie pamięci. Aplikacje fotograficzne często się kończą, a to podwoi ilość miejsca na zdjęcie, dopóki nie udostępnisz źródła obraz.

 14
Author: Dondragmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-25 02:46:32

Zajęło to kilka dni, ale w końcu rozgryzłem to dzięki odpowiedzi, którą napisał @Dondragmer. Ale pomyślałem, że opublikuję moje pełne rozwiązanie.

Więc w zasadzie musiałem napisać metodę inteligentnego automatycznego obracania moich obrazów. Minusem jest to, że muszę wywoływać tę metodę wszędzie w całym moim kodzie i jest to rodzaj intensywnego procesora, szczególnie podczas pracy na urządzeniach mobilnych, ale plusem jest to, że mogę robić obrazy, kopiować obrazy, wklejać obrazy i zapisywać obrazy, a wszystkie się obracają jak należy. Oto kod, którego użyłem (metoda nie jest jeszcze w 100% kompletna, nadal trzeba edytować wycieki pamięci i co nie).

W końcu dowiedziałem się, że po raz pierwszy obraz został wstawiony do mojej aplikacji (czy to ze względu na użytkownika naciśnięcie "take image", "wklej obraz", lub "wybierz obraz", z jakiegoś powodu wstawić tylko dobrze bez automatycznego obracania. W tym momencie zapisałem wartość rotacji w zmiennej globalnej o nazwie imageOrientationWhenAddedToScreen. To ułatwiło mi życie, ponieważ kiedy nadszedł czas, aby manipulować obrazem i zapisać obraz z programu, po prostu sprawdziłem tę buforowaną zmienną globalną i określiłem, Czy muszę prawidłowo obrócić obraz.

    - (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;

}

Nadal nie jestem w 100% pewien, dlaczego Apple ma takie dziwne zachowanie rotacji obrazu (spróbuj tego... Weź telefon i obróć go do góry nogami i zrób zdjęcie, zauważysz, że ostateczne zdjęcie okazuje się prawą stroną do góry - być może dlatego Apple ma tego typu funkcjonalność?).

I know I spędziłem dużo czasu na wymyślaniu tego, więc mam nadzieję, że pomoże to innym ludziom!

 13
Author: Boeckm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 16:07:59

To "dziwne zachowanie rotacji" nie jest wcale takie dziwne. Jest inteligentny, a przez inteligentny mam na myśli wydajną pamięć. Po obróceniu urządzenia z systemem iOS sprzęt kamery obraca się wraz z nim. Po zrobieniu zdjęcia to zdjęcie zostanie zrobione jednak aparat jest zorientowany. UIImage jest w stanie używać tych surowych danych obrazu bez kopiowania, po prostu śledząc orientację, w której powinien się znajdować. Kiedy używasz UIImagePNGRepresentation() tracisz te dane orientacyjne i otrzymujesz PNG podstawowego obrazu jako zostało zrobione przez kamerę. Aby to naprawić, zamiast obracać, możesz powiedzieć oryginalnemu obrazowi, aby narysował się w nowym kontekście i uzyskać odpowiednio zorientowany UIImage z tego kontekstu.

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);
 13
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-05 19:35:13

Oto jeszcze jeden sposób, aby to osiągnąć:

@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)
}
 0
Author: Dharmesh Kheni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-13 10:38:32

Możesz użyć Image I / O, aby zapisać obraz PNG do pliku (lub NSMutableData) w odniesieniu do orientacji obrazu. W poniższym przykładzie zapisuję obraz PNG do pliku 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: jest metodą UIImage kategorii.

+ (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;
}

Możesz alternatywnie zapisać obrazek do NSData używając CGImageDestinationCreateWithData i przekazać NSMutableData zamiast NSURL w CGImageDestinationCreateWithURL.

 0
Author: KudoCC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 10:30:12