Estoy usando Xcode 6.0.1 con Swift. Tengo un UIImage, y me gustaría hacer otra imagen con la vieja imagen como una fuente, con la nueva imagen que se ha de girar en alguna manera… decir volteado verticalmente.

Esta pregunta ya fue contestada hace un par de meses. Sin embargo, esa solución no funciona para mí, aunque la situación es idéntica.

Cuando tengo

var image = UIImage(CGImage: otherImage.CGImage, scale: 1.0, orientation: .DownMirrored)

Xcode se queja de que hay un «Extra argumento de ‘escala’ en llamar». Después de comprobar con la documentación de Apple, esto no tiene sentido, ya que la versión de la inicializador de no tomar esos tres argumentos. Dejando fuera de la escala y la orientación de los argumentos de no solucionar el problema, pero no me deja hacer la rotación.

La única otra referencia a este que puedo encontrar es este tipo, que tenía el mismo problema.

¿Qué te parece?

Necesito que esto se ejecute en esta versión de Xcode, así que si hay una forma alternativa de realizar el giro (no he encontrado uno) que podrían ser útiles.

  • Xcode 6.0.1 es anticuado (no sé si ese es el problema). El código se compila sin errores o advertencias en mi Xcode 6.1. Sólo si se omite el .CGImage (como en la que se hace referencia página de github) a continuación, obtendrá un error del compilador.
  • Usted puede girar la imagen en el dibujo de la vista de la imagen fácilmente si te gusta esta P/A stackoverflow.com/questions/40882487/…
InformationsquelleAutor std_answ | 2014-11-23

11 Comentarios

  1. 49

    Swift 5 Solución

    Aquí es la solución más sencilla

    extension UIImage {
        func rotate(radians: Float) -> UIImage? {
            var newSize = CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: CGFloat(radians))).size
            //Trim off the extremely small float value to prevent core graphics from rounding it up
            newSize.width = floor(newSize.width)
            newSize.height = floor(newSize.height)
    
            UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
            let context = UIGraphicsGetCurrentContext()!
    
            //Move origin to middle
            context.translateBy(x: newSize.width/2, y: newSize.height/2)
            //Rotate around middle
            context.rotate(by: CGFloat(radians))
            //Draw the image at its center
            self.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))
    
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return newImage
        }
    }

    y el uso de esta solución puede hacer lo siguiente

    let image = UIImage(named: "image.png")!
    let newImage = image.rotate(radians: .pi/2) // Rotate 90 degrees
    • esta es una gran solución. He utilizado otro en el que se recorte, mi imagen después de la rotación, pero este funciona perfecto.
    • Genial!!! Gracias!!!
    • Este código hace que la imagen pierda calidad.
    • He actualizado el código para tener en cuenta la escala de la imagen – gracias.
    • Tenga cuidado al tratar con UIImages con diferentes orientaciones. auto.draw() de forma automática dibujar la imagen con .hasta la orientación.
    • Estoy usando esto, trate de girar un uiimage en una costumbre annotationView. se trata de una imagen .png de una moto. no girar la imagen … y que acaba de regresar de un cuadrado negro?
    • .pi es de 180 grados, .pi/2 es de 90 grados, .pi/4 es de 45 grados, …, .pi/180 es de 1 grados.
    • Buena respuesta. usted salvar mi día!!

  2. 46

    Aquí es una simple extensión de 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
    }
    }

    (Fuente)

    Utilizar con:

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

    A la primera se le girar una imagen y darle la vuelta si el flip está establecida en true.

    • Finalmente un código de trabajo! Se agradece un montón!
    • confile, voltear obras impresionante. El problema con la rotación es el que se hace rotar la imagen, PERO cambia la relación de aspecto y «destruir»,se puede comprobar y modificar el código? sería estupendo. gracias!
    • también encontramos que se modifica la relación de tan cerca!
    • ImageView.tintColor deja de funcionar después de rotar la imagen con esta función. Incluso si intento para restablecer imageWithRenderingMode a AlwaysTemplate. Alguna idea de por qué?
    • UIGraphicsBeginImageContext(rotatedSize) debe ser UIGraphicsBeginImageContextWithOptions(rotatedSize, false, self.scale) para preservar escala
    • que era perfecto! La mía fue la pixelación, pero fue corregido después de usar su reemplazo sugerencia!
    • Funciona para mí, un buen copiar y pegar solución.
    • Xcode da sugerencias para convertir este código Swift 3, excepto por esta línea, CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage). Cambiar a bitmap?.draw( cgImage!, in: CGRect(x: -size.width / 2, y: -size.height / 2,width: size.width,height: size.height))
    • Tengo un error CGBitmapContextCreate: invalid data bytes/row: should be at least 7680 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedFirst. Nadie conocía este error?
    • De esta manera no se libera la memoria. Que se mantenga alrededor de 30 mb de Ram cada vez que gire una nueva foto tomada con el iPhone 6.

  3. 29
    extension UIImage {
    struct RotationOptions: OptionSet {
    let rawValue: Int
    static let flipOnVerticalAxis = RotationOptions(rawValue: 1)
    static let flipOnHorizontalAxis = RotationOptions(rawValue: 2)
    }
    func rotated(by rotationAngle: Measurement<UnitAngle>, options: RotationOptions = []) -> UIImage? {
    guard let cgImage = self.cgImage else { return nil }
    let rotationInRadians = CGFloat(rotationAngle.converted(to: .radians).value)
    let transform = CGAffineTransform(rotationAngle: rotationInRadians)
    var rect = CGRect(origin: .zero, size: self.size).applying(transform)
    rect.origin = .zero
    let renderer = UIGraphicsImageRenderer(size: rect.size)
    return renderer.image { renderContext in
    renderContext.cgContext.translateBy(x: rect.midX, y: rect.midY)
    renderContext.cgContext.rotate(by: rotationInRadians)
    let x = options.contains(.flipOnVerticalAxis) ? -1.0 : 1.0
    let y = options.contains(.flipOnHorizontalAxis) ? 1.0 : -1.0
    renderContext.cgContext.scaleBy(x: CGFloat(x), y: CGFloat(y))
    let drawRect = CGRect(origin: CGPoint(x: -self.size.width/2, y: -self.size.height/2), size: self.size)
    renderContext.cgContext.draw(cgImage, in: drawRect)
    }
    }
    }

    Se puede utilizar como esto:

    let rotatedImage = UIImage(named: "my_amazing_image")?.rotated(by: Measurement(value: 48.0, unit: .degrees))

    Con volteado bandera especificado:

    let flippedImage = UIImage(named: "my_amazing_image")?.rotated(by: Measurement(value: 48.0, unit: .degrees), options: [.flipOnVerticalAxis])
    • Gracias, gran solución. Podría usted puede proporcionar también una solución para voltear una imagen?
    • He actualizado la respuesta a mover sobre el eje vertical. Es que lo que quiso decir?
    • Que era exactamente lo que estaba buscando. Gracias de nuevo! 🙂
  4. 9

    ‘Extra argumento en la llamada’ generalmente sucede cuando uno de los tipos de entrada es incorrecta.

    Usted puede corregir el código con

    var image = UIImage(CGImage: otherImage.CGImage, scale: CGFloat(1.0), orientation: .DownMirrored)
  5. 9

    Swift 3:

    De rotación a derecha:

    let image = UIImage(cgImage: otherImage.cgImage!, scale: CGFloat(1.0), orientation: .right)

    Probado en el Patio de recreo:

    //MyPlayground.playground
    
    import UIKit
    import PlaygroundSupport
    let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
    view.backgroundColor = UIColor.white
    PlaygroundPage.current.liveView = view
    let otherImage = UIImage(named: "burger.png", in: Bundle.main,
    compatibleWith: nil)
    let imageViewLeft = UIImageView(image: UIImage(cgImage: (otherImage?.cgImage!)!, scale: CGFloat(1.0), orientation: .left)) 
    let imageViewRight = UIImageView(image: UIImage(cgImage: (otherImage?.cgImage!)!, scale: CGFloat(1.0), orientation: .right))
    view.addSubview(imageViewLeft)
    view.addSubview(imageViewRight)
    view.layoutIfNeeded()
    • simple, elegante, preciso. gracias!
    • Esto no funciona. Probado en el patio de recreo.
    • ¿Por qué no? Muéstrame tu Patio de recreo de Archivo!
    • Esta debe ser la respuesta! Gracias por eso!
    • Esto no responde a la pregunta, como pedían un método para hacer otra imagen. Esta solución utiliza la orientación en los datos EXIF de la imagen girada a la derecha. Así, por ejemplo, usted no puede llamar a esto dos veces para girar la imagen 180 grados.
    • tienes razón, pero ayuda a los demás a girar UIImages

  6. 5

    Prueba este código, a mí me funcionó:

    @IBAction func btnRotateImagePressed(sender: AnyObject) {
    if let originalImage = self.imageView.image {
    let rotateSize = CGSize(width: originalImage.size.height, height: originalImage.size.width)
    UIGraphicsBeginImageContextWithOptions(rotateSize, true, 2.0)
    if let context = UIGraphicsGetCurrentContext() {
    CGContextRotateCTM(context, 90.0 * CGFloat(M_PI) / 180.0)
    CGContextTranslateCTM(context, 0, -originalImage.size.height)
    originalImage.drawInRect(CGRectMake(0, 0, originalImage.size.width, originalImage.size.height))
    self.imageView.image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    }
    }
    }
    • Me he convertido esta a la Swift4, pero está causando un problema de memoria.
    • Después de usar UIGraphicsEndImageContext() de la memoria se resuelve el problema.
    • cuando la captura de landscapeLeft de la imagen, a continuación, mostrar la imagen es el lado equivocado.
  7. 4

    @confile respuesta actualizada a Swift 4

    import UIKit
    extension UIImage {
    public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage {
    let radiansToDegrees: (CGFloat) -> CGFloat = {
    return $0 * (180.0 / CGFloat.pi)
    }
    let degreesToRadians: (CGFloat) -> CGFloat = {
    return $0 / 180.0 * CGFloat.pi
    }
    //calculate the size of the rotated view's containing box for our drawing space
            let rotatedViewBox = UIView(frame: CGRect(origin: .zero, size: size))
    let t = CGAffineTransform(rotationAngle: 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.
            bitmap?.translateBy(x: rotatedSize.width / 2.0, y: rotatedSize.height / 2.0)
    //  //Rotate the image context
            bitmap?.rotate(by: 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)
    }
    bitmap?.scaleBy(x: yFlip, y: -1.0)
    let rect = CGRect(x: -size.width / 2, y: -size.height / 2, width: size.width, height: size.height)
    bitmap?.draw(cgImage!, in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
    }
    }
  8. 3

    No utilice UIGraphicsBeginImageContext porque va a destruir la calidad de su vector, el uso de UIGraphicsBeginImageContextWithOptions. Esta es mi aplicación en Swift 3/4:

    extension UIImage {
    func rotated(degrees: CGFloat) -> UIImage? {
    let degreesToRadians: (CGFloat) -> CGFloat = { (degrees: CGFloat) in
    return degrees / 180.0 * CGFloat.pi
    }
    //Calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox: UIView = UIView(frame: CGRect(origin: .zero, size: size))
    rotatedViewBox.transform = CGAffineTransform(rotationAngle: degreesToRadians(degrees))
    let rotatedSize: CGSize = rotatedViewBox.frame.size
    //Create the bitmap context
        UIGraphicsBeginImageContextWithOptions(rotatedSize, false, 0.0)
    guard let bitmap: CGContext = UIGraphicsGetCurrentContext(), let unwrappedCgImage: CGImage = cgImage else {
    return nil
    }
    //Move the origin to the middle of the image so we will rotate and scale around the center.
        bitmap.translateBy(x: rotatedSize.width/2.0, y: rotatedSize.height/2.0)
    //Rotate the image context
        bitmap.rotate(by: degreesToRadians(degrees))
    bitmap.scaleBy(x: CGFloat(1.0), y: -1.0)
    let rect: CGRect = CGRect(
    x: -size.width/2,
    y: -size.height/2,
    width: size.width,
    height: size.height)
    bitmap.draw(unwrappedCgImage, in: rect)
    guard let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() else {
    return nil
    }
    UIGraphicsEndImageContext()
    return newImage
    }
  9. 1

    Para Swift 4.2

    extension UIImage {
    func rotate(_ radians: CGFloat) -> UIImage {
    let cgImage = self.cgImage!
    let LARGEST_SIZE = CGFloat(max(self.size.width, self.size.height))
    let context = CGContext.init(data: nil, width:Int(LARGEST_SIZE), height:Int(LARGEST_SIZE), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: cgImage.colorSpace!, bitmapInfo: cgImage.bitmapInfo.rawValue)!
    var drawRect = CGRect.zero
    drawRect.size = self.size
    let drawOrigin = CGPoint(x: (LARGEST_SIZE - self.size.width) * 0.5,y: (LARGEST_SIZE - self.size.height) * 0.5)
    drawRect.origin = drawOrigin
    var tf = CGAffineTransform.identity
    tf = tf.translatedBy(x: LARGEST_SIZE * 0.5, y: LARGEST_SIZE * 0.5)
    tf = tf.rotated(by: CGFloat(radians))
    tf = tf.translatedBy(x: LARGEST_SIZE * -0.5, y: LARGEST_SIZE * -0.5)
    context.concatenate(tf)
    context.draw(cgImage, in: drawRect)
    var rotatedImage = context.makeImage()!
    drawRect = drawRect.applying(tf)
    rotatedImage = rotatedImage.cropping(to: drawRect)!
    let resultImage = UIImage(cgImage: rotatedImage)
    return resultImage
    }
    }
  10. 0

    Esto funciona para iOS 8+ y mantiene la calidad de la imagen. Se trata de dos extensiones para UIImage.

      extension UIImage {
    func withSize(_ width: CGFloat, _ height: CGFloat) -> UIImage {
    let target = CGSize(width, height)
    var scaledImageRect = CGRect.zero
    let aspectWidth:CGFloat = target.width / self.size.width
    let aspectHeight:CGFloat = target.height / self.size.height
    let aspectRatio:CGFloat = min(aspectWidth, aspectHeight)
    scaledImageRect.size.width = self.size.width * aspectRatio
    scaledImageRect.size.height = self.size.height * aspectRatio
    scaledImageRect.origin.x = (target.width - scaledImageRect.size.width) / 2.0
    scaledImageRect.origin.y = (target.height - scaledImageRect.size.height) / 2.0
    UIGraphicsBeginImageContextWithOptions(target, false, 0)
    self.draw(in: scaledImageRect)
    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return scaledImage!
    }
    func rotated(degrees: Double) -> UIImage {
    let radians = CGFloat(Double.pi * degrees / 180)
    var rotatedViewBox: UIView? = UIView(frame: CGRect(x: 0, y: 0, width: size.width * scale, height: size.height * scale))
    let t = CGAffineTransform(rotationAngle: radians)
    rotatedViewBox!.transform = t
    let rotatedSize = rotatedViewBox!.frame.size
    rotatedViewBox = nil
    //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.
          bitmap.translateBy(x: rotatedSize.width/2, y: rotatedSize.height/2)
    //  //Rotate the image context
          bitmap.rotate(by: radians)
    //Now, draw the rotated/scaled image into the context
          bitmap.scaleBy(x: 1.0, y: -1.0)
    bitmap.draw(cgImage!, in: CGRect(x:-size.width * scale / 2, y: -size.height * scale / 2, width: size.width * scale, height: size.height * scale))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage.withSize(newImage.size.width/scale, newImage.size.height/scale)
    }
    }
  11. 0

    Comprobarlo:

    func rotatedImage(with angle: CGFloat) -> UIImage {
    let updatedSize = CGRect(origin: .zero, size: size)
    .applying(CGAffineTransform(rotationAngle: angle))
    .size
    return UIGraphicsImageRenderer(size: updatedSize)
    .image { _ in
    let context = UIGraphicsGetCurrentContext()
    context?.translateBy(x: updatedSize.width / 2.0, y: updatedSize.height / 2.0)
    context?.rotate(by: angle)
    draw(in: CGRect(x: -size.width / 2.0, y: -size.height / 2.0, width: size.width, height: size.height))
    }
    .withRenderingMode(renderingMode)
    }

Dejar respuesta

Please enter your comment!
Please enter your name here