Как повернуть UIImage на 90 градусов? - PullRequest
172 голосов
/ 22 августа 2009

У меня есть UIImage, то есть UIImageOrientationUp (портрет), который я хотел бы повернуть против часовой стрелки на 90 градусов (для альбомной ориентации). Я не хочу использовать CGAffineTransform. Я хочу, чтобы пиксели UIImage фактически сдвинули положение. Я использую блок кода (показанный ниже), изначально предназначенный для изменения размера UIImage, чтобы сделать это. Я устанавливаю целевой размер как текущий размер UIImage, но получаю ошибку:

(Ошибка): CGBitmapContextCreate: недопустимые байты / строка данных: должно быть не менее 1708 для 8 целочисленных бит / компонент, 3 компонента, kCGImageAlphaPremultipliedLast.

(я не получаю сообщение об ошибке, когда в качестве целевого размера указываю размер SMALLER). Как я могу вращать UIImage 90 градусов против часовой стрелки, используя только основные графические функции, сохраняя текущий размер?

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

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

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

    CGContextRef bitmap;

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

    } else {


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

    }       


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

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

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

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

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

Ответы [ 19 ]

4 голосов
/ 31 июля 2016

Вот расширение Swift для UIImage, которое поворачивает изображение на любой произвольный угол. Используйте это так: let rotatedImage = image.rotated(byDegrees: degree). Я использовал код Objective C в одном из других ответов и удалил несколько строк, которые мы неверно (повернули поле), и превратил его в расширение для UIImage.

extension UIImage {

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

    return newImage
}
}
2 голосов
/ 22 июля 2016

Незначительные изменения в других ответах, основанных на коде Харди Макии. Нет необходимости создавать целый объект 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;
}
2 голосов
/ 31 декабря 2013

Я пытаюсь этот код, он работает, и взял от 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;
}
1 голос
/ 19 сентября 2018

Swift 4.2 версия Ответ 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!
}

}
0 голосов
/ 20 апреля 2015

Для Swift: вот простое расширение UIImage:

//ImageRotation.swift

import UIKit

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

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

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

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

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

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

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

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

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }
}

( Источник )

Используйте его с:

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

Первый будет поворачивать изображение и переворачивать его, если для flip установлено значение true.

0 голосов
/ 18 июля 2014

Существует чрезвычайно эффективная категория UIImage с именем NYXImagesKit. Он использует vDSP, CoreImage и vImage, чтобы быть максимально быстрым. У него есть категория UIImage + Вращающийся, которая спасла мой день:)

https://github.com/Nyx0uf/NYXImagesKit

0 голосов
/ 05 мая 2010

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.
0 голосов
/ 14 июля 2011

"Оттенки серого оттенка", по-видимому, является подходящим Google-Fu для этого

сразу получаю:

https://discussions.apple.com/message/8104516?messageID=8104516&#8104516

https://discussions.apple.com/thread/2751445?start=0&tstart=0

Как бы программно подкрасить изображение на iPhone?

0 голосов
/ 10 сентября 2012

Мне нравится простая элегантность ответа Peter Sarnowski, но это может вызвать проблемы, когда вы не можете полагаться на EXIF метаданные и тому подобное. В ситуациях, когда вам нужно повернуть фактические данные изображения , я бы порекомендовал что-то вроде этого:

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

Приведенный выше код берет изображение с ориентацией Landscape (не помню, если это Landscape Left или Landscape Right) и поворачивает его в Portrait. Это пример, который можно изменить для ваших нужд.

Ключевыми аргументами, с которыми вам придется играть, являются CGContextRotateCTM(context, M_PI_2), где вы решаете, на сколько вы хотите повернуть, но затем вы должны убедиться, что картинка все еще отображается на экране, используя CGContextTranslateCTM(context, 0, -640). Эта последняя часть очень важна, чтобы убедиться, что вы видите изображение, а не пустой экран.

Для получения дополнительной информации ознакомьтесь с источником .

...