首页 文章

如何将UIImage旋转90度?

提问于
浏览
167

我有 UIImageUIImageOrientationUp (肖像),我想逆时针旋转90度(到风景) . 我不想使用 CGAffineTransform . 我希望 UIImage 的像素实际上移位 . 我正在使用一段代码(如下所示),最初旨在调整 UIImage 的大小来执行此操作 . 我将目标大小设置为 UIImage 的当前大小,但是我收到错误:

(错误):CGBitmapContextCreate:无效数据字节/行:对于8个整数位/组件,3个组件,kCGImageAlphaPremultipliedLast,至少应为1708 .

(每当我提供SMALLER尺寸作为目标尺寸BTW时,我都不会收到错误) . 如何在保留当前大小的同时仅使用核心图形功能旋转我的 UIImage 90度CCW?

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

19 回答

  • 0

    这看起来很奇怪,下面的代码为我解决了这个问题:

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

    怎么样的:

    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;
    }
    
  • 0

    我相信最简单的方法(也是线程安全)是:

    //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 所说,这只会修改图像的方向数据 - 像素数据不受影响 . 对于某些应用程序,这可能还不够 .

    或者在Swift中:

    let portraitImage  : UIImage = UIImage(CGImage: landscapeImage.CGImage ,
                scale: 1.0 ,
                orientation: UIImageOrientation.Right)
    
  • 403

    查看Hardy Macia简单而精彩的代码:cutting-scaling-and-rotating-uiimages

    打电话吧

    UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];
    

    谢谢Hardy Macia!

    Headers :

    • *(UIImage )imageAtRect:(CGRect)rect;

    • *(UIImage )imageByScalingProportionallyToMinimumSize:(CGSize)targetSize;

    • *(UIImage )imageByScalingProportionallyToSize:(CGSize)targetSize;

    • *(UIImage )imageByScalingToSize:(CGSize)targetSize;

    • *(UIImage )imageRotatedByRadians:(CGFloat)radians;

    • *(UIImage )imageRotatedByDegrees:(CGFloat)degrees;

    由于链接可能会死亡,这里是完整的代码

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

    线程安全旋转功能如下(它工作得更好):

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

    我遇到了上述问题,包括批准的答案 . 我将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];
    

    谢谢哈迪!

  • 5

    Rotate Image by 90 degree (clockwise/anti-clockwise direction)

    功能调用 -

    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;
      }
    
  • 1

    如果你想添加一个照片旋转按钮,它将继续以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;
    }
    
  • 2

    简单 . 只需更改图像方向标志即可 .

    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];
    
  • 84

    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()!)
    }
    
  • 5

    这是UIImage的Swift扩展,可以将图像旋转任意角度 . 像这样使用它: 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
    }
    }
    
  • 0

    我尝试这个代码,它工作,并从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;
    }
    
  • 4

    对基于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

    我喜欢简单优雅的 Peter Sarnowski 's answer, but it can cause problems when you can' t依赖于 EXIF 元数据之类的东西 . 在你需要 rotate the actual image data 的情况下,我会推荐这样的东西:

    - (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 (可以't remember if it' s Landscape LeftLandscape Right )的图像并将其旋转为 Portrait . 这是一个可以根据您的需求进行修改的示例 .

    您必须使用的关键参数是 CGContextRotateCTM(context, M_PI_2) ,您可以在其中决定要旋转多少,但是您必须确保图片仍然使用 CGContextTranslateCTM(context, 0, -640) 在屏幕上绘制 . 最后一部分非常重要,以确保您看到图像而不是空白屏幕 .

    有关更多信息,请查看source .

  • 17

    resize-a-uiimage-the-right-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.
    
  • 5

    有一个非常有效的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
        }
    }
    

    Source

    使用它:

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

    该如果将flip设置为true,则前者将旋转图像并翻转它 .

  • 31

    Swift 4.2版RawMean's answer

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

相关问题