iOS: Rotating with CGContextRotate - ios

Im trying to rotate an image, that i want to draw on a image file (to the context.
Everything works fine, except when i rotate the image.
Basically i have an image; i want to scale and resize the image and then clip it to a rect and finaly draw it to the UICurrentContext;
//create a new graphic context
UIGraphicsBeginImageContext(CGSizeMake(500, 500));
CGContextRef graphicContext = UIGraphicsGetCurrentContext();
CGContextDrawImage(graphicContext, CGRectMake(0, 0, rect.size.width, rect.size.height), image.CGImage);
CGContextRotateCTM(graphicContext, 45 * M_PI/180.0);
UIImage* editedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//draw it to the current context
[editedImage drawAtPoint:CGPointMake(0,0)];
The thing is when i rotate the image, i dont have a clue what the new size of the imagecontext would be. Next to that, the image in the edited image is not rotated..

You need to rotate the context before you draw. I know this seems silly, but to use the analogy of a piece of paper...this is a piece of paper that cannot move. Instead you must move yourself around it and then draw.
This way, your size will never change because anything too big will just simply be cut off.
EDIT Also, this function takes radians, not degrees, so you don't need to convert as you are doing. If you want 45 degrees it will just be PI / 4 (which is stored as the constant M_PI_4 in math.h).

Related

Rotating CIImage around a point

I would like to rotate a UIImage from file (a jpeg on the file system) a computed amount of radians, but I would like to rotate it around a point in the image, as well as keep the original size of the image (with transparent gaps in the image where image data no longer exists, as well as cropping image data that has moved outside of the original frame). I would like to then store and display the resulting UIImage. I haven't found any resources for this task, any help would be much appreciated!
The closest thing I have found so far (with some slight modifications) is as follows:
-(UIImage*)rotateImage:(UIImage*)image aroundPoint:(CGPoint)point radians:(float)radians newSize:(CGRect)newSize
{
CGRect imageRect = { point, image.size };
UIGraphicsBeginImageContext(image.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, imageRect.origin.x, imageRect.origin.y);
CGContextRotateCTM(context, radians);
CGContextTranslateCTM(context, -imageRect.origin.x, -imageRect.origin.y);
CGContextDrawImage(context, (CGRect){ CGPointZero, imageRect.size }, [image CGImage]);
UIImage *returnImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return returnImg;
}
Unfortunately, this rotates the image incorrectly (in my tests, somewhere in the neighborhood of 180 degrees more than desired).
to rotate that UIImage image, lets say 90 degrees, you can easily do:
imageView.transform = CGAffineTransformMakeRotation(M_PI/2);
to rotate it multiple times you can use:
UIView animateKeyframesWithDuration method
and to anchor it to some point you can use:
[image.layer setAnchorPoint:CGPointMake(....)];

UIImageView rotation without moving Image

Hi,
I want to rotate my UIImageView without moving the whole "png". No code is only to test what happens
_fanImage.transform = CGAffineTransformMakeRotation(45);
It turns but the whole image moves. What can I do that this doesn't happen ?
You can try something like this.. You should rotate the UIImage rather than UIImageView.
- (UIImage *)imageWithTransform:(CGAffineTransform)transform {
CGRect rect = CGRectMake(0, 0, self.size.height, self.size.width);
CGImageRef imageRef = self.CGImage;
// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
self.size.width,
self.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, rect, imageRef);
// Get the resized image from the context and a UIImage
CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
// Clean up
CGContextRelease(bitmap);
CGImageRelease(newImageRef);
return newImage;
}
I think you mean that you want your image view to rotate around it's center point. Is that right? If so, that's what a view should do by default.
You should do a search on "Translating, Scaling, and Rotating Views" in Xcode and read the resulting article.
Note that all of iOS's angles are specified in radians, not degrees.
Your sample images aren't really helpful, since we can't see the frame that the image view is drawn into. It's almost impossible to tell what your image views are doing and what they are supposed to be doing instead based on the pictures you linked from your dropbox.
A full 360 degrees is 2pi.
You should use
CGFloat degrees = 45;
CGFloat radians = degrees/180*M_PI;
_fanImage.transform = CGAffineTransformMakeRotation(radians);
That will fix the rotation amount for your code, but probably not the rotation position.

Scaling an image is slow on an iPad 4th gen, are there faster alternatives?

I'm trying to zoom and translate an image on the screen.
here's my drawRect:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetShouldAntialias(context, NO);
CGContextScaleCTM (context, senderScale, senderScale);
[self.image drawAtPoint:CGPointMake(imgposx, imgposy)];
CGContextRestoreGState(context);
}
When senderScale is 1.0, moving the image (imgposx/imgposy) is very smooth. But if senderScale has any other value, performance takes a big hit and the image stutters when I move it.
The image I am drawing is a UIImageobject. I create it with
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
and draw a simple UIBezierPath(stroke):
self.image = UIGraphicsGetImageFromCurrentImageContext();
Am I doing something wrong? Turning off the anti-aliasing did not improve things much.
Edit:
I tried this:
rectImage = CGRectMake(0, 0, self.frame.size.width * senderScale, self.frame.size.height * senderScale);
[image drawInRect:rectImage];
but it was just as slow as the other method.
If you want this to perform well, you should let the GPU do the heavy lifting by using CoreAnimation instead of drawing the image in your -drawRect: method. Try creating a view and doing:
myView.layer.contents = self.image.CGImage;
Then zoom and translate it by manipulating the UIView relative to its superview. If you draw the image in -drawRect: you're making it do the hard work of blitting the image for every frame. Doing it via CoreAnimation only blits once, and then subsequently lets the GPU zoom and translate the layer.

cgcontext rotate rectangle

guys!
I need to draw some image to CGContext.This is the relevant code:
CGContextSaveGState(UIGraphicsGetCurrentContext());
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect rect = r;
CGContextRotateCTM(ctx, DEGREES_TO_RADIANS(350));
[image drawInRect:r];
CGContextRestoreGState(UIGraphicsGetCurrentContext());
Actually,the rectangle is rotate and display on a area what is not my purpose.I just want to
rotate the image and display on the same position.
Any ideas ?????
Rotation is about the context's origin, which is the same point that rectangles are relative to. If you imagine a sheet of graph paper in the background, you can see what's going on more clearly:
The line is the “bottom” (y=0) of your window/view/layer/context. Of course, you can draw below the bottom if you want, and if your context is transformed the right way, you might even be able to see it.
Anyway, I'm assuming that what you want to do is rotate the rectangle in place, relative to an unrotated world, not rotate the world and everything in it.
The only way to rotate anything is to rotate the world, so that's how you need to do it:
Save the graphics state.
Translate the origin to the point where you want to draw the rectangle. (You probably want to translate to its center point, not the rectangle's origin.)
Rotate the context.
Draw the rectangle centered on the origin. In other words, your rectangle's origin point should be negative half its width and negative half its height (i.e., (CGPoint){ width / -2.0, height / -2.0 })—don't use the origin it had before, because you already used that in the translate step.
Restore the gstate so that future drawing isn't rotated.
What worked for me was to first use a rotation matrix to calculate the amount of translation required to keep your image centered. Below I assume you've already calculated centerX and centerY to be the center of your drawing frame and 'theta' is your desired rotation angle in radians.
let newX = centerX*cos(theta) - centerY*sin(theta)
let newY = centerX*sin(theta) + centerY*cos(theta)
CGContextTranslateCTM(context,newX,newY)
CGContextRotateCTM(context,theta)
<redraw your image here>
Worked just fine for me. Hope it helps.
use following code to rotate your image
// convert degrees to Radians
CGFloat DegreesToRadians(CGFloat degrees)
{
return degrees * M_PI / 180;
};
write it in drawRect method
// create new context
CGContextRef context = UIGraphicsGetCurrentContext();
// define rotation angle
CGContextRotateCTM(context, DegreesToRadians(45));
// get your UIImage
UIImage *img = [UIImage imageNamed:#"yourImageName"];
// Draw your image at rect
CGContextDrawImage(context, CGRectMake(100, 0, 100, 100), [img CGImage]);
// draw context
UIGraphicsGetImageFromCurrentImageContext();

How to smooth edges of drawn image?

I'm using this code to colorize some images of a UIButton subclass:
UIImage *img = [self imageForState:controlState];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContextWithOptions(img.size, NO, 0.0f);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[self.buttonColor setFill];
CGContextSetAllowsAntialiasing(context, true);
CGContextSetShouldAntialias(context, true);
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to multiply, and the original image
CGContextSetBlendMode(context, kCGBlendModeScreen);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw the colored image
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the colored image
[self setImage:coloredImg forState:controlState];
But the images come out with rough edges. I've tried using screen, lighten, and plusLighter blend modes, because some of the images have white parts that I want to stay white. The only part I want colorized is the black areas. I've attached the original button images, and after they've been colorized. I can't get the edges to look good. When I had them as white images that were colorized using multiply blend mode, it looked much better. But I want to use black so I can use one method for colorizing images with and without white in them. I tried with anti-aliasing, that didn't help either. It looks like it just isn't anti-aliasing it. I haven't worked with Core Graphics enough to know what's up with it.
EDIT
Here's what the original PNGs look like:
and here's what it should look like:
and here's what it does look like:
The size if different, but you can see the bad quality around the edges.
Maybe your original icons (PNGs?) are just "too sharp"? Could you show us? You just draw the image at its original size without resizing, so the problem could be right from the start.
I'm not sure what is what you are trying to accomplish here. Are you trying to round the edges of the images? If so, you are better of by changing the round corner property of the UIButton's layer. Since UIButton is a subclass of UIView, you can get its layer property and change the edge color and round its corner.

Resources