rotar image usando CGContextDrawImage

¿Cómo puedo girar una image dibujada por CGContextDrawImage() en su centro?

En drawRect:

  CGContextSaveGState(c); rect = CGRectOffset(rect, -rect.size.width / 2, -rect.size.height / 2); CGContextRotateCTM(c, angle); CGContextDrawImage(c, rect, doodad.CGImage); CGContextRotateCTM(c, -angle); CGContextTranslateCTM(c, pt.x, pt.y); prevRect = rect; CGContextRestoreGState(c); 

Dibujaré la image en el origen, y la rotaré en su centro, y luego traduciré a dónde debería dibujarse. No funciona.

Lo que hay que recordar acerca de las transformaciones de coorderadas, bueno, una de las cosas para recordar, es que no estás manipulando objects, como el command Transformar en un editor de charts; estás manipulando el espacio mismo .

Imagine que el dispositivo está suspendido sobre un escritorio por un arm de cuello de cisne, y está fijo en su position. Las transformaciones de coorderadas mueven el escritorio alnetworkingedor (traducción), y lo vuelven de una manera u otra (rotation), e incluso aplastan y estiran (escala).

Otra de las cosas para recordar acerca de las transformaciones de coorderadas es que la transformación siempre es relativa al origen. Imagine que su escritorio comienza con una de sus esquinas, que corresponde a una esquina de su vista, directamente debajo de la esquina donde su vista termina en la pantalla. La traducción mueve la esquina del escritorio y el rest del escritorio con él, deslizándolo de una manera u otra debajo de la pantalla. Girando gira el escritorio alnetworkingedor de esa esquina.

Una cosa más: las transformaciones afectan el futuro, no el pasado. Dibujar algo y luego tratar de transformarlo no funcionará, porque no transforms lo que has dibujado, transforms el espacio que vas a dibujar. Entonces, debemos mover el escritorio antes de que podamos colocar la image en el lugar correcto.

(Menciono la última parte porque tiene un par de commands de transformación que son inmediatamente revertidos por su llamada CGContextRestoreGState . No hay dibujo entre ellos para que afecten).

Entonces, comencemos con el rectángulo sin girar de la image.

 CGRect imageRect = { pointWhereYouWantTheImageCentenetworking, doodad.size }; 

Ahora, CGContextDrawImage toma un rectángulo, pero, como sabes, dibujará la image en la esquina inferior izquierda de ese rectángulo, no en el centro. (Por lo tanto, todo este ejercicio).

Entonces, esto es lo que vas a hacer. Al final de este, dibujarás la image no en el punto que se muestra arriba, sino en el punto cero , es decir, en la esquina del escritorio. (No centrado en la esquina, pero con la esquina de la image en la esquina del escritorio.)

¿Cómo funcionará eso? Se necesita algo de configuration. Tendrás que mover tu escritorio.

Primero, debe mover su escritorio hacia arriba y hacia la derecha hasta que la esquina de origen de su escritorio esté en el punto central deseado:

 CGContextTranslateCTM(context, imageRect.origin.x, imageRect.origin.y); 

Luego haces la rotation (girando el escritorio alnetworkingedor de su esquina de origen):

 CGContextRotateCTM(context, angleInRadians); 

Luego, mueve el escritorio hacia abajo y lo deja a la mitad de la anchura y altura de la image:

 CGContextTranslateCTM(context, imageRect.size.width * -0.5, imageRect.size.height * -0.5); 

Y luego, finalmente, coloque la image en la esquina del escritorio.

 CGContextDrawImage(context, (CGRect){ CGPointZero, imageRect.size }, [doodad CGImage]); 

Con su escritorio tan movido, el centro de ese rectángulo se encuentra directamente debajo del punto en la pantalla donde desea que la image se centre, por lo que la image está tan cinput.

Esta function puede dibujar imágenes en una image existente con ángulo de rotation en radianes.

Swift 3:

 extension UIImage { func putImage(image: UIImage, on rect: CGRect, angle: CGFloat = 0.0) -> UIImage{ let drawRect = CGRect(x: 0, y: 0, width: size.width, height: size.height) UIGraphicsBeginImageContextWithOptions(drawRect.size, false, 1.0) // Start drawing self self.draw(in: drawRect) // Drawing new image on top let context = UIGraphicsGetCurrentContext()! // Get the center of new image let center = CGPoint(x: rect.midX, y: rect.midY) // Set center of image as context action point, so rotation works right context.translateBy(x: center.x, y: center.y) context.saveGState() // Rotate the context context.rotate(by: angle) // Context origin is image's center. So should draw image on point on origin image.draw(in: CGRect(origin: CGPoint(x: -rect.size.width/2, y: -rect.size.height/2), size: rect.size), blendMode: .normal, alpha: 1.0) // Go back to context original state. context.restreGState() // Get new image let newImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return newImage } } 

Si necesita crear y vaciar image con tamaño y color, use:

 extension UIImage { convenience init?(size: CGSize, color: UIColor) { let rect = CGRect(origin: .zero, size: size) UIGraphicsBeginImageContextWithOptions(rect.size, true, 1.0) color.setFill() UIRectFill(rect) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() guard let cgImage = image?.cgImage else { return nil } self.init(cgImage: cgImage) } } 

Puede usar el siguiente método para girar imágenes.

 -(UIImage*)rotateImage:(UIImage*)img forAngle:(CGFloat)radian { UIView *rotatedViewBox = [[UIView alloc]initWithFrame:CGRectMake(0, 0, img.size.width, img.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(radian); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; UIGraphicsBeginImageContext(rotatedSize); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(context, rotatedSize.width, rotatedSize.height); CGContextRotateCTM(context, radian); CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGRectMake(-img.size.width, -img.size.height, img.size.width, img.size.height), img.CGImage); UIImage *returnImg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return returnImg; } 

Si usa el ángulo, aquí está la macro para convertir el grado a radian

 #define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI) 

Si finalmente estás dibujando en la pantalla (en lugar de generar una image para save en un file), podrías considerar no usar un CGContext en absoluto, sino poner la image en un CALayer y rotar la capa sobre su punto de anclaje:

 [layer setValue:@(rotationInRadians) forKeyPath:@"transform.rotation.z"]; 

Si la image se genera por sí misma (a diferencia de un recurso estático de su package o algo provisto por el usuario), podría considerar salir de las capas y configurar la sublayerTransform de su capa padre / antepasado común:

 [layerContainingTheConstituentLayers setValue:@(rotationInRadians) forKeyPath:@"sublayerTransform.rotation.z"]; 

(Puede haber forms de hacerlo con vistas en vez de capas; soy un chico de Mac, así que no conozco a UIView muy profundamente).