การวางแนวรูปภาพผลของ iOS UIImagePickerController หลังจากอัปโหลด


332

ฉันกำลังทดสอบแอปพลิเคชัน iPhone ของฉันบน iOS 3.1.3 iPhone ฉันกำลังเลือก / ถ่ายภาพโดยใช้UIImagePickerController:

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[imagePicker setDelegate:self];
[self.navigationController presentModalViewController:imagePicker animated:YES];
[imagePicker release];



- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
    imageView.image = self.image;
    [self.navigationController dismissModalViewControllerAnimated:YES];
    submitButton.enabled = YES;
}

ในบางครั้งฉันก็ส่งไปยังเว็บเซิร์ฟเวอร์ของฉันโดยใช้คลาส ASI:

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://example.com/myscript.php"]];
[request setDelegate:self];
[request setStringEncoding:NSUTF8StringEncoding];
[request setShouldContinueWhenAppEntersBackground:YES];
//other post keys/values
[request setFile:UIImageJPEGRepresentation(self.image, 100.0f) withFileName:[NSString stringWithFormat:@"%d.jpg", [[NSDate date] timeIntervalSinceNow]] andContentType:@"image/jpg" forKey:@"imageFile"];
[request startAsynchronous];

ปัญหา: เมื่อฉันถ่ายภาพด้วย iphone ในขณะที่ถือเป็นแนวนอนรูปภาพจะถูกอัปโหลดไปยังเซิร์ฟเวอร์และดูเหมือนว่าคุณจะคาดหวัง เมื่อถ่ายภาพถือโทรศัพท์ในแนวตั้งรูปภาพจะถูกอัปโหลดและดูเนื่องจากหมุนไป 90 องศา

แอปพลิเคชันของฉันถูกตั้งค่าให้ทำงานในโหมดแนวตั้งเท่านั้น (กลับด้านและปกติ)

ฉันจะทำให้ภาพแสดงการวางแนวที่ถูกต้องเสมอหลังจากอัปโหลดได้อย่างไร

ภาพดูเหมือนจะถูกต้องตามที่ปรากฏใน UIImageView (หลังจากถ่ายภาพโดยตรง) แต่การดูบนเซิร์ฟเวอร์จะระบุเป็นอย่างอื่น

คำตอบ:


513

A UIImageมีคุณสมบัติimageOrientationซึ่งสั่งให้ผู้บริโภคUIImageViewและอื่น ๆUIImageหมุนข้อมูลภาพดิบ มีโอกาสที่ดีที่การตั้งค่าสถานะนี้จะถูกบันทึกลงในข้อมูล exif ในอิมเมจ jpeg ที่อัปโหลด แต่โปรแกรมที่คุณใช้เพื่อดูไม่ได้รับการยอมรับจากการตั้งค่าสถานะนั้น

หากต้องการหมุนUIImageไปที่แสดงอย่างถูกต้องเมื่ออัปโหลดคุณสามารถใช้หมวดหมู่ดังนี้:

UIImage + fixOrientation.h

@interface UIImage (fixOrientation)

- (UIImage *)fixOrientation;

@end

UIImage + fixOrientation.m

@implementation UIImage (fixOrientation)

- (UIImage *)fixOrientation {

    // No-op if the orientation is already correct
    if (self.imageOrientation == UIImageOrientationUp) return self;

    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    CGAffineTransform transform = CGAffineTransformIdentity;

    switch (self.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            break;
    }

    switch (self.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationDown:
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
            break;
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
                                             CGImageGetBitsPerComponent(self.CGImage), 0,
                                             CGImageGetColorSpace(self.CGImage),
                                             CGImageGetBitmapInfo(self.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (self.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
            break;

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
            break;
    }

    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}

@end

9
ขอบคุณทำงานสมบูรณ์แบบ ไม่เคยใช้หมวดหมู่หรือเข้าใจพวกเขาจนกระทั่งตอนนี้!
James

1
@Anomie มันยากสำหรับฉันที่จะอธิบายว่าคุณมีความสุขแค่ไหนที่ทำให้ฉัน คำตอบของคุณช่วยชีวิตฉันไว้ ขอบคุณมาก.
Darkshore Grouper

3
ฉันลองเหมือนกันใช้งานได้ดี แต่ใช้เวลาประมาณ 2-3 วินาทีในการหมุนภาพความละเอียด 3264 * 2448 ดังนั้นโปรดแนะนำรุ่นที่ปรับปรุงใหม่
Laxmi Lal Menaria

3
ฉันพิจารณาstackoverflow.com/questions/8915630/…คำตอบที่ดีกว่า
pojomx

2
ยังมีวิธีแก้ไขปัญหานี้อีกวิธีหนึ่ง ที่นี่ (ค่อนข้างคล้ายกับที่นี้) ซึ่งรวมถึงการอภิปรายที่ยาวนานของสิ่งที่เกิดขึ้นจริง
Gallymon

239

ฉันคิดออกง่ายกว่ามาก:

- (UIImage *)normalizedImage {
    if (self.imageOrientation == UIImageOrientationUp) return self; 

    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawInRect:(CGRect){0, 0, self.size}];
    UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return normalizedImage;
}

BTW: @ รหัสของ Anomie ไม่ได้คำนึงscaleถึงดังนั้นจะไม่ทำงานกับภาพ 2x


คุณใช้มันอย่างไรในรหัส? ฉันมีสิ่งนี้: UIImageJPEG การนำเสนอ (รูปภาพ 90); ที่ภาพเป็น UIImage
Dejell

2
@Odelya เพิ่มวิธีนี้ในหมวดหมู่ UIImage ของคุณแล้วเรียก [image normalizedImage] หรือใช้รหัสของวิธีการโดยตรงโดยแทนที่selfด้วยวัตถุ UIImage ของคุณ
an0

1
@ an0 วิธีการใช้เวลาประมาณหนึ่งวินาทีซึ่งใช้เวลา มีวิธีปรับปรุงหรือไม่
Dejell

1
ขอบคุณสำหรับสิ่งนั้นจากการทดสอบของฉันดูเหมือนว่าวิธีนี้จะเร็วกว่าคำตอบที่เลือกเล็กน้อยเช่น 20% สำหรับ iphone4 ของฉัน
chrisben

7
ยังมีวิธีแก้ไขปัญหานี้อีกที่นี่พร้อมกับคำอธิบายที่ยาวเกี่ยวกับสิ่งที่เกิดขึ้น
Gallymon

118

นี่คือคำตอบเวอร์ชั่นโดย Swift โดย @ an0:

func normalizedImage() -> UIImage {

  if (self.imageOrientation == UIImageOrientation.Up) { 
      return self;
  }

  UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
  let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
  self.drawInRect(rect)

  let normalizedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext();
  return normalizedImage;
}

นอกจากนี้ในฟังก์ชั่นทั่วไปมากขึ้น:

func fixOrientation(img:UIImage) -> UIImage {

  if (img.imageOrientation == UIImageOrientation.Up) { 
      return img;
  }

  UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale);
  let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
  img.drawInRect(rect)

  let normalizedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext();
  return normalizedImage;

}

เวอร์ชั่น Swift 3:

func fixOrientation(img: UIImage) -> UIImage {
    if (img.imageOrientation == .up) {
        return img
    }

    UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
    let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
    img.draw(in: rect)

    let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return normalizedImage
}

7
หายากที่คุณต้องเลื่อนไปจนสุดเพื่อหาคำตอบที่ดีที่สุด +1!
sudo ทำการติดตั้ง

ฉันควรใช้ fixOrientation ที่ไหน ฉันมีฟังก์ชั่น saveImage ฉันควรใช้ที่นั่นหรือที่ imageHolder.image ของฉันหรือไม่?
alex

หากคุณต้องการใช้ฟังก์ชั่นทั่วไปด้านบนใช่คุณสามารถใช้ฟังก์ชั่น saveImage ของคุณได้ เพียงผ่านการแก้ไขการเปิดใช้งานวัตถุ UII ของคุณและมันจะคืนค่ารุ่นที่มุ่งเน้นอย่างถูกต้องของ UIImage ที่คุณส่งผ่านเข้าไป
prajna

1
ขอบคุณสำหรับรุ่น Swift 3
Shadros

41

วิธีแก้ปัญหาสำหรับ Swift 3.1 สำหรับปัญหาการวางแนวขณะถ่ายภาพจากกล้อง

ฉันได้อัปเดตโซลูชันที่ให้โดย jake และ Metal Heart

ส่วนขยาย UIImage

//MARK:- Image Orientation fix

extension UIImage {

    func fixOrientation() -> UIImage {

        // No-op if the orientation is already correct
        if ( self.imageOrientation == UIImageOrientation.up ) {
            return self;
        }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        var transform: CGAffineTransform = CGAffineTransform.identity

        if ( self.imageOrientation == UIImageOrientation.down || self.imageOrientation == UIImageOrientation.downMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: self.size.height)
            transform = transform.rotated(by: CGFloat(Double.pi))
        }

        if ( self.imageOrientation == UIImageOrientation.left || self.imageOrientation == UIImageOrientation.leftMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.rotated(by: CGFloat(Double.pi / 2.0))
        }

        if ( self.imageOrientation == UIImageOrientation.right || self.imageOrientation == UIImageOrientation.rightMirrored ) {
            transform = transform.translatedBy(x: 0, y: self.size.height);
            transform = transform.rotated(by: CGFloat(-Double.pi / 2.0));
        }

        if ( self.imageOrientation == UIImageOrientation.upMirrored || self.imageOrientation == UIImageOrientation.downMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        }

        if ( self.imageOrientation == UIImageOrientation.leftMirrored || self.imageOrientation == UIImageOrientation.rightMirrored ) {
            transform = transform.translatedBy(x: self.size.height, y: 0);
            transform = transform.scaledBy(x: -1, y: 1);
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height),
                                                      bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0,
                                                      space: self.cgImage!.colorSpace!,
                                                      bitmapInfo: self.cgImage!.bitmapInfo.rawValue)!;

        ctx.concatenate(transform)

        if ( self.imageOrientation == UIImageOrientation.left ||
            self.imageOrientation == UIImageOrientation.leftMirrored ||
            self.imageOrientation == UIImageOrientation.right ||
            self.imageOrientation == UIImageOrientation.rightMirrored ) {
            ctx.draw(self.cgImage!, in: CGRect(x: 0,y: 0,width: self.size.height,height: self.size.width))
        } else {
            ctx.draw(self.cgImage!, in: CGRect(x: 0,y: 0,width: self.size.width,height: self.size.height))
        }

        // And now we just create a new UIImage from the drawing context and return it
        return UIImage(cgImage: ctx.makeImage()!)
    }
}

Swift 2.0

//MARK:- Image Orientation fix

extension UIImage {

    func fixOrientation() -> UIImage {

        // No-op if the orientation is already correct
        if ( self.imageOrientation == UIImageOrientation.Up ) {
            return self;
        }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        var transform: CGAffineTransform = CGAffineTransformIdentity

        if ( self.imageOrientation == UIImageOrientation.Down || self.imageOrientation == UIImageOrientation.DownMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
        }

        if ( self.imageOrientation == UIImageOrientation.Left || self.imageOrientation == UIImageOrientation.LeftMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
        }

        if ( self.imageOrientation == UIImageOrientation.Right || self.imageOrientation == UIImageOrientation.RightMirrored ) {
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform,  CGFloat(-M_PI_2));
        }

        if ( self.imageOrientation == UIImageOrientation.UpMirrored || self.imageOrientation == UIImageOrientation.DownMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformScale(transform, -1, 1)
        }

        if ( self.imageOrientation == UIImageOrientation.LeftMirrored || self.imageOrientation == UIImageOrientation.RightMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height),
            CGImageGetBitsPerComponent(self.CGImage), 0,
            CGImageGetColorSpace(self.CGImage),
            CGImageGetBitmapInfo(self.CGImage).rawValue)!;

        CGContextConcatCTM(ctx, transform)

        if ( self.imageOrientation == UIImageOrientation.Left ||
            self.imageOrientation == UIImageOrientation.LeftMirrored ||
            self.imageOrientation == UIImageOrientation.Right ||
            self.imageOrientation == UIImageOrientation.RightMirrored ) {
                CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage)
        } else {
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage)
        }

        // And now we just create a new UIImage from the drawing context and return it
        return UIImage(CGImage: CGBitmapContextCreateImage(ctx)!)
    }
}

การใช้ UIImage Extension ในรหัสของคุณ:

ให้ fixOrientationImage = selectedImage.fixOrientation ()

วางสิ่งนี้ในวิธีมอบสิทธิ์ของตัวเลือกภาพเช่นนี้

สวิฟท์ 3.1

//MARK: Image Picker Delegates
    func imagePickerController(
        _ picker: UIImagePickerController,
        didFinishPickingMediaWithInfo info: [String : Any]){
        let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
        profileImg.contentMode = .scaleAspectFill
        let fixOrientationImage=chosenImage.fixOrientation()
        profileImg.image = fixOrientationImage

        dismiss(animated: true, completion: nil)
    }

Swift 2.0

//MARK: Image Picker Delegates
    func imagePickerController(
        picker: UIImagePickerController,
        didFinishPickingMediaWithInfo info: [String : AnyObject])
    {
        let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
        profileImg.contentMode = .ScaleAspectFill
        **//Fix the image orientation**
         let fixOrientationImage=chosenImage.fixOrientation()
        profileImg.image = fixOrientationImage

        dismissViewControllerAnimated(true, completion: nil)
    }

3
ขอบคุณสิ่งนี้ช่วยฉันได้มาก
darkndream

ฉันมี ViewController แล้วฉันจะวางคันนี้ไว้ที่ไหน?
applecrusher

โดยเฉพาะอย่างยิ่งฉันสามารถวางสิ่งนี้ไว้ในนั้นได้ที่ไหนและฉันจะต้องเรียกวิธีนี้อย่างไร
applecrusher

มันทำงาน แต่ฉันสงสัยว่ามีวิธีใดบ้างที่สามารถหลีกเลี่ยงการเรียก CG ที่เกี่ยวข้องกับ API เนื่องจากสิ่งนั้นทำให้เกิดการจัดสรรหน่วยความจำจำนวนมาก มันจะได้รับการปล่อยตัวเมื่อเราไม่รักษา UIImage อีกต่อไป
Tony Fung Choi Fung

1
มันใช้งานได้ดีจนถึง iOS 10 ใน iOS 11 หลังจากทำสิ่งนี้ฉันจะได้ภาพสีดำกลับมา ฉันได้ทำการเปลี่ยนแปลงเล็กน้อย (แทนที่ M_PI ด้วย Double.pi) ฉันใช้ XCode 9 กับ Swift 3.2
Mahbub Morshed

25

อย่างรวดเร็ว;)

อัพเดต SWIFT 3.0: D

func sFunc_imageFixOrientation(img:UIImage) -> UIImage {


    // No-op if the orientation is already correct
    if (img.imageOrientation == UIImageOrientation.up) {
        return img;
    }
    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    var transform:CGAffineTransform = CGAffineTransform.identity

    if (img.imageOrientation == UIImageOrientation.down
        || img.imageOrientation == UIImageOrientation.downMirrored) {

        transform = transform.translatedBy(x: img.size.width, y: img.size.height)
        transform = transform.rotated(by: CGFloat(M_PI))
    }

    if (img.imageOrientation == UIImageOrientation.left
        || img.imageOrientation == UIImageOrientation.leftMirrored) {

        transform = transform.translatedBy(x: img.size.width, y: 0)
        transform = transform.rotated(by: CGFloat(M_PI_2))
    }

    if (img.imageOrientation == UIImageOrientation.right
        || img.imageOrientation == UIImageOrientation.rightMirrored) {

        transform = transform.translatedBy(x: 0, y: img.size.height);
        transform = transform.rotated(by: CGFloat(-M_PI_2));
    }

    if (img.imageOrientation == UIImageOrientation.upMirrored
        || img.imageOrientation == UIImageOrientation.downMirrored) {

        transform = transform.translatedBy(x: img.size.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)
    }

    if (img.imageOrientation == UIImageOrientation.leftMirrored
        || img.imageOrientation == UIImageOrientation.rightMirrored) {

        transform = transform.translatedBy(x: img.size.height, y: 0);
        transform = transform.scaledBy(x: -1, y: 1);
    }


    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    let ctx:CGContext = CGContext(data: nil, width: Int(img.size.width), height: Int(img.size.height),
                                  bitsPerComponent: img.cgImage!.bitsPerComponent, bytesPerRow: 0,
                                  space: img.cgImage!.colorSpace!,
                                  bitmapInfo: img.cgImage!.bitmapInfo.rawValue)!

    ctx.concatenate(transform)


    if (img.imageOrientation == UIImageOrientation.left
        || img.imageOrientation == UIImageOrientation.leftMirrored
        || img.imageOrientation == UIImageOrientation.right
        || img.imageOrientation == UIImageOrientation.rightMirrored
        ) {


        ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.height,height:img.size.width))

    } else {
        ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.width,height:img.size.height))
    }


    // And now we just create a new UIImage from the drawing context
    let cgimg:CGImage = ctx.makeImage()!
    let imgEnd:UIImage = UIImage(cgImage: cgimg)

    return imgEnd
}

หลังจากหลายสัปดาห์ของการดิ้นรนกับปัญหานี้และลองวิธีแก้ปัญหาอื่น ๆ อีกมากมายปัญหานี้ได้ผลอย่างสมบูรณ์ ถ้าฉันสามารถลงคะแนน +10 ฉันจะ ขอบคุณ. :)
SirNod

@ MetalHeart2003 วิธีนี้อย่างมากเพิ่มขนาดไฟล์รูปภาพของฉัน Mine เริ่มจาก 200kb เป็น 4mb มีวิธีใดที่จะหยุดสิ่งนี้ได้หรือไม่?
TimWhiting

2
@ TimWhiting ดูเหมือนว่าคุณเริ่มต้นด้วยภาพที่ถูกบีบอัด แต่วิธีนี้จะวาดภาพที่หมุนใหม่โดยไม่มีการบีบอัดใด ๆ คุณสามารถบีบอัดภาพบิตแมปอีกครั้งในภายหลังด้วย UIImageJPEG การนำเสนอ ()
Richard Venable

16

@an0โซลูชันของรุ่น Swift 4.x / 5.0 :

extension UIImage {
    func upOrientationImage() -> UIImage? {
        switch imageOrientation {
        case .up:
            return self
        default:
            UIGraphicsBeginImageContextWithOptions(size, false, scale)
            draw(in: CGRect(origin: .zero, size: size))
            let result = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return result
        }
    }
}

1
ขอบคุณมันทำงานได้อย่างสมบูรณ์แบบที่สุดคำตอบที่ประเมินน้อยที่สุด
Vinayak Bhor

@VayayakBhor:]
Benjamin Wen

12

ฉันใช้หน้านี้เมื่อออกแบบแอพที่ถ่ายภาพและฉันพบว่าวิธีการต่อไปนี้จะแก้ไขการวางแนวและใช้หน่วยความจำและตัวประมวลผลน้อยกว่าคำตอบก่อนหน้า:

CGImageRef cgRef = image.CGImage;
image = [[UIImage alloc] initWithCGImage:cgRef scale:1.0 orientation:UIImageOrientationUp];

เพียงแค่กรอกข้อมูลภาพที่แท้จริงด้วยการวางแนวใหม่ ฉันใช้รหัส @ an0 แต่มันทำให้ภาพใหม่ในหน่วยความจำซึ่งสามารถเก็บภาษีได้ในภาพขนาด 3264x2448 ที่คุณอาจได้รับจากกล้อง


1
ฉันทดสอบคำตอบนี้ด้วย iOS 7.1 บน iPhone 5s แต่มันไม่ทำงานซึ่งเครื่อง windows [MS-Paint, Win photo Viewer] และ UIImageView แสดงภาพที่มีการวางแนว 90 องศาจากต้นฉบับ! โปรดทราบว่าภาพที่ถ่ายด้วยปุ่มกล้องเริ่มต้นไม่ใช่ระดับเสียง
Jawad Al Shaikh

3
ดูเหมือนว่านี่เป็นเพียงการเปลี่ยนธงปฐมนิเทศ ... ต้องหมุนบิตจริง
hamsterdam

10

หากคุณเปิดใช้งานการแก้ไขรูปภาพที่แก้ไข (ตรงข้ามกับต้นฉบับ) จะถูกจัดวางตามที่คาดไว้:

UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.allowsEditing = YES;
// set delegate and present controller

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    UIImage *photo = [info valueForKey:UIImagePickerControllerEditedImage];
    // do whatever
}

การเปิดใช้งานการแก้ไขช่วยให้ผู้ใช้ปรับขนาดและย้ายภาพก่อนที่จะแตะ "ใช้ภาพถ่าย"


น่าเสียดายที่โซลูชันนี้ไม่พลิกภาพในแนวนอนแม้จะอนุญาตให้แก้ไข
King-Wizard

4
ใช้งานได้ แต่บังคับให้ผู้ใช้ครอบตัดรูปภาพเป็นสี่เหลี่ยมเว้นเสียแต่ว่าคุณต้องการเพิ่มรหัสอีกมากเพื่อให้สามารถครอบตัดขนาด
user3000868

6

นี่คือสิ่งที่ฉันได้พบเพื่อแก้ไขปัญหาการวางแนว

UIImage *initialImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
NSData *data = UIImagePNGRepresentation(self.initialImage);

UIImage *tempImage = [UIImage imageWithData:data];
UIImage *fixedOrientationImage = [UIImage imageWithCGImage:tempImage.CGImage
                                     scale:initialImage.scale
                               orientation:self.initialImage.imageOrientation];
initialImage = fixedOrientationImage;

แก้ไข:

UIImage *initialImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
NSData *data = UIImagePNGRepresentation(self.initialImage);

initialImage = [UIImage imageWithCGImage:[UIImage imageWithData:data].CGImage
                                                     scale:initialImage.scale
                                               orientation:self.initialImage.imageOrientation];

2
การแปลงระหว่างรูปภาพเป็น PNG มากเกินไปกลับไปที่รูปภาพทำให้มีราคาแพง @ an0 คำตอบดีกว่า
lxcid

4

อัปเดตสำหรับ Swift 3.1 ตามSourabh Sharmaคำตอบของโค้ดโดยการล้างข้อมูลโค้ด

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

        var transform:CGAffineTransform = .identity
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height).rotated(by: .pi)
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0).rotated(by: .pi/2)
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height).rotated(by: -.pi/2)
        default: break
        }

        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: 0).scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: size.height, y: 0).scaledBy(x: -1, y: 1)
        default: break
        }

        let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height),
                                       bitsPerComponent: cgImage!.bitsPerComponent, bytesPerRow: 0,
                                       space: cgImage!.colorSpace!, bitmapInfo: cgImage!.bitmapInfo.rawValue)!
        ctx.concatenate(transform)

        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(cgImage!, in: CGRect(x: 0, y: 0, width: size.height,height: size.width))
        default:
            ctx.draw(cgImage!, in: CGRect(x: 0, y: 0, width: size.width,height: size.height))
        }
        return UIImage(cgImage: ctx.makeImage()!)
    }
}

ตัวอย่างวิธีมอบหมายของตัวเลือก:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    guard let originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
    let fixedImage = originalImage.fixedOrientation()
    // do your work
}

4

นี่คือวิธีการแก้ปัญหาที่ไม่เปลี่ยนสีของภาพต้นฉบับ หากคุณต้องการทำให้การวางแนวของภาพสีเทาเป็นเรื่องปกติคุณไม่มีโชคกับการแก้ปัญหาทั้งหมดUIGraphicsBeginImageContextWithOptionsเพราะมันจะสร้างบริบทในพื้นที่สี RGB แต่คุณต้องสร้างบริบทที่มีคุณสมบัติเช่นเดียวกับภาพต้นฉบับและวาด:

extension UIImage {
    static let rotatedOrentations: [UIImage.Orientation] = [.left, .leftMirrored, .right, .rightMirrored]

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

        let image = self.cgImage!
        let swapOrientation = UIImage.rotatedOrentations.contains(imageOrientation)
        let width = swapOrientation ? image.height : image.width
        let height = swapOrientation ? image.width : image.height
        let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: image.bitsPerComponent, bytesPerRow: image.bytesPerRow, space: image.colorSpace!, bitmapInfo: image.bitmapInfo.rawValue)!
        let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height));
        context.concatenate(flipVertical)
        UIGraphicsPushContext(context)
        self.draw(at: .zero)
        UIGraphicsPopContext()

        return UIImage(cgImage: context.makeImage()!)
    }
}

3

นี่คือส่วนขยาย UIImage สำหรับ swift:

extension UIImage {

    func fixOrientation() -> UIImage {

        // No-op if the orientation is already correct
        if ( self.imageOrientation == UIImageOrientation.Up ) {
            return self;
        }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        var transform: CGAffineTransform = CGAffineTransformIdentity

        if ( self.imageOrientation == UIImageOrientation.Down || self.imageOrientation == UIImageOrientation.DownMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
        }

        if ( self.imageOrientation == UIImageOrientation.Left || self.imageOrientation == UIImageOrientation.LeftMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
        }

        if ( self.imageOrientation == UIImageOrientation.Right || self.imageOrientation == UIImageOrientation.RightMirrored ) {
            transform = CGAffineTransformTranslate(transform, 0, self.size.height);
            transform = CGAffineTransformRotate(transform,  CGFloat(-M_PI_2));
        }

        if ( self.imageOrientation == UIImageOrientation.UpMirrored || self.imageOrientation == UIImageOrientation.DownMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformScale(transform, -1, 1)
        }

        if ( self.imageOrientation == UIImageOrientation.LeftMirrored || self.imageOrientation == UIImageOrientation.RightMirrored ) {
            transform = CGAffineTransformTranslate(transform, self.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        var ctx: CGContextRef = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height),
            CGImageGetBitsPerComponent(self.CGImage), 0,
            CGImageGetColorSpace(self.CGImage),
            CGImageGetBitmapInfo(self.CGImage));

        CGContextConcatCTM(ctx, transform)

        if ( self.imageOrientation == UIImageOrientation.Left ||
            self.imageOrientation == UIImageOrientation.LeftMirrored ||
            self.imageOrientation == UIImageOrientation.Right ||
            self.imageOrientation == UIImageOrientation.RightMirrored ) {
                CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage)
        } else {
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage)
        }

        // And now we just create a new UIImage from the drawing context and return it
        return UIImage(CGImage: CGBitmapContextCreateImage(ctx))!
    }
}

จากการทำงานก่อนหน้านี้ของ MetalHeart2003 ..


3

นี่คือส่วนขยาย UIImage ใน Swift 2 ตามคำตอบที่ยอมรับโดย @Anomie ใช้ตัวเรือนสวิตช์ที่ชัดเจน นอกจากนี้ยังใช้ค่าที่เป็นทางเลือกที่ส่งคืนโดยCGBitmapContextCreateImage()คำนึงถึง

extension UIImage {
    func rotateImageByOrientation() -> UIImage {
        // No-op if the orientation is already correct
        guard self.imageOrientation != .Up else {
            return self
        }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        var transform = CGAffineTransformIdentity;

        switch (self.imageOrientation) {
        case .Down, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI))

        case .Left, .LeftMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))

        case .Right, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, self.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))

        default:
            break
        }

        switch (self.imageOrientation) {
        case .UpMirrored, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.width, 0)
            transform = CGAffineTransformScale(transform, -1, 1)

        case .LeftMirrored, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, self.size.height, 0)
            transform = CGAffineTransformScale(transform, -1, 1)

        default:
            break
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height),
            CGImageGetBitsPerComponent(self.CGImage), 0,
            CGImageGetColorSpace(self.CGImage),
            CGImageGetBitmapInfo(self.CGImage).rawValue)
        CGContextConcatCTM(ctx, transform)
        switch (self.imageOrientation) {
        case .Left, .LeftMirrored, .Right, .RightMirrored:
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage)

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage)
        }

        // And now we just create a new UIImage from the drawing context
        if let cgImage = CGBitmapContextCreateImage(ctx) {
            return UIImage(CGImage: cgImage)
        } else {
            return self
        }
    }
}

3

ฉันประสบปัญหานี้กับภาพที่ถ่ายจากกล้องหรือบันทึกในม้วนฟิล์มซึ่งถ่ายจากกล้อง รูปภาพที่ดาวน์โหลดในไลบรารีรูปภาพจากเบราว์เซอร์ซาฟารีจะไม่หมุนเมื่ออัปโหลด

ฉันสามารถแก้ไขปัญหานี้ได้ด้วยการทำให้ข้อมูลภาพเป็น JPEG ก่อนที่จะอัปโหลด

let image = info[UIImagePickerControllerOriginalImage] as! UIImage        
let data = UIImageJPEGRepresentation(image, 1.0)

ตอนนี้เราสามารถใช้ข้อมูลสำหรับการอัปโหลดและภาพจะไม่หมุนหลังจากอัปโหลด

หวังว่ามันจะใช้ได้


แปลกมากที่ข้อมูล png ยังคงหมุนอยู่ แต่การหมุนได้รับการแก้ไขเมื่อใช้ข้อมูล jpeg
user3344977

2

ฉันประสบความสำเร็จโดยการเขียนโค้ดด้านล่างไม่กี่บรรทัด

extension UIImage {

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

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

        return normalizedImage;
    }
}

0

ถ้าฉันเข้าใจสิ่งที่คุณต้องการจะทำคือไม่สนใจการวางแนวของ UIImage? ถ้าเป็นเช่นนั้นคุณสามารถทำได้: -

//image is your original image
image = [UIImage imageWithCGImage:[image CGImage]
                             scale:[image scale]
                       orientation: UIImageOrientationUp];

หรือใน Swift: -

image = UIImage(CGImage: image.CGImage!, scale: image.scale, orientation:.Up)

มันแก้ไขปัญหาการครอบตัดของฉัน .. หวังว่านี่คือสิ่งที่คุณกำลังมองหา ..


0

Swift 3 version จาก @ jake1981 ที่นำมาจาก @ MetalHeart2003

extension UIImage {

    func fixOrientation() -> UIImage {

        // No-op if the orientation is already correct
        if ( self.imageOrientation == UIImageOrientation.up ) {
            return self;
        }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.

        var transform: CGAffineTransform = CGAffineTransform.identity

        if ( self.imageOrientation == UIImageOrientation.down || self.imageOrientation == UIImageOrientation.downMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: self.size.height)
            transform = transform.rotated(by: CGFloat(M_PI))
        }

        if ( self.imageOrientation == UIImageOrientation.left || self.imageOrientation == UIImageOrientation.leftMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.rotated(by: CGFloat(M_PI_2))
        }

        if ( self.imageOrientation == UIImageOrientation.right || self.imageOrientation == UIImageOrientation.rightMirrored ) {
            transform = transform.translatedBy(x: 0, y: self.size.height);
            transform = transform.rotated(by: CGFloat(-M_PI_2));
        }

        if ( self.imageOrientation == UIImageOrientation.upMirrored || self.imageOrientation == UIImageOrientation.downMirrored ) {
            transform = transform.translatedBy(x: self.size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        }

        if ( self.imageOrientation == UIImageOrientation.leftMirrored || self.imageOrientation == UIImageOrientation.rightMirrored ) {
            transform = transform.translatedBy(x: self.size.height, y: 0);
            transform = transform.scaledBy(x: -1, y: 1);
        }

        // Now we draw the underlying CGImage into a new context, applying the transform
        // calculated above.
        let ctx: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height),
                                       bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0,
                                       space: self.cgImage!.colorSpace!,
                                       bitmapInfo: self.cgImage!.bitmapInfo.rawValue)!
        ctx.concatenate(transform)

        if ( self.imageOrientation == UIImageOrientation.left ||
            self.imageOrientation == UIImageOrientation.leftMirrored ||
            self.imageOrientation == UIImageOrientation.right ||
            self.imageOrientation == UIImageOrientation.rightMirrored ) {

            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: self.size.height, height: self.size.width))
        } else {
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        }

        // And now we just create a new UIImage from the drawing context and return it
        return UIImage(cgImage: ctx.makeImage()!)

    }
}

0
@an0, thanks for the answer!
The only thing is autoreleasepool: 

func fixOrientation(img: UIImage) -> UIImage? {

    let result: UIImage?
    if img.imageOrientation == .up {
        result = img
    } else {

        result = autoreleasepool { () -> UIImage? in
            UIGraphicsBeginImageContextWithOptions(img.size, false, img.scale)
            let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
            img.draw(in: rect)

            let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()

            return normalizedImage
        }
    }

    return result
}

0

นี่คือรหัส Swift-4.2 สำหรับแก้ไขการวางแนวภาพของคุณคืนค่า UIImage โดยอัตโนมัติ

func AutofixImageOrientation(_ image: UIImage)->UIImage {

    UIGraphicsBeginImageContext(image.size)

    image.draw(at: .zero)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return newImage ?? image
}

0

ฉันเปลี่ยนมันเป็น Xamarin:

private static UIImage FixImageOrientation(UIImage image)
    {
        if (image.Orientation == UIImageOrientation.Up)
        {
            return image;
        }

        var transform = CGAffineTransform.MakeIdentity();

        float pi = (float)Math.PI;

        switch (image.Orientation)
        {
            case UIImageOrientation.Down:
            case UIImageOrientation.DownMirrored:
                transform = CGAffineTransform.Translate(transform, image.Size.Width, image.Size.Height);
                transform = CGAffineTransform.Rotate(transform, pi);
                break;

            case UIImageOrientation.Left:
            case UIImageOrientation.LeftMirrored:
                transform = CGAffineTransform.Translate(transform, image.Size.Width, 0);
                transform = CGAffineTransform.Rotate(transform, pi / 2);
                break;

            case UIImageOrientation.Right:
            case UIImageOrientation.RightMirrored:
                transform = CGAffineTransform.Translate(transform, 0, image.Size.Height);
                transform = CGAffineTransform.Rotate(transform, -(pi / 2));
                break;
        }

        switch (image.Orientation)
        {
            case UIImageOrientation.UpMirrored:
            case UIImageOrientation.DownMirrored:
                transform = CGAffineTransform.Translate(transform, image.Size.Width, 0);
                transform = CGAffineTransform.Scale(transform, -1, 1);
                break;

            case UIImageOrientation.LeftMirrored:
            case UIImageOrientation.RightMirrored:
                transform = CGAffineTransform.Translate(transform, image.Size.Height, 0);
                transform = CGAffineTransform.Scale(transform, -1, 1);
                break;
        }

        var ctx = new CGBitmapContext(null, (nint)image.Size.Width, (nint)image.Size.Height, image.CGImage.BitsPerComponent,
            image.CGImage.BytesPerRow, image.CGImage.ColorSpace, image.CGImage.BitmapInfo);

        ctx.ConcatCTM(transform);

        switch (image.Orientation)
        {
            case UIImageOrientation.Left:
            case UIImageOrientation.LeftMirrored:
            case UIImageOrientation.Right:
            case UIImageOrientation.RightMirrored:
                ctx.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), image.CGImage);
                break;

            default:
                ctx.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage);
                break;
        }

        var cgimg = ctx.ToImage();
        var img = new UIImage(cgimg);

        ctx.Dispose();
        ctx = null;
        cgimg.Dispose();
        cgimg = null;

        return img;
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.