2014-11-23 3 views
26

Я использую Xcode 6.0.1 с Swift. У меня есть UIImage, и я хотел бы сделать другое изображение, используя старое изображение в качестве источника, при этом новое изображение будет каким-то образом повернуто ... скажем, перевернуто вертикально.Вращающийся UIImage в Swift

Этот вопрос уже ответил a few months ago. Однако это решение не работает для меня, хотя ситуация идентична.

Когда я

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

Xcode жалуется, что есть «дополнительный аргумент„масштаб“в вызове». После проверки документации Apple это бессмысленно, так как эта версия инициализатора принимает эти три аргумента. Оставляя аргументы шкалы и ориентации, она устраняет проблему, но не позволяет мне вращаться.

Единственная ссылка на это, что я могу найти, это this guy, у кого была такая же проблема.

Как вы думаете?

Мне нужно это для запуска этой версии Xcode, поэтому, если есть альтернативный способ выполнения вращения (я еще не нашел его), это было бы полезно.

+2

Xcode 6.0.1 устарел (не знаю если это проблема). Ваш код компилируется без ошибок или предупреждений в моем Xcode 6.1. Только если вы опустите '.CGImage' (как на ссылочной странице github), вы получите ошибку компилятора. –

+0

Вы можете вращать изображение, рисуя изображение легко, если хотите, в этом Q/A http://stackoverflow.com/questions/40882487/how-to-rotate-image-in-swift-3#40882640 –

ответ

6

«Дополнительный аргумент при вызове» обычно происходит, когда один из типов ввода неверен.

Вы можете исправить код с

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

Вот простое расширение для 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) 

Фо rmer будет вращать изображение и переворачивать его, если для параметра flip установлено значение true.

+0

Наконец, рабочий код! Большое спасибо! –

+4

confile, flipping работает потрясающе. Проблема с вращением заключается в том, что он вращает изображение, НО - он изменяет соотношение сторон и «уничтожает его», можете ли вы проверить его и изменить код? было бы здорово. благодаря! –

+0

также найти это изменяет соотношение - так близко! –

3

Попробуйте этот код, он работал для меня:

@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() 
     } 
    } 
} 
21

В Swift 3 для прошивки 10:

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

Вы можете использовать его как это:

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

С переворачиваются Указанный флаг:

let flippedImage = UIImage(named: "my_amazing_image")?.rotated(by: Measurement(value: 48.0, unit: .degrees), options: [.flipOnVerticalAxis]) 
+0

Спасибо, отличное решение. Не могли бы вы также предложить решение для переворота изображения? – ixany

+1

@ixany Я обновил ответ, чтобы перевернуть вертикальную ось. Это ты имел в виду? –

+0

Это именно то, что я искал. Еще раз спасибо! :) – ixany

6

Swift 3:

Поворот направо:

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

Испытано в Playground:

// 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() 
+0

простой, элегантный, точный. благодаря! – nurxyz

+1

Это не работает. Протестировано на детской площадке. – rr1g0

+0

Почему бы и нет? Покажите мне свой игровой файл! –

1

@confile ответить обновлен до 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! 
    } 
} 
3

Swift 4 Решение

Вот самое простое решение

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) 

     UIGraphicsBeginImageContext(newSize); 
     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)) 

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

и использовать это решение, которое вы можете сделать следующее

let image = UIImage(named: "image.png")! 
let newImage = image.rotate(radians: .pi/2) // Rotate 45 degrees 
+0

Это отличное решение. Я использовал еще один, который отрезал мой образ после вращения, но этот работает отлично. – Adela

Смежные вопросы