วิธีการหมุน UIImage 90 องศา


177

ฉันมีUIImageที่อยู่UIImageOrientationUp(แนวตั้ง) ที่ผมอยากจะหมุนทวนเข็มนาฬิกา 90 องศา (แนวนอน) CGAffineTransformฉันไม่ต้องการที่จะใช้ ฉันต้องการพิกเซลของUIImageเพื่อเปลี่ยนตำแหน่งจริง ฉันใช้บล็อกของรหัส (แสดงด้านล่าง) เดิมทีมีจุดประสงค์เพื่อปรับขนาด a UIImageเพื่อทำสิ่งนี้ ฉันตั้งขนาดเป้าหมายเป็นขนาดปัจจุบันของUIImageแต่ฉันได้รับข้อผิดพลาด:

(ข้อผิดพลาด): CGBitmapContextCreate: ไบต์ข้อมูล / แถวที่ไม่ถูกต้อง: ควรมีอย่างน้อย 1708 สำหรับ 8 บิต / ส่วนประกอบจำนวนเต็ม 8 ส่วนประกอบ 3 องค์ประกอบ kCGImageAlphaPremultipliedLast

(ฉันไม่ได้รับข้อผิดพลาดเมื่อใดก็ตามที่ฉันให้ขนาดที่เล็กลงเป็นขนาดเป้าหมาย BTW) ฉันจะหมุนUIImageCCW 90 องศาของฉันโดยใช้ฟังก์ชั่นกราฟิกหลักได้อย่างไรขณะที่รักษาขนาดปัจจุบันไว้

-(UIImage*)reverseImageByScalingToSize:(CGSize)targetSize:(UIImage*)anImage
{
    UIImage* sourceImage = anImage; 
    CGFloat targetWidth = targetSize.height;
    CGFloat targetHeight = targetSize.width;

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {


        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }       


    if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

ฉันพบลิงค์ที่มีประโยชน์อื่น ๆ .. หวังว่านี่จะช่วยได้บ้าง .. mobiledevelopertips.com/user-interface/
Dilip Rajkumar

วิธีการแก้ปัญหา .......... stackoverflow.com/questions/5427656/…
Fattie

ปัญหาของฉันคือภาพถ่ายที่อัปโหลดไปยัง Amazon S3 ถูกหมุน วิธีการแก้ปัญหานี้แก้ไขปัญหาในการมองเห็นและอัปโหลด
chrisallick

stackoverflow.com/questions/30701578/… เฮ้ nilam เห็นสิ่งนี้หลังจากที่ได้เห็นฉันจะลบ
hrishikesh Deshpande

คำตอบ:


89

เกี่ยวกับสิ่งที่ชอบ:

static inline double radians (double degrees) {return degrees * M_PI/180;}
UIImage* rotate(UIImage* src, UIImageOrientation orientation)
{
    UIGraphicsBeginImageContext(src.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orientation == UIImageOrientationRight) {
        CGContextRotateCTM (context, radians(90));
    } else if (orientation == UIImageOrientationLeft) {
        CGContextRotateCTM (context, radians(-90));
    } else if (orientation == UIImageOrientationDown) {
        // NOTHING
    } else if (orientation == UIImageOrientationUp) {
        CGContextRotateCTM (context, radians(90));
    }

    [src drawAtPoint:CGPointMake(0, 0)];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

1
ความคิดเห็นของฉันคือ drawAtPoint อาจต้องเรียกหลังจากเรียกเพื่อตั้งค่า RotateCTM ที่เหมาะสม ลองย้าย drawAtPoint ไปก่อน UIGraphicsGetImageFromCurrentImageContext
fbrereto

4
สิ่งนี้จะไม่ทำงานบนเธรดพื้นหลัง UIGraphicsGetCurrentContext () ไม่ปลอดภัยสำหรับเธรดและควรถูกเรียกบนเธรดหลัก (UI) เท่านั้น
Chris R. Donnelly

1
การเรียก CGContextRotateCTM ครั้งสุดท้ายนั้นอาจจะหมุนได้ 180 ไม่ใช่ 90 จริง ๆ แล้ว… Down น่าจะหมุนได้ 180 และ… Up ไม่น่าจะหมุน
Ivan Vučica

5
ใน iOS 4 และใหม่กว่าคุณอาจเรียกใช้ฟังก์ชัน UIGraphicsGetCurrentContext จากชุดข้อความใด ๆ ของแอปของคุณ
bentford

3
ต้อง CGContextTranslateCTM (ctx, width / 2, height / 2) ก่อนและย้อนกลับหลัง
Glenn Maynard

411

ฉันเชื่อว่าวิธีที่ง่ายที่สุด (และด้ายปลอดภัยเกินไป) จะทำ:

//assume that the image is loaded in landscape mode from disk
UIImage * landscapeImage = [UIImage imageNamed:imgname];
UIImage * portraitImage = [[UIImage alloc] initWithCGImage: landscapeImage.CGImage
                                                     scale: 1.0
                                               orientation: UIImageOrientationRight];

หมายเหตุ: ดังที่Brainwareกล่าวว่าสิ่งนี้จะแก้ไขข้อมูลการวางแนวของภาพเท่านั้น - ข้อมูลพิกเซลไม่ถูกแตะต้อง สำหรับแอปพลิเคชั่นบางตัวอาจไม่เพียงพอ

หรือในสวิฟท์:

guard
    let landscapeImage = UIImage(named: "imgname"),
    let landscapeCGImage = landscapeImage.cgImage
else { return }
let portraitImage = UIImage(cgImage: landscapeCGImage, scale: landscapeImage.scale, orientation: .right)

1
ทำให้เป็นเรื่องทั่วไปมากขึ้น: UIImage * origImg = [UIImage imageNamed: @ "1.JPG"]; UIImage * fixed = [UIImage imageWithCGImage: [origImg CGImage] มาตราส่วน: 1.0 การวางแนว: origImg.imageOrientation];
Cullen SUN

13
นี่ไม่ได้หมุนภาพจริงๆ มันทำสำเนาของภาพและตั้งค่า imageOrientation บิตของคุณสมบัติ imageFlags ของรูปภาพเป็น 0, 1, 2 หรือ 3 บางคลาสจะละเว้นแฟล็กเหล่านี้เช่น UIActivityViewController หากคุณต้องการหมุนภาพจริงๆให้ดูคำตอบของ Ben Groot ซึ่งส่วนขยาย UIImage ของ Hardy Macia
Brainware

การปรับสเกลเป็น 1.0 จะไม่ทำงานหากแอปของคุณใช้ทั้งบนหน้าจอเรตินาและหน้าจอที่ไม่ใช่เรตินาคุณจะต้องใช้ originalImage.scale และส่งผ่านเป็นส่วนประกอบของสเกล
teradyl

2
ดูเหมือนว่าจะหยุดทำงานใน iOS10 เท่าที่ฉันสามารถบอกได้
Nailer

let img = UIImage(cgImage: myImage!.cgImage!, scale: UIScreen.main.scale, orientation: .right)
Alexandre G

110

ลองดูโค้ด Hardy Macia ที่เรียบง่ายและยอดเยี่ยมได้ที่: การตัดการปรับและการหมุนภาพเคลื่อนไหว

เพียงแค่โทร

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];

ขอบคุณ Hardy Macia!

หัวข้อ:

  • (UIImage *) imageAtRect: (CGRect) rect;
  • (UIImage *) imageByScalingProportionallyToMinimumSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingProportionallyToSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingToSize: (CGSize) targetSize;
  • (UIImage *) imageRotatedByRadians: (CGFloat) เรเดียน;
  • (UIImage *) imageRotatedByDegrees: (CGFloat) องศา;

เนื่องจากลิงก์อาจตายนี่คือรหัสที่สมบูรณ์

//
//  UIImage-Extensions.h
//
//  Created by Hardy Macia on 7/1/09.
//  Copyright 2009 Catamount Software. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIImage (CS_Extensions)
- (UIImage *)imageAtRect:(CGRect)rect;
- (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize;
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
- (UIImage *)imageByScalingToSize:(CGSize)targetSize;
- (UIImage *)imageRotatedByRadians:(CGFloat)radians;
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;

@end;

//
//  UIImage-Extensions.m
//
//  Created by Hardy Macia on 7/1/09.
//  Copyright 2009 Catamount Software. All rights reserved.
//

#import "UIImage-Extensions.h"

CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;};

@implementation UIImage (CS_Extensions)

-(UIImage *)imageAtRect:(CGRect)rect
{

   CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect);
   UIImage* subImage = [UIImage imageWithCGImage: imageRef];
   CGImageRelease(imageRef);

   return subImage;

}

- (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize {

   UIImage *sourceImage = self;
   UIImage *newImage = nil;

   CGSize imageSize = sourceImage.size;
   CGFloat width = imageSize.width;
   CGFloat height = imageSize.height;

   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;

   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;

   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

   if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

      CGFloat widthFactor = targetWidth / width;
      CGFloat heightFactor = targetHeight / height;

      if (widthFactor > heightFactor) 
         scaleFactor = widthFactor;
      else
         scaleFactor = heightFactor;

      scaledWidth  = width * scaleFactor;
      scaledHeight = height * scaleFactor;

      // center the image

      if (widthFactor > heightFactor) {
         thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
      } else if (widthFactor < heightFactor) {
         thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
      }
   }


   // this is actually the interesting part:

   UIGraphicsBeginImageContext(targetSize);

   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;

   [sourceImage drawInRect:thumbnailRect];

   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   if(newImage == nil) NSLog(@"could not scale image");


   return newImage ;
}


- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {

   UIImage *sourceImage = self;
   UIImage *newImage = nil;

   CGSize imageSize = sourceImage.size;
   CGFloat width = imageSize.width;
   CGFloat height = imageSize.height;

   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;

   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;

   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

   if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

      CGFloat widthFactor = targetWidth / width;
      CGFloat heightFactor = targetHeight / height;

      if (widthFactor < heightFactor) 
         scaleFactor = widthFactor;
      else
         scaleFactor = heightFactor;

      scaledWidth  = width * scaleFactor;
      scaledHeight = height * scaleFactor;

      // center the image

      if (widthFactor < heightFactor) {
         thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
      } else if (widthFactor > heightFactor) {
         thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
      }
   }


   // this is actually the interesting part:

   UIGraphicsBeginImageContext(targetSize);

   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;

   [sourceImage drawInRect:thumbnailRect];

   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   if(newImage == nil) NSLog(@"could not scale image");


   return newImage ;
}


- (UIImage *)imageByScalingToSize:(CGSize)targetSize {

   UIImage *sourceImage = self;
   UIImage *newImage = nil;

   //   CGSize imageSize = sourceImage.size;
   //   CGFloat width = imageSize.width;
   //   CGFloat height = imageSize.height;

   CGFloat targetWidth = targetSize.width;
   CGFloat targetHeight = targetSize.height;

   //   CGFloat scaleFactor = 0.0;
   CGFloat scaledWidth = targetWidth;
   CGFloat scaledHeight = targetHeight;

   CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

   // this is actually the interesting part:

   UIGraphicsBeginImageContext(targetSize);

   CGRect thumbnailRect = CGRectZero;
   thumbnailRect.origin = thumbnailPoint;
   thumbnailRect.size.width  = scaledWidth;
   thumbnailRect.size.height = scaledHeight;

   [sourceImage drawInRect:thumbnailRect];

   newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   if(newImage == nil) NSLog(@"could not scale image");


   return newImage ;
}


- (UIImage *)imageRotatedByRadians:(CGFloat)radians
{
   return [self imageRotatedByDegrees:RadiansToDegrees(radians)];
}

- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees 
{   
   // calculate the size of the rotated view's containing box for our drawing space
   UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
   CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
   rotatedViewBox.transform = t;
   CGSize rotatedSize = rotatedViewBox.frame.size;
   [rotatedViewBox release];

   // Create the bitmap context
   UIGraphicsBeginImageContext(rotatedSize);
   CGContextRef bitmap = UIGraphicsGetCurrentContext();

   // Move the origin to the middle of the image so we will rotate and scale around the center.
   CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

   //   // Rotate the image context
   CGContextRotateCTM(bitmap, DegreesToRadians(degrees));

   // Now, draw the rotated/scaled image into the context
   CGContextScaleCTM(bitmap, 1.0, -1.0);
   CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);

   UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   return newImage;

}

@end;

... ลิงค์เสียชีวิต +1 สำหรับการรวมรหัสที่สมบูรณ์
Greg

31

อย่างที่แปลกอย่างนี้รหัสต่อไปนี้แก้ไขปัญหาให้ฉัน:

+ (UIImage*)unrotateImage:(UIImage*)image {
    CGSize size = image.size;
    UIGraphicsBeginImageContext(size);
    [image drawInRect:CGRectMake(0,0,size.width ,size.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

8
มันทำงานได้เพราะการวางแนวภาพไม่ได้รับการรักษาไว้เมื่อคุณวาดเป็นรูปสี่เหลี่ยมผืนผ้า
Mercurial

ใช่นี่จะเป็นประโยชน์ในการลบการวางแนวจากรูปภาพ
Shihab

ชื่อฟังก์ชั่นควรได้รับ removeOrientationProperty
Shihab

29

ฟังก์ชันการหมุนที่ปลอดภัยของเธรดมีดังต่อไปนี้ (ใช้งานได้ดีกว่ามาก):

-(UIImage*)imageByRotatingImage:(UIImage*)initImage fromImageOrientation:(UIImageOrientation)orientation
{
CGImageRef imgRef = initImage.CGImage;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);

CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = orientation;
switch(orient) {

    case UIImageOrientationUp: //EXIF = 1
        return initImage;
        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"];

}
// Create the bitmap context
CGContextRef    context = NULL;
void *          bitmapData;
int             bitmapByteCount;
int             bitmapBytesPerRow;

// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow   = (bounds.size.width * 4);
bitmapByteCount     = (bitmapBytesPerRow * bounds.size.height);
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
    return nil;
}

// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
CGColorSpaceRef colorspace = CGImageGetColorSpace(imgRef);
context = CGBitmapContextCreate (bitmapData,bounds.size.width,bounds.size.height,8,bitmapBytesPerRow,
                                 colorspace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);

if (context == NULL)
    // error creating context
    return nil;

CGContextScaleCTM(context, -1.0, -1.0);
CGContextTranslateCTM(context, -bounds.size.width, -bounds.size.height);

CGContextConcatCTM(context, transform);

// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, CGRectMake(0,0,width, height), imgRef);

CGImageRef imgRef2 = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(bitmapData);
UIImage * image = [UIImage imageWithCGImage:imgRef2 scale:initImage.scale orientation:UIImageOrientationUp];
CGImageRelease(imgRef2);
return image;
}

มีปัญหาเกี่ยวกับรหัสของคุณคือ ... มันจะเพิ่มกรอบสีขาวแปลกรอบ ๆ UIImageOrientationDownภาพใน
iosfreak

1
คุณไม่ต้องการให้มีการเรียก CGColorSpaceRelease (colorspace) ดูstackoverflow.com/questions/5269815/ …
Seth Spitzer

ใช่ขอโทษเกี่ยวกับการเปิดตัว
thewormsterror

18

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

- (UIImage *)imageRotatedByDegrees:(UIImage*)oldImage deg:(CGFloat)degrees{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,oldImage.size.width, oldImage.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(degrees * M_PI / 180);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();

// Move the origin to the middle of the image so we will rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

//   // Rotate the image context
CGContextRotateCTM(bitmap, (degrees * M_PI / 180));

// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-oldImage.size.width / 2, -oldImage.size.height / 2, oldImage.size.width, oldImage.size.height), [oldImage CGImage]);

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

และการใช้งาน:

UIImage *image2 = [self imageRotatedByDegrees:image deg:90];

ขอบคุณ Hardy!


16

หมุนรูปภาพ 90 องศา (ทิศทางตามเข็มนาฬิกา / ทวนเข็มนาฬิกา)

ฟังก์ชั่นการโทร -

 UIImage *rotatedImage = [self rotateImage:originalImage clockwise:YES];

การดำเนินงาน:

- (UIImage*)rotateImage:(UIImage*)sourceImage clockwise:(BOOL)clockwise
  {
    CGSize size = sourceImage.size;
    UIGraphicsBeginImageContext(CGSizeMake(size.height, size.width));
    [[UIImage imageWithCGImage:[sourceImage CGImage]
                         scale:1.0
                   orientation:clockwise ? UIImageOrientationRight : UIImageOrientationLeft]
                   drawInRect:CGRectMake(0,0,size.height ,size.width)];

   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
  }

สิ่งนี้จะเพิ่มขนาดของภาพ
Shashikant ขึ้น

5

หากคุณต้องการเพิ่มปุ่มหมุนรูปถ่ายที่จะทำให้การหมุนรูปถ่ายเพิ่มขึ้นทีละ 90 องศาคุณไปได้เลย ( finalImageเป็น UIImage ที่ถูกสร้างขึ้นที่อื่นแล้ว)

- (void)rotatePhoto {
    UIImage *rotatedImage;

    if (finalImage.imageOrientation == UIImageOrientationRight)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationDown];
    else if (finalImage.imageOrientation == UIImageOrientationDown)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationLeft];
    else if (finalImage.imageOrientation == UIImageOrientationLeft)
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                              scale: 1.0
                                        orientation: UIImageOrientationUp];
    else
        rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage
                                                     scale: 1.0
                                               orientation: UIImageOrientationRight];
    finalImage = rotatedImage;
}

5

ง่าย เพียงแค่เปลี่ยนการตั้งค่าตำแหน่งของภาพ

UIImage *oldImage = [UIImage imageNamed:@"whatever.jpg"];
UIImageOrientation newOrientation;
switch (oldImage.imageOrientation) {
    case UIImageOrientationUp:
        newOrientation = UIImageOrientationLandscapeLeft;
        break;
    case UIImageOrientationLandscapeLeft:
        newOrientation = UIImageOrientationDown;
        break;
    case UIImageOrientationDown:
        newOrientation = UIImageOrientationLandscapeRight;
        break;
    case UIImageOrientationLandscapeRight:
        newOrientation = UIImageOrientationUp;
        break;
    // you can also handle mirrored orientations similarly ...
}
UIImage *rotatedImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1.0f orientation:newOrientation];

5

นี่คือส่วนขยาย Swift ถึง UIImage ที่หมุนภาพในมุมใดก็ได้ ใช้มันแบบนี้: let rotatedImage = image.rotated(byDegrees: degree). ฉันใช้รหัส Objective-C ในหนึ่งในคำตอบอื่น ๆ และลบไม่กี่บรรทัดที่เราไม่ถูกต้อง (สิ่งกล่องหมุน) และกลายเป็นส่วนขยายสำหรับ UIImage

extension UIImage {

func rotate(byDegrees degree: Double) -> UIImage {
    let radians = CGFloat(degree*M_PI)/180.0 as CGFloat
    let rotatedSize = self.size
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
    let bitmap = UIGraphicsGetCurrentContext()
    CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);
    CGContextRotateCTM(bitmap, radians);
    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2 , self.size.width, self.size.height), self.CGImage );
    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    return newImage
}
}

ใช้งานได้ดี! ฉันเปลี่ยนมันเล็กน้อยเพื่อที่ฉันจะได้สลับความกว้างและสูง: func หมุน (องศาองศา: สอง, toSize: CGSize? = ไม่มี) -> UIImage {let rotatedSize = toSize ?? self.size
Edwin Vermeer

1
สิ่งนี้ไม่ได้กำหนดขอบเขตของภาพอย่างเหมาะสม คุณจบลงด้วยภาพที่หมุนได้ซึ่งจะไหลล้นขอบเขตดั้งเดิม
Devin B

ขอบคุณมากสำหรับสิ่งนี้ น่าทึ่งว่าวันนี้ฉันใช้เวลากับมันมากแค่ไหน
ChrisH

5

ส่วนขยาย Swift 3 UIImage:

func fixOrientation() -> UIImage {

    // No-op if the orientation is already correct
    if ( self.imageOrientation == .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 = .identity

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

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

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

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

    if ( self.imageOrientation == .leftMirrored || self.imageOrientation == .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 == .left ||
        self.imageOrientation == .leftMirrored ||
        self.imageOrientation == .right ||
        self.imageOrientation == .rightMirrored ) {
        ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: self.size.height,height: self.size.width))
    } else {
        ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.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()!)
}

3

คำตอบของ RawMeanเวอร์ชัน Swift 4.2 :

extension UIImage {

func rotated(byDegrees degree: Double) -> UIImage {
    let radians = CGFloat(degree * .pi) / 180.0 as CGFloat
    let rotatedSize = self.size
    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
    let bitmap = UIGraphicsGetCurrentContext()
    bitmap?.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
    bitmap?.rotate(by: radians)
    bitmap?.scaleBy(x: 1.0, y: -1.0)
    bitmap?.draw(
        self.cgImage!,
        in: CGRect.init(x: -self.size.width / 2, y: -self.size.height / 2 , width: self.size.width, height: self.size.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext() // this is needed
    return newImage!
}

}

ลูกโป่งน้ำหนักของภาพ ฉันทดสอบของฉัน: ก่อนที่จะหมุน ============================== กว้าง 3024.0 สูง 3024.0 ขนาด 4952213 ไบต์ ======= ======================= หลังจากการหมุน ========================= ===== ความกว้าง 3024.0 ความสูง 3024.0 ขนาด 35191195 ไบต์ ==============================
barrylachapelle

2

ฉันลองใช้รหัสนี้ใช้งานได้และนำมาจาก http://www.catamount.com/blog/1015/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/

+ (UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian
{
    // calculate the size of the rotated view's containing box for our drawing space
    UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, src.size.width, src.size.height)];
    CGAffineTransform t = CGAffineTransformMakeRotation(radian);
    rotatedViewBox.transform = t;
    CGSize rotatedSize = rotatedViewBox.frame.size;

    // Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    // Move the origin to the middle of the image so we will rotate and scale around the center.
    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

    //   // Rotate the image context
    CGContextRotateCTM(bitmap, radian);

    // Now, draw the rotated/scaled image into the context
    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

2

การเปลี่ยนแปลงเล็กน้อยในคำตอบอื่น ๆ ที่เป็นไปตามรหัสของ Hardy Macia ไม่จำเป็นต้องสร้างUIViewวัตถุทั้งหมดเพื่อคำนวณสี่เหลี่ยมผืนผ้าที่มีขอบเขตของภาพที่หมุน CGRectApplyAffineTransformเพียงแค่ใช้การหมุนเปลี่ยนไปสี่เหลี่ยมผืนผ้าภาพโดยใช้

static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
static CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;}


- (CGSize)rotatedImageSize:(CGFloat)degrees
{
    CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
    CGRect originalImageRect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGRect rotatedImageRect = CGRectApplyAffineTransform(originalImageRect, t);
    CGSize rotatedSize = rotatedImageRect.size;

    return rotatedSize;
}

- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
    // calculate the size of the rotated view's containing box for our drawing space
    CGSize rotatedSize = [self rotatedImageSize:degrees];

    // Create the bitmap context
    UIGraphicsBeginImageContext(rotatedSize);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    // Move the origin to the middle of the image so we will rotate and scale around the center.
    CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);

    //   // Rotate the image context
    CGContextRotateCTM(bitmap, DegreesToRadians(degrees));

    // Now, draw the rotated/scaled image into the context
    CGContextScaleCTM(bitmap, 1.0, -1.0);
    CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

0

0

ฉันชอบความเรียบง่ายสง่างามของPeter Sarnowskiคำตอบ แต่อาจทำให้เกิดปัญหาเมื่อคุณไม่สามารถพึ่งพาEXIFเมทาดาทาและสิ่งที่ชอบ ในสถานการณ์ที่คุณต้องหมุนข้อมูลภาพจริงฉันขอแนะนำดังนี้:

- (UIImage *)rotateImage:(UIImage *) img
{
    CGSize imgSize = [img size];
    UIGraphicsBeginImageContext(imgSize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextRotateCTM(context, M_PI_2);
    CGContextTranslateCTM(context, 0, -640);
    [img drawInRect:CGRectMake(0, 0, imgSize.height, imgSize.width)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

รหัสดังกล่าวจะใช้เวลาภาพที่มีการวางแนวทางคือLandscape(จำไม่ได้ถ้ามันLandscape LeftหรือLandscape Right) Portraitและหมุนมันเข้าไป มันเป็นตัวอย่างที่สามารถปรับเปลี่ยนได้ตามความต้องการของคุณ

ข้อโต้แย้งสำคัญที่คุณจะต้องเล่นกับเป็นCGContextRotateCTM(context, M_PI_2)ที่ที่คุณตัดสินใจว่าคุณต้องการที่จะหมุนด้วย CGContextTranslateCTM(context, 0, -640)แต่แล้วคุณต้องให้แน่ใจว่าภาพยังคงวาดบนหน้าจอโดยใช้ ส่วนสุดท้ายนี้ค่อนข้างสำคัญเพื่อให้แน่ใจว่าคุณเห็นภาพและไม่ใช่หน้าจอที่ว่างเปล่า

สำหรับข้อมูลเพิ่มเติมตรวจสอบแหล่งที่มา


2
Downvote สำหรับลิงก์ที่เสียและไม่มีคำอธิบายของ -640 magic number จะกลับถ้าแก้ไข
เนท

0

resize-a-uiimage-the-wayอธิบายถึงปัญหาบางอย่างของตัวอย่างโค้ดจำนวนมากสำหรับการทำเช่นนี้และมีโค้ดบางส่วนเพื่อช่วยจัดการกับ UIImages - วิธีการช่วยเหลือส่วนตัวใน UIImage + resize.m ยอมรับการแปลงเพื่ออนุญาต การหมุนดังนั้นคุณต้องแสดงให้เห็นว่าเป็นส่วนต่อประสานสาธารณะ

// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
// If the new size is not integral, it will be rounded up
- (UIImage *)resizedImage:(CGSize)newSize
                transform:(CGAffineTransform)transform
           drawTransposed:(BOOL)transpose
     interpolationQuality:(CGInterpolationQuality)quality {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
    CGImageRef imageRef = self.CGImage;

    // Build a context that's the same dimensions as the new size
    CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                                newRect.size.width,
                                                newRect.size.height,
                                                CGImageGetBitsPerComponent(imageRef),
                                                0,
                                                CGImageGetColorSpace(imageRef),
                                                CGImageGetBitmapInfo(imageRef));

    // Rotate and/or flip the image if required by its orientation
    CGContextConcatCTM(bitmap, transform);

    // Set the quality level to use when rescaling
    CGContextSetInterpolationQuality(bitmap, quality);

    // Draw into the context; this scales the image
    CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);

    // Get the resized image from the context and a UIImage
    CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    // Clean up
    CGContextRelease(bitmap);
    CGImageRelease(newImageRef);

    return newImage;
}

นี่คือใบอนุญาตจากไฟล์นั้น:

// Created by Trevor Harmon on 8/5/09.
// Free for personal or commercial use, with or without modification.
// No warranty is expressed or implied.

0

มีหมวดหมู่ UIImage ที่มีประสิทธิภาพมากที่ชื่อว่า NYXImagesKit มันใช้ vDSP, CoreImage และ vImage ให้เร็วที่สุด มันมีหมวดหมู่ UIImage + การหมุนที่บันทึกวันของฉัน :)

https://github.com/Nyx0uf/NYXImagesKit


0

สำหรับ Swift: นี่คือส่วนขยายที่เรียบง่ายสำหรับ UIImage:

//ImageRotation.swift

import UIKit

extension UIImage {  
    public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage {
        let radiansToDegrees: (CGFloat) -> CGFloat = {
            return $0 * (180.0 / CGFloat(M_PI))
        }
        let degreesToRadians: (CGFloat) -> CGFloat = {
            return $0 / 180.0 * CGFloat(M_PI)
        }

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size))
        let t = CGAffineTransformMakeRotation(degreesToRadians(degrees));
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let bitmap = UIGraphicsGetCurrentContext()

        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0, rotatedSize.height / 2.0);

        //   // Rotate the image context
        CGContextRotateCTM(bitmap, degreesToRadians(degrees));

        // Now, draw the rotated/scaled image into the context
        var yFlip: CGFloat

        if(flip){
            yFlip = CGFloat(-1.0)
        } else {
            yFlip = CGFloat(1.0)
        }

        CGContextScaleCTM(bitmap, yFlip, -1.0)
        CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }
}

( ที่มา )

ใช้กับ:

rotatedPhoto = rotatedPhoto?.imageRotatedByDegrees(90, flip: false) 

อดีตจะหมุนรูปภาพและพลิกหากตั้งค่าการพลิกเป็นจริง


คุณช่วยอธิบายหน่อยได้ไหม?
G.Abhisek

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