J'utilise Xcode 6.0.1 avec Swift. J'ai une UIImage, et je voudrais faire une autre image en utilisant l'ancienne image comme source, avec la nouvelle image en rotation d'une manière ou d'une autre ... disons inversée verticalement.
Cette question a déjà été répondue il y a quelques mois . Cependant, cette solution ne fonctionne pas pour moi, même si la situation est identique.
Quand j'ai
var image = UIImage(CGImage: otherImage.CGImage, scale: 1.0, orientation: .DownMirrored)
Xcode se plaint qu'il existe un "argument supplémentaire 'scale' dans l'appel". Après vérification auprès de la documentation Apple, cela n’a aucun sens, car cette version de l’initialiseur prend ces trois arguments. Abandonner les arguments d'échelle et d'orientation corrige le problème, mais m'empêche d'effectuer la rotation.
La seule autre référence à cela que je puisse trouver est ce gars , qui a eu le même problème.
Qu'est-ce que tu penses?
J'ai besoin que cela fonctionne sur cette version de Xcode, donc s'il existe un autre moyen d'effectuer la rotation (je n'en ai pas encore trouvé), ce serait utile.
Voici une simple extension 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
}
}
( La source )
Utilisez-le avec:
rotatedPhoto = rotatedPhoto?.imageRotatedByDegrees(90, flip: false)
Le premier fera pivoter une image et la retournera si retourner est défini sur true.
Voici la solution la plus simple
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
}
}
et pour utiliser cette solution, vous pouvez faire ce qui suit
let image = UIImage(named: "image.png")!
let newImage = image.rotate(radians: .pi/2) // Rotate 90 degrees
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)
}
}
}
Vous pouvez l'utiliser comme ceci:
let rotatedImage = UIImage(named: "my_amazing_image")?.rotated(by: Measurement(value: 48.0, unit: .degrees))
Avec drapeau inversé spécifié:
let flippedImage = UIImage(named: "my_amazing_image")?.rotated(by: Measurement(value: 48.0, unit: .degrees), options: [.flipOnVerticalAxis])
Un «argument supplémentaire dans l'appel» survient généralement lorsqu'un des types d'entrée est incorrect.
Vous pouvez réparer votre code avec
var image = UIImage(CGImage: otherImage.CGImage, scale: CGFloat(1.0), orientation: .DownMirrored)
Swift 3:
Rotation à droite:
let image = UIImage(cgImage: otherImage.cgImage!, scale: CGFloat(1.0), orientation: .right)
Testé sur le terrain de jeu:
// 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()
Essayez ce code, cela a fonctionné pour moi:
@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()
}
}
}
@confile answer mis à jour vers 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!
}
}
N'utilisez pas UIGraphicsBeginImageContext
car cela détruirait la qualité de votre vecteur, utilisez UIGraphicsBeginImageContextWithOptions
. Ceci est ma mise en œuvre dans 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
}
Pour 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
}
}
Cela fonctionne pour iOS 8+ et maintient la qualité de l'image. Ce sont deux extensions pour 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)
}
}