UIImage loses quality when rotated - iphone

I am using this code to rotate UIImage.
CGFloat DegreesToRads(CGFloat degrees) {
return degrees * M_PI / 180;
}
- (UIImage *)scaleAndRotateImage:(UIImage *)image forAngle: (double) angle {
float radians=DegreesToRads(angle);
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, image.size.width, image.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(radians);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef 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, rotatedSize.height/2);
//Rotate the image context
CGContextRotateCTM(bitmap, radians);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-image.size.width/2, -image.size.height/2 , image.size.width, image.size.height), image.CGImage );
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Works ok, but the quality of image is worse after rotation. What could be the cause?

try
UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, 2.0)
from apple documentation:
void UIGraphicsBeginImageContextWithOptions(
CGSize size,
BOOL opaque,
CGFloat scale
);
Parameters
size The size (measured in points) of the new bitmap context. This represents the size of the image returned by the UIGraphicsGetImageFromCurrentImageContext function. To get the size of the bitmap in pixels, you must multiply the width and height values by the value in the scale parameter.
opaque
A Boolean flag indicating whether the bitmap is opaque. If you know the bitmap is fully opaque, specify YES to ignore the alpha channel and optimize the bitmap’s storage. Specifying NO means that the bitmap must include an alpha channel to handle any partially transparent pixels.
scale
The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
bye :)

Related

Crop image using border frame

I am trying to crop image using rectangle frame. But somehow not able to do that according to its required.
Here is What i am trying:
Here is the result i want :
Now what i need is when click on done image should crop in rectangle shape exactly placed in image. I have tried few things like masking & draw image using mask image rect but no success yet.
Here is my code which is not working :
CALayer *mask = [CALayer layer];
mask.contents = (id)[imgMaskImage.image CGImage];
mask.frame = imgMaskImage.frame;
imgEditedImageView.layer.mask = mask;
imgEditedImageView.layer.masksToBounds = YES;
Can anyone suggest me the better way to implement it.
I have tried so many other things & wasted time so please if i get some help that it will be great & appreciated.
Thanks.
- (UIImage *)croppedPhoto {
// For dealing with Retina displays as well as non-Retina, we need to check
// the scale factor, if it is available. Note that we use the size of teh cropping Rect
// passed in, and not the size of the view we are taking a screenshot of.
CGRect croppingRect = CGRectMake(imgMaskImage.frame.origin.x,
imgMaskImage.frame.origin.y, imgMaskImage.frame.size.width,
imgMaskImage.frame.size.height);
imgMaskImage.hidden=YES;
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(croppingRect.size, YES,
[UIScreen mainScreen].scale);
} else {
UIGraphicsBeginImageContext(croppingRect.size);
}
// Create a graphics context and translate it the view we want to crop so
// that even in grabbing (0,0), that origin point now represents the actual
// cropping origin desired:
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, -croppingRect.origin.x, -croppingRect.origin.y);
[self.view.layer renderInContext:ctx];
// Retrieve a UIImage from the current image context:
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Return the image in a UIImageView:
return snapshotImage;
}
Here is the way you do
+(UIImage *)maskImage:(UIImage *)image andMaskingImage:(UIImage *)maskingImage{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef maskImageRef = [maskingImage CGImage];
CGContextRef mainViewContentContext = CGBitmapContextCreate (NULL, maskingImage.size.width, maskingImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
if (mainViewContentContext==NULL)
return NULL;
CGFloat ratio = 0;
ratio = maskingImage.size.width/ image.size.width;
if(ratio * image.size.height < maskingImage.size.height) {
ratio = maskingImage.size.height/ image.size.height;
}
CGRect rect1 = {{0, 0}, {maskingImage.size.width, maskingImage.size.height}};
//// CHANGE THIS RECT ACCORDING TO YOUR NEEDS
CGRect rect2 = {{-((image.size.width*ratio)-maskingImage.size.width)/2 , -((image.size.height*ratio)-maskingImage.size.height)/2}, {image.size.width*ratio, image.size.height*ratio}};
CGContextClipToMask(mainViewContentContext, rect1, maskImageRef);
CGContextDrawImage(mainViewContentContext, rect2, image.CGImage);
CGImageRef newImage = CGBitmapContextCreateImage(mainViewContentContext);
CGContextRelease(mainViewContentContext);
CGColorSpaceRelease(colorSpace);
UIImage *theImage = [UIImage imageWithCGImage:newImage];
CGImageRelease(newImage);
return theImage;
}
You need to have image like this
Note that
The mask image cannot have ANY transparency. Instead, transparent areas must be white or some value between black and white. The more towards black a pixel is the less transparent it becomes.

iphone stroke path used for clipping UIImage

I'm very new to CoreGraphics (although I've been doing iphone programming for a while)
Question, I have this snippet that scales proportionally and clips an UIImage to a circle:
-(UIImage *)counterpartImageForSchedule:(Schedule *)counterpartSchedule inSize:(CGSize)size
{
// This function returns a newImage, based on image, that has been:
// - scaled to fit in (CGRect) rect
// - and cropped within a circle of radius: rectWidth/2
UIImage *image=[UIImage imageNamed:#"fakeuser1.png"];
// when kendy sends hash, check that this image is not on the cache, otherwise download, clip & stylized
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
//Get the width and heights
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
CGFloat rectWidth = size.width;
CGFloat rectHeight = size.height;
//Calculate the scale factor
CGFloat scaleFactorX = rectWidth/imageWidth;
CGFloat scaleFactorY = rectHeight/imageHeight;
if (scaleFactorX>scaleFactorY) {
scaleFactorY=scaleFactorX;
} else
{
scaleFactorX=scaleFactorY;
}
//Calculate the centre of the circle
CGFloat imageCentreX = rectWidth/2;
CGFloat imageCentreY = rectHeight/2;
// Create and CLIP to a CIRCULAR Path
// (This could be replaced with any closed path if you want a different shaped clip)
CGFloat radius = rectWidth/2;
CGContextBeginPath (context);
CGContextAddArc (context, imageCentreX, imageCentreY, radius, 0, 2*M_PI, 0);
CGContextClosePath (context);
CGContextClip (context);
//Set the SCALE factor for the graphics context
//All future draw calls will be scaled by this factor
CGContextScaleCTM (context, scaleFactorX, scaleFactorY);
// the stroke
// Draw the IMAGE
CGRect myRect = CGRectMake(0, 0, imageWidth, imageHeight);
[image drawInRect:myRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Question is, how can I stroke the path I'm using to clip the image (say, 4 pixels with black or white color)? do i need to draw a new one?
any help is much appreciated!
A path can be an object like any other - in this case, a CGPath (CGPathRef). Before using the path for anything, encapsulate it as a CGPath (in this case, probably a CGMutablePathRef, or perhaps you can call CGContextCopyPath before using the path to clip to). Now you can reuse that path.
Here's an example from one of my apps where I form a path, then stroke it, and then clip to the same path (c is the graphics context):
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, CGRectGetMaxX(r) - radius, ins);
CGPathAddArc(path, nil,
radius+ins, radius+ins, radius, -M_PI/2.0, M_PI/2.0, true);
CGPathAddArc(path, nil,
CGRectGetMaxX(r) - radius, radius+ins, radius, M_PI/2.0, -M_PI/2.0, true);
CGPathCloseSubpath(path);
CGContextAddPath(c, path);
CGContextSetLineWidth(c, 2);
CGContextStrokePath(c);
CGContextAddPath(c, path);
CGContextClip(c);
CGPathRelease(path);
Another possibility is to use UIBezierPath - a full-fledged Objective-C object, instead of CGContext functions. It encapsulates a CGPath and you can reuse that path - clip to it, then stroke it. Or the other way round.

crop a rotated UIImage

I have the exact problem as described here:
crop a rotated UIImage.
I need to crop a rotated UIImage, however, when I try the solution it doesn't crop the image
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:videoPreviewView.frame];
NSLog(#"frame width: %f height:%f x:%f y:%f",videoPreviewView.frame.size.width, videoPreviewView.frame.size.height,videoPreviewView.frame.origin.x,videoPreviewView.frame.origin.y);
rotatedViewBox.transform = CGAffineTransformMakeRotation(90 * M_PI / 180);
CGSize rotatedSize = rotatedViewBox.frame.size;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0f, rotatedSize.height / 2.0f);
CGContextRotateCTM(bitmap, 90 * M_PI / 180);
CGContextScaleCTM(bitmap, 1.0f, -1.0f);
CGContextDrawImage(bitmap, CGRectMake(-videoPreviewView.frame.size.width / 2.0f,
-videoPreviewView.frame.size.height / 2.0f,
videoPreviewView.frame.size.width,
videoPreviewView.frame.size.height),
image.CGImage);
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
The log is:
frame width:310 height:310 x:0 y: 69
The rotation works though but the new image is not cropped on 0,69,310,310 of the old image.
You are using a "solution" which, although accepted, also carries the OP comment "but it's not working."
The solution only claims to deal with the rotation part of the problem, not the crop. It's doing what it claims to do, but no more.
Here's a CG function that performs a crop:
CGImageRef CGImageCreateWithImageInRect (
CGImageRef image,
CGRect rect
);
Input you image and the rect of the region you want to crop to.
See the answer here for an example use:
Cropping an UIImage

UIImage iPhone Rotate 37.8 degrees

After I load an image from the device, I need to rotate it 37.8 degrees then display it on a View.
Is there an function in Objective-C that can do the image rotation?
Ian
To rotate the view:
imageView.transform = CGAffineTransformMakeRotation(37.8°);
To rotate the image,
Calculate the width and height will be occupied by the image after rotation.
Create a CGContext by UIGraphicsBeginImageContext.
CGContextRotateCTM(UIGraphicsGetCurrentContext(), 37.8°);
[yourImage drawAtPoint:...];
UIGraphicsGetImageFromCurrentImageContext(); and use this image instead.
Release the context.
Yes, see my answer to this question: Question about rotating a slider
To convert degrees to radians (for the positionInRadians arg) use this function:
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
To rotate the image, try this:
-(IBAction)rotateImageClick:(id)sender{
UIImage *image2=[[UIImage alloc]init];
image2 = [self imageRotatedByDegrees:self.roateImageView.image deg:(90)]; //Angle by 90 degree
self.roateImageView.image = image2;
imgData= UIImageJPEGRepresentation(image2,0.9f);
}
This method allows you to rotate an image an arbitrary amount:
- (UIImage *)imageRotatedByDegrees:(UIImage*)oldImage deg:(CGFloat)degrees{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,oldImage.size.width, oldImage.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(degrees * M_PI / 180);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef 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, rotatedSize.height/2);
// // Rotate the image context
CGContextRotateCTM(bitmap, (degrees * M_PI / 180));
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(-oldImage.size.width / 2, -oldImage.size.height / 2, oldImage.size.width, oldImage.size.height), [oldImage CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
See this link for more information.

Drawing half image

Hi all i am having .png image.I want to draw only half of this image.If i call method drawInRect: on image with width being half the size of image,it will still draw the full image
in given rect.So how to draw half image
Before calling -drawInRect, try setting a clip mask on the current context:
UIImage *image = // your image, let's say 100x100
CGRect drawingRect = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f); // adjust the origin; size has to be the image's size
CGRect clippingRect = drawingRect; // copy drawingRect...
clippingRect.size.width = 50.0f; // ...and reduce the width
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context); // save current graphics state
CGContextClipToRect(context, clippingRect);
[image drawInRect:drawingRect];
CGContextRestoreGState(context); // restore previous state (without clip mask)
If it's in a UIImageView, you can change the frame to only fit half the image, then set [imageView setClipsToBounds:YES].
You could crop your existing image by using CGImageCreateWithImageInRect
Clip Rect did the magic. Thanks #thomas
CGContextClipToRect(context, clippingRect);