Định hướng hình ảnh iOS có Hành vi lạ


94

Trong vài tuần qua, tôi đã làm việc với hình ảnh trong vật thể-c và nhận thấy rất nhiều hành vi kỳ lạ. Đầu tiên, giống như nhiều người khác, tôi đã gặp vấn đề này khi hình ảnh được chụp bằng máy ảnh (hoặc được chụp bằng máy ảnh của người khác và MMS'd cho tôi) bị xoay 90 độ. Tôi không chắc tại sao trên thế giới điều này lại xảy ra (do đó là câu hỏi của tôi ) nhưng tôi đã có thể nghĩ ra một công việc rẻ tiền.

Câu hỏi của tôi lần này là tại sao điều này lại xảy ra ? Tại sao Apple xoay hình ảnh? Khi tôi chụp ảnh với máy ảnh hướng lên bên phải, trừ khi tôi thực hiện mã đã đề cập ở trên, khi tôi lưu ảnh, nó sẽ được lưu xoay. Bây giờ, cách giải quyết của tôi đã ổn cho đến vài ngày trước.

Ứng dụng của tôi sửa đổi các pixel riêng lẻ của một hình ảnh, cụ thể là kênh alpha của PNG (vì vậy bất kỳ chuyển đổi JPEG nào đều bị loại khỏi cửa sổ đối với kịch bản của tôi). Một vài ngày trước, tôi nhận thấy rằng mặc dù hình ảnh được hiển thị chính xác trong ứng dụng của tôi nhờ mã giải pháp thay thế, nhưng khi thuật toán của tôi sửa đổi các pixel riêng lẻ của hình ảnh, nó cho rằng hình ảnh đã được xoay. Vì vậy, thay vì sửa đổi các pixel ở trên cùng của hình ảnh, nó sẽ sửa đổi các pixel ở bên cạnh của hình ảnh (vì nó nghĩ rằng nó nên được xoay)! Tôi không thể tìm ra cách xoay hình ảnh trong bộ nhớ - lý tưởng là tôi muốn xóa imageOrientationtất cả lá cờ đó cùng nhau.

Đây là một cái gì đó khác cũng làm tôi bối rối ... Khi tôi chụp ảnh, mã imageOrientationđược đặt thành 3. Mã giải pháp của tôi đủ thông minh để nhận ra điều này và lật nó để người dùng không bao giờ nhận thấy. Ngoài ra, mã của tôi để lưu hình ảnh vào thư viện nhận ra điều này, lật nó, sau đó lưu nó để nó xuất hiện trong thư viện chính xác.

Mã đó trông giống như vậy:

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

Khi tôi tải hình ảnh mới lưu này vào ứng dụng của mình, giá trị imageOrientationlà 0 - chính xác những gì tôi muốn xem và giải pháp xoay vòng của tôi thậm chí không cần chạy (lưu ý: khi tải hình ảnh từ internet thay vì hình ảnh được chụp bằng máy ảnh , imageOrientationluôn luôn là 0, dẫn đến hành vi hoàn hảo). Vì một số lý do, mã lưu của tôi dường như xóa sạch imageOrientationcờ này . Tôi đã hy vọng chỉ ăn cắp mã đó và sử dụng nó để xóa imageOrientation của mình ngay sau khi người dùng chụp ảnh và thêm nó vào ứng dụng, nhưng nó dường như không hoạt động. Làm UIImageWriteToSavedPhotosAlbumđiều gì đó đặc biệt với imageOrientation?

Cách khắc phục tốt nhất cho vấn đề này là chỉ thổi bay imageOrientationngay sau khi người dùng chụp ảnh xong. Tôi cho rằng Apple thực hiện hành vi xoay vòng là có lý do, phải không? Một vài người cho rằng đây là một khiếm khuyết của Apple.

(... nếu bạn vẫn chưa bị lạc ... Lưu ý 2: Khi tôi chụp ảnh ngang, mọi thứ dường như hoạt động hoàn hảo, giống như ảnh chụp từ internet)

BIÊN TẬP:

Dưới đây là một số hình ảnh và kịch bản thực sự trông như thế nào. Dựa trên các bình luận cho đến nay, có vẻ như hành vi kỳ lạ này không chỉ là một hành vi của iPhone, mà tôi nghĩ là tốt.

Đây là hình ảnh của bức ảnh tôi đã chụp bằng điện thoại của mình (lưu ý hướng phù hợp), nó xuất hiện chính xác như trên điện thoại của tôi khi tôi chụp ảnh:

Ảnh chụp thực tế trên iPhone

Đây là hình ảnh trông như thế nào trong Gmail sau khi tôi gửi nó qua email cho chính mình (có vẻ như Gmail xử lý nó đúng cách):

Ảnh xuất hiện trong Gmail

Đây là hình ảnh trông giống như một hình thu nhỏ trong cửa sổ (có vẻ như nó không được xử lý đúng cách):

Hình thu nhỏ của Windows

Và đây là hình ảnh thực tế trông như thế nào khi được mở bằng Windows Photo Viewer (vẫn chưa được xử lý đúng cách):

Phiên bản Windows Photo Viewer

Sau tất cả các bình luận về câu hỏi này, đây là những gì tôi đang nghĩ ... iPhone chụp ảnh và nói "để hiển thị đúng cách, nó cần phải được xoay 90 độ". Thông tin này sẽ nằm trong dữ liệu EXIF. (Tại sao nó cần được xoay 90 độ, chứ không phải mặc định là thẳng đứng, tôi không biết). Từ đây, Gmail đủ thông minh để đọc và phân tích dữ liệu EXIF ​​đó và hiển thị đúng cách. Tuy nhiên, Windows không đủ thông minh để đọc dữ liệu EXIF ​​và do đó hiển thị hình ảnh không đúng cách . Những giả định của tôi có đúng không?


Thật thú vị ... nếu đó là sự thật, tại sao những hình ảnh được chụp lại được đặt ở góc vuông? Tôi biết đây không phải là một khiếm khuyết của iPhone, vì tôi đã nhận thấy hành vi tương tự khi một người bạn (sử dụng BlackBerry) chụp ảnh và MMS của nó cho tôi.
Boeckm

Xem máy ảnh của bạn ghi siêu dữ liệu để xoay nó 90 độ, một số hệ điều hành đọc siêu dữ liệu đó và phần còn lại thì không.
HarshIT

Đọc khá tốt (xem câu trả lời của @ Hadley bên dưới - từng là trong một bình luận). Vì vậy, ứng dụng của tôi rõ ràng cần phải đủ thông minh để xử lý hình ảnh có chứa dữ liệu EXIF, cũng như hình ảnh không chứa dữ liệu đó ... Tôi vẫn không hiểu tại sao khi tôi chụp ảnh từ bên phải lên, cờ định hướng nói rằng nó nên được xoay 90 độ?
Boeckm

Bạn đặt chế độ ảnh thành Chân dung và bạn không xoay máy ảnh sang góc phải hoặc Chế độ phong cảnh được đặt và máy ảnh đã chụp ảnh ở vị trí góc đúng, cảm biến sẽ tự động đặt hướng thành thích hợp. Kiểm tra nó
HarshIT

1
Giải pháp có lẽ nhất là ứng dụng của bạn cần đọc dữ liệu meta và xoay hình ảnh và / hoặc sửa đổi siêu dữ liệu theo yêu cầu.
HarshIT

Câu trả lời:


50

Tôi đã thực hiện R&D trên đó và phát hiện ra, mọi tệp hình ảnh đều có thuộc tính siêu dữ liệu. Nếu siêu dữ liệu chỉ định hướng của hình ảnh thường bị hệ điều hành khác trừ Mac bỏ qua. Hầu hết các hình ảnh được chụp đều có thuộc tính dữ liệu meta được đặt thành góc vuông. Vì vậy, Mac hiển thị nó theo cách xoay 90 độ. Bạn có thể thấy hình ảnh tương tự theo cách thích hợp trong hệ điều hành windows.

Để biết thêm chi tiết, hãy đọc câu trả lời này http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

hãy thử đọc exif của hình ảnh của bạn tại đây http://www.exifviewer.org/ hoặc http://regex.info/exif.cgi hoặc http://www.addictivetips.com/internet-tips/view-complete-exif -metadata-information-of-any-jpeg-image-online /


1
WOW! Tôi không biết có RẤT NHIỀU thông tin trong dữ liệu EXIF! regex.info/exif.cgi là một trang web đáng kinh ngạc! Tôi chắc chắn sẽ chơi xung quanh với những hình ảnh tối nay trên trang web này. Tôi sẽ phải kiểm tra mọi kịch bản, hình ảnh chụp thẳng lên, hình ảnh lấy từ internet, hình ảnh được chụp xoay, v.v. Cảm ơn rất nhiều!
Boeckm

Liên kết exif đầu tiên hiện đã bị hỏng và liên kết thứ hai đã được cập nhật thành exif.regex.info/exif.cgi Tôi đã cố gắng chỉnh sửa câu trả lời nhưng @ cj-dennis đã từ chối nó vì một số lý do.
Ryan

55

Tôi đã gặp sự cố tương tự khi lấy hình ảnh từ Máy ảnh, tôi đã đặt mã sau để sửa nó .. Đã thêm phương pháp scaleAndRotateImage từ đây

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

3
Mã scaleAndRotateImage của bạn trông như thế nào? Sau khi thực hiện google, nó có giống với cái ở đây không? discussions.apple.com/thread/1537011?start=0&tstart=0
Boeckm

2
WOW ... Haha! Điều đó hoạt động rất tốt! Tôi đã sử dụng mã trong bình luận của tôi ở trên. Tôi có hai câu trả lời tuyệt vời cho câu hỏi của mình! Tôi nghĩ rằng điều đó có nghĩa là tôi đã đặt một câu hỏi quá lớn ... Cảm ơn rất nhiều. Tôi sẽ có một số thử nghiệm chuyên sâu để làm, nhưng cho đến nay vấn đề định hướng hoạt động tốt với các bức ảnh được chụp theo chiều dọc và chiều ngang.
Boeckm

3
Tôi nghĩ rằng đó là một phần của phương pháp của bạn mất tích, nhưng điều đó và liên kết vẫn còn đủ cho tôi để làm việc ra phần còn lại và cuối cùng là có được hình ảnh của tôi cắt xén xem hoạt động bình thường, do đó, nhờ :)
Vic Smith

Tôi rất vui vì nó đã giúp .. :)
Dilip Rajkumar

khối mã này có giữ nguyên hình ảnh ban đầu trông như thế nào nhưng thay đổi hướng để hướng lên không?
Junchao Gu

18

Sao chép / dán nhanh bản dịch Swift của câu trả lời xuất sắc của 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;
}

1
Cảm ơn, nhưng "let ratio = width / height;" sử dụng cho? Tôi không thể thấy bất kỳ nơi nào sử dụng tỷ lệ trong đó {}
Pengzhi Zhou

18

Câu hỏi của tôi lần này là tại sao điều này lại xảy ra? Tại sao Apple lại xoay hình ảnh?

Câu trả lời cho điều này rất đơn giản. Apple KHÔNG xoay hình ảnh. Đó là nơi mà sự nhầm lẫn nằm.

Máy ảnh CCD không xoay, vì vậy nó luôn chụp ảnh ở chế độ ngang.

Apple đã làm một điều rất thông minh - thay vì dành toàn bộ thời gian để xoay hình ảnh - xáo trộn hàng megabyte dữ liệu xung quanh - chỉ cần gắn thẻ nó bằng CÁCH chụp ảnh.

OpenGL thực hiện các bản dịch rất dễ dàng - vì vậy DỮ LIỆU không bao giờ bị xáo trộn - chỉ là CÁCH KHOẢNG CÁCH CỦA NÓ.

Do đó dữ liệu meta định hướng.

Điều này sẽ trở thành vấn đề nếu bạn muốn cắt, thay đổi kích thước, v.v. - nhưng khi bạn biết điều gì đang xảy ra, bạn chỉ cần xác định ma trận của mình và mọi thứ sẽ diễn ra.


1
Cảm ơn bạn vì lời giải thích này. Thông thường khi bạn nghĩ về nó, nhưng không có kết quả nào khác trên Google giải thích điều đó.
Dakine83

16

Phiên bản Swift 4 với sự kiểm tra an toàn của câu trả lời 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
}

Bạn cũng có thể làm (bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)mà không cần tạo biến làm bộ nhớ.
Almas Sapargali,

Đôi khi tôi gặp sự cố, đó là một đường màu trắng xuất hiện ở cuối hình ảnh sau khi thu nhỏ. Điều này là do CGFloat dường như không đủ chính xác. Tôi đã khắc phục sự cố này với bounds.size.height.round()bounds.size.width.round()
ndreisg

13

Bất kỳ hình ảnh nào do iPhone / iPad tạo ra đều được lưu dưới dạng Ngang Trái với thẻ Định hướng EXIF ​​(Exif.Image.Orientation) chỉ định hướng thực tế.

Nó có các giá trị sau: 1: Ngang Trái 6: Ngang Bình thường 3: Ngang Phải 4: Dọc Lật ngược

Trong IOS, thông tin EXIF ​​được đọc đúng cách và hình ảnh được hiển thị giống như cách nó được chụp. Nhưng trong Windows, thông tin EXIF ​​KHÔNG được sử dụng.

Nếu bạn mở một trong những hình ảnh này trong GIMP, nó sẽ thông báo rằng hình ảnh có thông tin xoay.


8

Đối với bất kỳ ai khác đang sử dụng Xamarin, đây là bản dịch C # về câu trả lời tuyệt vời của Dilip và lời cảm ơn đến thattyson về bản dịch 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;
}

Điều này đã giúp giải quyết vấn đề của tôi sau nhiều giờ chơi với nó! Không thể tin được rằng Xamarin không có một số hỗ trợ tích hợp cho việc này vì nó hiện là sản phẩm của Microsoft.
Sami.C

4

Tôi gặp câu hỏi này vì tôi đang gặp sự cố tương tự, nhưng đang sử dụng Swift. Tôi chỉ muốn liên kết đến câu trả lời phù hợp với tôi cho bất kỳ nhà phát triển Swift nào khác: https://stackoverflow.com/a/26676578/3904581

Đây là đoạn mã Swift có thể khắc phục sự cố một cách hiệu quả:

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

Siêu đơn giản. Một dòng mã. Vấn đề đã được giải quyết.


Điều này không hiệu quả với tôi, tôi đã sử dụng giải pháp này: stackoverflow.com/a/27775741/945247
Leon


0

Nhanh chóng cấu trúc lại cho Swift 3 (ai đó có thể kiểm tra nó và xác nhận mọi thứ hoạt động ổn không?):

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!
}

0

Đây là phiên bản Swift3 của câu trả lời tuyệt vời của 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!;
}

-3

Hãy thử thay đổi định dạng hình ảnh thành .jpeg. Điều này đã làm việc cho tôi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.