Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate image using CGContextDrawImage

How can I rotate an image drawn by CGContextDrawImage() at its center?

In 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);

I draw the image at the origin, and rotate it at its center, then translate to where it should be drawn. Not working.

like image 248
Morrowless Avatar asked May 27 '13 04:05

Morrowless


People also ask

How do I rotate a picture with a certain degree?

Manually rotate a picture or shape Select the picture or shape. Manually rotate the text box by selecting the shape or picture rotation handle and dragging in the direction you want. To keep the rotation to 15 degree angles, press and hold Shift while you drag the rotation handle.

How do I rotate an image in Xcode?

Step 1 − Open Xcode→SingleViewApplication→name it RotateImage. Step 2 − Open Main. storyboard, add UIImageView and add 2 buttons as shown below name them ROTATE BY 90 DEGREES AND ROTATE BY 45 DEGREES.

How do you rotate an image in Python?

The imutils. rotate() function is used to rotate an image by an angle in Python.


2 Answers

The thing to remember about coordinate transformations—well, one of the things to remember—is that you are not manipulating objects, like the Transform command in a graphics editor; you are manipulating space itself.

Imagine that the device is suspended over a desk by a gooseneck arm, and is fixed in position. Coordinate transformations move the desk around (translation), and turn it one way or the other (rotation), and even squash and stretch it (scaling).

Another of the things to remember about coordinate transformations is that transformation is always relative to the origin. Imagine that your desk starts out with one of its corners—corresponding to a corner of your view—directly underneath the corner of where your view ends up on the screen. Translating moves the corner of the desk, and the rest of the desk with it, sliding it one way or another underneath the screen. Rotating turns the desk around that corner.

One more thing: Transformations affect the future, not the past. Drawing something and then trying to transform it won't work, because you don't transform what you've drawn, you transform the space you're going to draw into. So, we need to move the desk before we can place the image in the right spot.

(I mention that last part because you have a couple of transformation commands that are immediately reverted by your CGContextRestoreGState call. There is no drawing in between for them to affect.)

So, let's start with the unrotated rectangle of the image.

CGRect imageRect = { pointWhereYouWantTheImageCentered, doodad.size };

Now, CGContextDrawImage takes a rectangle, but, as you know, it's going to draw the image from the lower-left corner of that rectangle, not the center. (Hence this whole exercise.)

So, here's what you're going to do. At the end of this, you're going to draw the image not at that point shown above, but at the zero point—that is, on the very corner of the desk. (Not centered on the corner, but with the image's corner on the desk's corner.)

How will that work? It takes some set-up. You're going to have to move your desk.

First, you need to move your desk up and right until the origin corner of your desk is at the desired center point:

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

Then you do the rotation (turning the desk around its origin corner):

CGContextRotateCTM(context, angleInRadians);

Then you move the desk back down and left by half of the image's width and height:

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

And then, finally, place the image on the corner of the desk.

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

With your desk so moved, the center of that rectangle lies directly under the point on the screen where you want the image centered, so the image is so centered.

like image 90
Peter Hosey Avatar answered Oct 19 '22 15:10

Peter Hosey


This function can draw image on an existing image with rotation angle in radians.

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.restoreGState()

        // Get new image
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return newImage
    }

}

If you need to create and empty image with size and 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)
    }
}
like image 7
akoruk Avatar answered Oct 19 '22 15:10

akoruk