Bir UIImage 90 derece nasıl döndürülür?


177

Bir sahip UIImageolduğu UIImageOrientationUpI (yatay) 90 derece döndürme saat yönünün tersine istiyorum (dikey). A kullanmak istemiyorum CGAffineTransform. Ben pikselleri UIImageaslında pozisyon kaydırmak istiyorum . Başlangıçta UIImagebunu yapmak için yeniden boyutlandırmak amaçlanan bir kod bloğu (aşağıda gösterilen) kullanıyorum . Hedef boyutu geçerli boyutu olarak ayarladım UIImageama bir hata alıyorum:

(Hata): CGBitmapContextCreate: geçersiz veri baytı / satırı: 8 tamsayı biti / bileşeni, 3 bileşeni, kCGImageAlphaPremultipliedLast için en az 1708 olmalıdır.

(Hedef boyut BTW olarak bir SMALLER boyutu sağladığımda hata almıyorum). UIImageMevcut boyutu korurken, yalnızca temel grafik işlevlerini kullanarak 90 derecelik CCW'mi nasıl DÖNDÜRÜRİM ?

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

Başka bir yararlı bağlantı buldum .. Umarım bu bazı yardımcı olur .. mobiledevelopertips.com/user-interface/…
Dilip Rajkumar


Benim sorunum Amazon S3'e yüklenen fotoğrafların döndürülmüş olması. Bu çözüm sorunu görsel olarak çözdü ve yükledi.
chrisallick

stackoverflow.com/questions/30701578/… hey nilam, sileceğimizi gördükten sonra bakın
hrishikesh Deshpande

Yanıtlar:


89

Peki ya şöyle bir şey:

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
Benim yorumum, doğru RotateCTM'yi ayarlamak için çağrıdan sonra drawAtPoint'in çağrılması gerekebileceğiydi. DrawAtPoint'i UIGraphics'den hemen önce taşımayı deneyinGetImageFromCurrentImageContext
fbrereto

4
Bu bir arka plan iş parçacığı üzerinde işe yaramaz. UIGraphicsGetCurrentContext (), iş parçacığı için güvenli değildir ve yalnızca ana (UI) iş parçacığında çağrılmalıdır.
Chris R. Donnelly

1
CGContextRotateCTM () 'ye son çağrı muhtemelen 90 değil 180 döndürmeli. Aslında… Aşağı muhtemelen 180 döndürmeli ve… Yukarı muhtemelen döndürmemelidir.
Ivan Vučica

5
İOS 4 ve sonraki sürümlerde, uygulamanızın herhangi bir iş parçacığından UIGraphicsGetCurrentContext işlevini çağırabilirsiniz.
bentford

3
Önce ve sonra CGContextTranslateCTM (ctx, width / 2, height / 2) gerekir.
Glenn Maynard

411

En kolay yolu (ve iş parçacığı çok güvenli) yapmak olduğuna inanıyorum:

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

Not: Brainware'in söylediği gibi , bu yalnızca görüntünün yönlendirme verilerini değiştirir - piksel verilerine dokunulmaz. Bazı uygulamalar için bu yeterli olmayabilir.

Veya Swift'te:

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

1
Daha genel yapın: UIImage * origImg = [UIImage imageNamed: @ "1.JPG"]; UIImage * fixed = [UIImage imageWithCGImage: [origImg CGImage] ölçek: 1.0 yönlendirme: origImg.imageOrientation];
Cullen SUN

13
Bu aslında görüntüyü döndürmez. Görüntünün bir kopyasını oluşturur ve görüntünün imageFlags özelliğinin imageOrientation bitlerini 0, 1, 2 veya 3 olarak ayarlar. Bazı sınıflar UIActivityViewController gibi bu bayrakları yoksayar. Görüntünün gerçekten döndürülmesine ihtiyacınız varsa, Ben Groot'un Hardy Macia'nın UIImage uzantısının cevabına bakın.
Brainware

Uygulamanız hem retina hem de retina olmayan ekranlarda kullanılıyorsa ölçeği 1.0 olarak koymak, originalImage.scale dosyasını alıp ölçek bileşeni olarak iletmeniz gerekir.
teradyl

2
Anlayabildiğim kadarıyla iOS10'da çalışmayı bırakmış gibi görünüyor.
Nailer

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

110

Hardy Macia'nın basit ve harika koduna göz atın: kesme-ölçeklendirme ve döndürme-uiimages

Sadece ara

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];

Teşekkürler Hardy Macia!

Başlık:

  • (UIImage *) imageAtRect: (CGRect) doğrultusu;
  • (UIImage *) imageByScalingPorfortionallyToMinimumSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingProportionallyToSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingToSize: (CGSize) targetSize;
  • (UIImage *) imageRotatedByRadians: (CGFloat) radyanları;
  • (UIImage *) imageRotatedByDegrees: (CGFloat) derece;

Bağlantı ölebileceğinden, tam kod İşte

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

... bağlantı koptu. Kodun tamamını
Greg

31

Göründüğü kadar garip, aşağıdaki kod benim için sorunu çözdü:

+ (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
Çalışır, çünkü doğrultuda çizdiğinizde görüntü yönü korunmaz.
Mercurial

Evet, bu bir görüntüden yönlendirmeyi kaldırmak için yararlı olacaktır
Shihab

İşlev adı kaldırılmış olmalıdırOrientationProperty
Shihab

29

Bir iş parçacığı güvenli döndürme işlevi aşağıdaki gibidir (çok daha iyi çalışır):

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

Kodunuzla ilgili bir sorun var ... Görüntünün etrafına garip beyaz bir çerçeve ekliyor UIImageOrientationDown.
iosfreak

1
CGColorSpaceRelease (colorspace) çağrısını istemiyorsunuz, bkz. Stackoverflow.com/questions/5269815/…
Seth Spitzer

Evet, bu sürüm için üzgünüm
thewormsterror

18

Onaylanan cevap dahil olmak üzere yukarıdakilerin tümüyle sorun yaşadım. İstediğim tek şey bir görüntüyü döndürmek olduğu için Hardy'nin kategorisini bir yönteme dönüştürdüm. İşte kod ve kullanım:

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

Ve kullanımı:

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

Teşekkürler Hardy!


16

Görüntüyü 90 derece döndürme (saat yönünde / saat yönünün tersine yönde)

İşlev çağrısı -

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

Uygulama:

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

Bu görüntü boyutunu artırır
Shashikant More

5

Fotoğrafı 90 derecelik artışlarla döndürmeye devam edecek bir fotoğraf döndürme düğmesi eklemek istiyorsanız, işte gidiyorsunuz. ( finalImagebaşka bir yerde oluşturulmuş bir 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

Basit. Görüntü yönlendirme bayrağını değiştirmeniz yeterlidir.

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

İşte görüntüyü herhangi bir keyfi açıyla döndüren UIImage için bir Swift uzantısı. Bu şekilde kullanın: let rotatedImage = image.rotated(byDegrees: degree). Objective-C kodunu diğer cevaplardan birinde kullandım ve yanlış yaptığımız birkaç satırı kaldırdım (kutu öğelerini döndürdüm) ve UIImage için bir uzantıya dönüştürdüm.

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

Harika çalışıyor! Ben genişlik ve yüksekliği takas böylece biraz değiştirdim: func döndürmek (byDegrees derecesi: Çift, toSize: CGSize? = Nil) -> UIImage {let rotatedSize = toSize ?? self.size
Edwin Vermeer

1
Bu, görüntünün sınırlarını düzgün ayarlamıyor. Sonunda orijinal sınırları aşan döndürülmüş bir görüntü elde edersiniz.
Devin B

Bunun için çok teşekkürler. Bugün bunun için ne kadar zaman harcadığım inanılmaz.
ChrisH

5

Swift 3 UIImage uzantısı:

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'ın cevabının Swift 4.2 sürümü :

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

}

Balonlar bir görüntünün ağırlığı. Testim: DÖNMEDEN ÖNCE ============================== genişlik 3024.0 yükseklik 3024.0 boyut 4952213 bayt ======= ======================= DÖNEM SONRASI ========================= ===== genişlik 3024.0 yükseklik 3024.0 boyut 35191195 bayt =============================
barrylachapelle

2

Bu kodu deniyorum, işe yarıyor ve 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'nın koduna dayanan diğer cevaplarda küçük değişiklik. UIViewDöndürülen görüntünün sınırlayıcı dikdörtgenini hesaplamak için bir nesnenin tamamını oluşturmaya gerek yoktur . Düğmesini kullanarak görüntü dikdörtgenine bir döndürme dönüşümü uygulamanız yeterlidir 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 SarnowskiCevabının basit zarafetini seviyorum , ancak EXIFmeta verilere ve benzerine güvenemediğinizde sorunlara neden olabilir . Gerçek görüntü verilerini döndürmeniz gereken durumlarda böyle bir şey tavsiye ederim:

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

Yukarıdaki kod, yönü olan bir görüntüyü alır Landscape( Landscape Leftya da olup olmadığını hatırlayamaz Landscape Right) ve döndürür Portrait. İhtiyaçlarınız için değiştirilebilen bir örnektir.

Oynamak zorunda olduğunuz temel argümanlar, CGContextRotateCTM(context, M_PI_2)ne kadar döndürmek istediğinize karar verdiğiniz yerdir, ancak daha sonra resmin hala ekranda çizildiğinden emin olmanız gerekir.CGContextTranslateCTM(context, 0, -640) . Bu son bölüm, boş bir ekranı değil görüntüyü gördüğünüzden emin olmak için oldukça önemlidir.

Daha fazla bilgi için kaynağa göz atın .


2
Kırık bağlantı için aşağı oy ve -640 sihirli numarasının açıklaması yok. Sabit ise tersine dönecektir.
Nate

0

yeniden boyutlandırma-a-uiimage-the-right - bu işlemi gerçekleştiren birçok kod örneğinin sahip olduğu sorunların bazılarını açıklar ve UIImage + resize.m'deki özel yardımcı yöntemi UIImages ile başa çıkmaya yardımcı olacak bazı kod parçacıklarına sahiptir. rotasyon, bu yüzden bunu herkese açık bir arayüz olarak göstermeniz gerekir.

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

Bu dosyadaki lisans:

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

Swift için: İşte UIImage için basit bir uzantı:

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

( Kaynak )

Şununla kullanın:

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

Birincisi görüntüyü döndürür ve flip true değerine ayarlanırsa çevirir.


Bunu biraz açıklayabilir misiniz?
G.Abhisek

2
Bu nedense boy oranına sahip karmaşa gibi görünüyor
fwhenin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.