Làm thế nào để xoay một UIImage 90 độ?


177

Tôi có một UIImagecái là UIImageOrientationUp(chân dung) mà tôi muốn xoay ngược chiều kim đồng hồ 90 độ (theo chiều ngang). Tôi không muốn sử dụng a CGAffineTransform. Tôi muốn các pixel của UIImagevị trí thực sự thay đổi. Tôi đang sử dụng một khối mã (hiển thị bên dưới) ban đầu dự định thay đổi kích thước UIImageđể làm điều này. Tôi đặt kích thước mục tiêu là kích thước hiện tại của UIImagenhưng tôi gặp lỗi:

(Lỗi): CGBitmapContextCreate: byte / hàng dữ liệu không hợp lệ: tối thiểu phải là 1708 cho 8 bit / thành phần, 3 thành phần, kCGImageAlphaPremultipliedLast.

(Tôi không gặp lỗi bất cứ khi nào tôi cung cấp kích thước NHỎ làm kích thước mục tiêu BTW). Làm cách nào tôi có thể QUAY LẠI UIImage90 độ CCW của mình bằng cách chỉ sử dụng các chức năng đồ họa cốt lõi trong khi duy trì kích thước hiện tại?

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

Tôi tìm thấy một liên kết hữu ích khác .. Hy vọng điều này sẽ giúp được ai đó .. mobiledevelopertips.com/user-interface/,
Dilip Rajkumar


Vấn đề của tôi là ảnh được tải lên Amazon S3 đã được xoay. Giải pháp này đã giải quyết vấn đề trực quan và tải lên.
chrisallick

stackoverflow.com/questions/30701578/ từ hey nilam thấy điều này sau khi thấy tôi sẽ xóa
hrishikesh Deshpande

Câu trả lời:


89

Điều gì về một cái gì đó như:

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
Nhận xét của tôi là drawAtPoint có thể phải được gọi sau cuộc gọi để đặt RotateCTM thích hợp. Hãy thử di chuyển drawAtPoint đến ngay trước UIGraphicsGetImageFromCienImageContext
fbrereto

4
Điều này sẽ không làm việc trên một chủ đề nền. UIGraphicsGetCienContext () không an toàn cho luồng và chỉ nên được gọi trên luồng chính (UI).
Chris R. Donnelly

1
Cuộc gọi cuối cùng tới CGContextRotateCTM () có lẽ nên xoay 180, chứ không phải 90. Trên thực tế, có lẽ nên quay xuống 180, và có thể không nên xoay.
Ivan Vučica

5
Trong iOS 4 trở lên, bạn có thể gọi hàm UIGraphicsGetCienContext từ bất kỳ chuỗi nào trong ứng dụng của bạn.
bentford

3
Cần CGContextTranslateCTM (ctx, width / 2, height / 2) trước và đảo ngược sau.
Glenn Maynard

411

Tôi tin rằng cách dễ nhất (và chủ đề an toàn quá) là làm:

//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];

Lưu ý: Như Brainware cho biết điều này chỉ sửa đổi dữ liệu định hướng của hình ảnh - dữ liệu pixel không bị ảnh hưởng. Đối với một số ứng dụng, điều này có thể không đủ.

Hoặc trong Swift:

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

1
Làm cho nó tổng quát hơn: UIImage * origImg = [UIImage image Named: @ "1.JPG"]; UIImage * fixed = [UIImage imageWithCGImage: [origImg CGImage] scale: 1.0 direction: origImg.imageOrientation];
Cullen CN

13
Điều này không thực sự xoay hình ảnh. Nó tạo một bản sao của hình ảnh và đặt các bit imageOrientation của thuộc tính imageFlags của hình ảnh thành 0, 1, 2 hoặc 3. Một số lớp bỏ qua các cờ này như UIActivityViewControll. Nếu bạn thực sự cần hình ảnh được xoay, hãy xem câu trả lời của Ben Groot, phần mở rộng UIImage của Hardy Macia.
Brainware

Đặt tỷ lệ là 1.0 sẽ không hoạt động nếu ứng dụng của bạn được sử dụng trên cả màn hình võng mạc và không võng mạc, bạn phải lấy bản gốcImage.scale và chuyển nó làm thành phần tỷ lệ.
teradyl

2
Có vẻ như đã ngừng hoạt động trong iOS10 như tôi có thể nói.
Thợ làm móng

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

110

Kiểm tra mã đơn giản và tuyệt vời của Hardy Macia tại: cắt xén-và-xoay-uiimages

Chỉ cần gọi

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];

Cảm ơn Hardy Macia!

Tiêu đề:

  • (UIImage *) imageAtRect: (CGRect) trực tràng;
  • (UIImage *) imageByScalingProportionallyToMinimumSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingProportionallyToSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingToSize: (CGSize) targetSize;
  • (UIImage *) imageRotatedByRadians: (CGFloat) radian;
  • (UIImage *) imageRotatedByDegrees: (CGFloat) độ;

Vì liên kết có thể chết, đây là mã hoàn chỉnh

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

... liên kết đã chết. +1 để bao gồm mã hoàn chỉnh
Greg

31

Điều kỳ lạ là dường như, đoạn mã sau đã giải quyết vấn đề cho tôi:

+ (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
Nó hoạt động vì hướng hình ảnh không được bảo tồn một khi bạn vẽ trong chỉnh lưu.
Mercurial

Có, điều này sẽ hữu ích xóa hướng khỏi hình ảnh
Shihab

Tên hàm nên đã bị xóaOrientationProperty
Shihab

29

Một chức năng xoay vòng an toàn của luồng là như sau (nó hoạt động tốt hơn nhiều):

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

Có vấn đề với mã của bạn ... Nó thêm một khung màu trắng kỳ lạ xung quanh hình ảnh trên UIImageOrientationDown.
iosfreak

1
Bạn không muốn cuộc gọi đó đến CGColorSpaceRelease (không gian màu), xem stackoverflow.com/questions/5269815/iêu
Seth Spitzer

Vâng xin lỗi về bản phát hành đó
thewormsterror

18

Tôi đã gặp rắc rối với ll ở trên, bao gồm cả câu trả lời được phê duyệt. Tôi đã chuyển đổi danh mục của Hardy thành một phương thức vì tất cả những gì tôi muốn là xoay một hình ảnh. Đây là mã và cách sử dụng:

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

Và cách sử dụng:

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

Cảm ơn Hardy!


16

Xoay hình ảnh 90 độ (chiều kim đồng hồ / hướng ngược chiều kim đồng hồ)

Chức năng gọi -

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

Thực hiện:

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

điều này làm tăng kích thước hình ảnh
Shashikant

5

Nếu bạn muốn thêm nút xoay ảnh sẽ tiếp tục xoay ảnh theo gia số 90 độ, bạn hãy vào đây. ( finalImagelà một UIImage đã được tạo ở nơi khác.)

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

Đơn giản. Chỉ cần thay đổi cờ định hướng hình ảnh.

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

Dưới đây là phần mở rộng Swift cho UIImage giúp xoay hình ảnh theo bất kỳ góc độ tùy ý nào. Sử dụng nó như thế này : let rotatedImage = image.rotated(byDegrees: degree). Tôi đã sử dụng mã Objective-C trong một trong những câu trả lời khác và xóa một vài dòng mà chúng tôi không chính xác (công cụ hộp xoay) và biến nó thành một phần mở rộng cho 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
}
}

Hoạt động tuyệt vời! Tôi đã thay đổi nó một chút để tôi có thể trao đổi chiều rộng và chiều cao: xoay func (byDegrees độ: Double, toSize: CGSize? = Nil) -> UIImage {let rotatedSize = toSize ?? self.size
Edwin Vermeer

1
Điều này không đặt giới hạn hình ảnh đúng. Bạn kết thúc với một hình ảnh xoay được tràn ra các giới hạn ban đầu.
Devin B

Cảm ơn rất nhiều vì điều này. Thật ngạc nhiên khi tôi dành bao nhiêu thời gian cho việc này hôm nay.
ChrisH

5

Phần mở rộng 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

Phiên bản Swift 4.2 của câu trả lời của RawMean :

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

}

Những quả bóng có trọng lượng của một hình ảnh. Im thử nghiệm của tôi: TRƯỚC KHI QUAY LẠI ============================== chiều rộng 3024.0 chiều cao 3024.0 kích thước 4952213 byte ======= ======================= SAU KHI QUAY LẠI ========================= ===== chiều rộng 3024.0 chiều cao 3024.0 kích thước 35191195 byte ==============================
barrylachapelle

2

Tôi thử mã này, nó hoạt động và lấy từ http://www.catamount.com/blog/1015/uiimage-extensions-for-cuting-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

Thay đổi nhỏ đối với các câu trả lời khác dựa trên mã của Hardy Macia. Không cần phải tạo toàn bộ một UIViewđối tượng chỉ đơn giản là tính toán hình chữ nhật giới hạn của hình ảnh được xoay. Chỉ cần áp dụng một biến đổi xoay cho hình chữ nhật hình ảnh bằng cách sử dụng 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

Tôi thích sự thanh lịch đơn giản của Peter Sarnowskicâu trả lời, nhưng nó có thể gây ra vấn đề khi bạn không thể dựa vào EXIFsiêu dữ liệu và những thứ tương tự. Trong trường hợp bạn cần xoay dữ liệu hình ảnh thực tế, tôi sẽ đề xuất một cái gì đó như thế này:

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

Đoạn mã trên lấy một hình ảnh có hướng Landscape(không thể nhớ nếu nó Landscape Lefthoặc Landscape Right) và xoay nó vào Portrait. Đây là một ví dụ có thể được sửa đổi cho nhu cầu của bạn.

Các đối số chính bạn sẽ phải chơi là CGContextRotateCTM(context, M_PI_2)nơi bạn quyết định mức độ bạn muốn xoay, nhưng sau đó bạn phải đảm bảo hình ảnh vẫn được vẽ trên màn hình bằng cách sử dụng CGContextTranslateCTM(context, 0, -640). Phần cuối cùng này khá quan trọng để đảm bảo bạn nhìn thấy hình ảnh chứ không phải màn hình trống.

Để biết thêm thông tin kiểm tra nguồn .


2
Downvote cho liên kết bị hỏng và không có lời giải thích về số ma thuật -640. Sẽ đảo ngược nếu cố định.
Nate

0

resize-a-uiimage-the-right-way giải thích một số vấn đề mà nhiều mẫu mã để thực hiện điều này và có một số đoạn mã để giúp đối phó với UIImage - phương thức trợ giúp riêng trong UIImage + resize.m chấp nhận chuyển đổi để cho phép xoay vòng, vì vậy bạn chỉ cần hiển thị đó là giao diện công cộng.

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

Đây là giấy phép từ tập tin đó:

// 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

Có một thể loại UIImage cực kỳ hiệu quả có tên NYXImagesKit. Nó sử dụng vDSP, CoreImage và vImage để nhanh nhất có thể. Nó có một thể loại UIImage + Xoay lưu lại ngày của tôi :)

https://github.com/Nyx0uf/NYXImagesKit


0

Đối với Swift: Đây là một phần mở rộng đơn giản cho 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
    }
}

( Nguồn )

Sử dụng nó với:

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

Cái trước sẽ xoay một hình ảnh và lật nó nếu lật được đặt thành đúng.


Bạn có thể vui lòng giải thích điều đó một chút?
G.Abhisek 3/03/2016

2
điều này dường như gây rối với tỷ lệ khung hình vì một số lý do
fwhenin
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.