Cropping an iPhone camera photo in ios programmatically - ios

I have the portrait version working fine as the scale is 0.75. But I cannot get the landscape to work correctly. I am using UIImagePickerController.
// Landscape
// Full landscape image is width: 3264 and height 2448
CGRect cropped = CGRectMake(306.0, 0.0, 1836.0, 2448.0);
CGImageRef imageRef = CGImageCreateWithImageInRect ([photo CGImage], cropped);
// UIImage * croppedPhoto = [UIImage imageWithCGImage: imageRef];
UIImage * croppedPhoto = [UIImage imageWithCGImage:imageRef scale:photo.scale orientation:UIImageOrientationUp];
CGImageRelease (imageRef);
// Scale the photo down
CGRect rect = CGRectMake(0.0, 0.0, 450.0, 600.0);
UIGraphicsBeginImageContext( rect.size );
[croppedPhoto drawInRect:rect];
picture = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
I have the following issues:
I want the edges cut off to make the landscape into a portrait (the center part of the landscape needs to be converted to portrait).
Depending on which way I hold the device, the image is either upside down or correct.
What am I doing wrong?

Related

CGImageCreateWithImageInRect not cropping at correct position

I have a scenario in my app where I take a screenshot of the video using
[myMovieController requestThumbnailImagesAtTimes:#[#(myMovieController.currentPlaybackTime)] timeOption:MPMovieTimeOptionExact];
which just works fine. Then I have to crop the image with touched location on the video. I have added gesture recognizer of myMovieController. I get the touch location from the gesture Recognizer.
then I use following code to take the screen shot
CGRect cropRect = tapCircleView.frame;
cropRect = CGRectMake(touchPoint.x * image.scale,
touchPoint.y * image.scale,
cropRect.size.width * image.scale,
cropRect.size.height * image.scale);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect) ;
UIImage* cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
[self showImage:cropped];
where cropRect width and height is 150.
But crop result is not with correct x and y. And also resulting image is very pixilated.
I have tried every solution but it's not working.
What is it that I am missing?
Thanks.
The image size which captures screenshot is not same as device size on which application is running.
So instead of using same image, change size of image using following code :
CGRect rect = CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
UIGraphicsBeginImageContext( rect.size );
[image drawInRect:rect];
UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(picture1);
UIImage *img=[UIImage imageWithData:imageData];
And now just use this image wherever you want !!
Cheers.

How to do properly cropping of UIImage taken with UIImagePickerController?

This is camera overlay for my app,
The yellow square is to indicate user that only photo inside this part (in camera) will be saved. It's like crop.
When I saved that capture image, it'll save zoomed photo [a big zoomed on photo],
What I found is, when I took a photo, it'll be of size of {2448, 3264}
I'm cropping the image like this,
- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
double x = (image.size.width - size.width) / 2.0;
double y = (image.size.height - size.height) / 2.0;
CGRect cropRect = CGRectMake(x, y, size.height, size.width);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
if (image) {
UIImage *newImage = [self imageByCroppingImage:image toSize:CGSizeMake(300.f, 300.f)];
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil);
}
}
Notes,
Orientation was fixed before perform cropping. Using this, http://pastebin.com/WYUkDLS0
That yellow square on camera is also same size that's width=300 and height=300.
If I'll set front camera for UIImagePickerController then it'll give me perfect output of cropped image. Yes this is really strange!
I've tried everything from here, Cropping an UIImage. Even https://github.com/Nyx0uf/NYXImagesKit won't help.
Any idea/suggestions?
Update:
From this question, Trying to crop my UIImage to a 1:1 aspect ratio (square) but it keeps enlarging the image causing it to be blurry. Why?
I followed the answer of #DrummerB like this,
CGFloat originalWidth = image.size.width * image.scale;
CGFloat originalHeight = image.size.height * image.scale;
float smallestDimension = fminf(originalWidth, originalHeight);
CGRect square = CGRectMake(0, 0, smallestDimension, smallestDimension);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], square);
UIImage *squareImage = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
UIImageWriteToSavedPhotosAlbum(squareImage, nil, nil, nil);
CGImageRelease(imageRef);
This is what I captured,
And it result me the following,
Now I'm getting the square photo, but note in output, still I'm getting photo outside that yellow square. What I want is to get photo which is reside in yellow square. Captured image is still of size, {w=2448, h=3264}. Note, that red circles which indicate outer part of image which should not include in output as that part is not inside yellow square.
What's wrong in this?
It looks like the image you are receiving in your implementation is returning an image crop of 300 by 300 pixels. The yellow square you have on screen is 300 by 300 points. Points are not the same as pixels. So if your photo 3264 pixels wide, then cropping it to 300 pixels would return an image of about 1/10th the original size.

Crop a Portion of UIImage from Larger UIImage, and include non-image parts

I think I may have an odd request, however hopefully someone can help. I am using the well known UIScrollView + UIImageView to zoom into and out of an image, as well as pan. This works fine and dandy, but the current project we have needs to be able to crop the image, but also include the black bars on the sides if the image is smaller than the crop rectangle. See the images below.
We wish to capture everything inside of the blue box, including the white (which will be black, since opaque is set to YES).
This works great for images that are completely zoomed out (The white is just the UIImageView's extra space).
However the problem arises when we try to zoom into the image, and capture only that portion, plus the empty space.
This results in the following image
The problem we are seeing is we need to be able to create an image that is exactly what is in the Crop Rect, regardless if there is part of the image there or not. The other problem is we wish to have the ability to dynamically change the output resolution. The aspect ratio is 16:9, and for this example kMaxWidth = 1136 and kMaxHeight = 639, however in the future we may want to request a larger or smaller 16:9 resolution.
Below is the function I have so far:
- (UIImage *)createCroppedImageFromImage:(UIImage *)image {
CGSize newRect = CGSizeMake(kMaxWidth, kMaxHeight);
UIGraphicsBeginImageContextWithOptions(newRect, YES, 0.0);
// 0 is the edge of the screen, to help with zooming
CGFloat xDisplacement = ((abs(0 - imageView.frame.origin.x) * kMaxWidth) / (self.cropSize.width / self.scrollView.zoomScale) / self.scrollView.zoomScale);
CGFloat yDisplacement = ((abs(self.cropImageView.frame.origin.y - imageView.frame.origin.y) * kMaxHeight) / (self.cropSize.height / self.scrollView.zoomScale) / self.scrollView.zoomScale);
CGFloat newImageWidth = (self.image.size.width * kMaxWidth) / (self.cropSize.width / self.scrollView.zoomScale);
CGFloat newImageHeight = (self.image.size.height * kMaxHeight) / (self.cropSize.height / self.scrollView.zoomScale);
[image drawInRect:CGRectMake(xDisplacement, 0, newImageWidth, newImageHeight)];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
Any help would be greatly appreciated.
I ended up just taking a screenshot, and cropping that. It seems to work well enough.
- (UIImage *)cropImage {
CGRect cropRect = self.cropOverlay.cropRect;
UIGraphicsBeginImageContext(self.view.frame.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *fullScreenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRef croppedImage = CGImageCreateWithImageInRect(fullScreenshot.CGImage, cropRect);
UIImage *crop = [[UIImage imageWithCGImage:croppedImage] resizedImage:self.outputSize interpolationQuality:kCGInterpolationHigh];
CGImageRelease(croppedImage);
return crop;
}
If using iOS 7, you would use drawViewHierarchyInRect:afterScreenUpdates:, instead of renderInContext:
I think the translated rect for the image view isn't calculated properly. Since UIImageView is the subview inside the UIScrollView, you should be able to calculate the visible rect by calling [scrollView convertRect:scrollView.bounds toView:imageView];. That will be the visible rect of your image view. All you need to now is crop it.
-(UIImage*)cropImage:(UIImage*)img inRect:(CGRect)rect{
CGImageRef cropped = CGImageCreateWithImageInRect(img.CGImage, rect);
UIImage *image = [UIImage imageWithCGImage:cropped];
CGImageRelease(cropped);
return image;
}
Edit: Yeah... I forgot to mention that cropping should be done in (0,1) coordinate space. I've modified the crop function for you, so it crops the image based on all parameters you provided, UIImageView inside UIScrollView and an image.
-(UIImage*)cropImage:(UIImage*)image inImageView:(UIImageView*)imageView scrollView:(UIScrollView*)scrollView{
// get visible rect from image scrollview
CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:imageView];
UIImage* rCroppedImage;
CALayer* maskLayer= [[CALayer alloc] init];
maskLayer.contents= (id)image.CGImage;
maskLayer.frame= CGRectMake(0, 0, visibleRect.size.width, visibleRect.size.height);
CGRect rect= CGRectMake(visibleRect.origin.x / image.size.width,
visibleRect.origin.y / image.size.height,
visibleRect.size.width / image.size.width,
visibleRect.size.height / image.size.height);
maskLayer.contentsRect= rect;
UIGraphicsBeginImageContext(visibleRect.size);
CGContextRef context= UIGraphicsGetCurrentContext();
[maskLayer renderInContext:context];
rCroppedImage= UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return rCroppedImage;
}

Crop and save visible region of UIImageView using AspectFill

I have a fullscreen UIImageView with a image in it set to AspectFill (full bleed), how can I save only the visible portion of the image when its using the Aspect Fill content mode?
CGRect visibleRect;
visibleRect.size= mImageView.frame.size;
CGImageRef cropped_img = CGImageCreateWithImageInRect(mImageView.image.CGImage, visibleRect);
UIImage *finalImage = [[UIImage alloc]initWithCGImage:cropped_img];
UIImageWriteToSavedPhotosAlbum(finalImage, nil, nil, nil);
This is my current code, cropping and saving works, its just not cropping correctly. Any ideas?
Try this:
UIGraphicsBeginImageContext(mImageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef image = CGBitmapContextCreateImage(context);
width = CGImageGetWidth(image);
height = CGImageGetHeight(image);
CGImageRef cropped_img = CGImageCreateWithImageInRect(image, CGRectMake(0, 0, width, height));
// save...
CGImageRelease(image);
UIGraphicsEndImageContext();

Cropping and scaling a UIImage properly

I'm trying to crop a image into a square shape, and then scale it to a size 200x200. Here's the code I use, but it's not really working for me. The image I get is sometimes in a different orientation, or isn't cropped from the center, or is wider than it should be.
float scale = _avatar.image.scale;
UIImageOrientation orientation = _avatar.image.imageOrientation;
if(_avatar.image.size.width < _avatar.image.size.height){ // avatar is a UIImageView
float startingY = (_avatar.image.size.height-_avatar.image.size.width)/2; // image is taller, determine the origin of the width-sized square, which will be the new image
CGImageRef imageRef = CGImageCreateWithImageInRect([_avatar.image CGImage], CGRectMake(0, startingY, _avatar.image.size.width, _avatar.image.size.width));
_avatar.image = [UIImage imageWithCGImage:imageRef scale:scale orientation:orientation];
CGImageRelease(imageRef);
} else {
float startingX = (_avatar.image.size.width-_avatar.image.size.height)/2; // image is wider, determine the origin of the height-sized square, which will be the new image
CGImageRef imageRef = CGImageCreateWithImageInRect([_avatar.image CGImage], CGRectMake(startingX, 0, _avatar.image.size.height, _avatar.image.size.height));
_avatar.image = [UIImage imageWithCGImage:imageRef scale:scale orientation:orientation];
CGImageRelease(imageRef);
}
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), YES, 0.0);
[_avatar.image drawInRect:CGRectMake(0, 0, 200, 200)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
How it must be done to achieve the correct result?
I would suggest you to use this category for UIImage posted on github. They are also really simple classes and you can also use them to learn what is under the hood.
The UIImage has done all the coordinate and orientation tricks for you. So you should not use the width and height from an UIImage object to caculate the square's coordinate. You can take advantages of the UIKit to crop an image.
CGFloat startingX = 0;
CGFloat startingY = 0;
CGFloat squareWidth;
if(_avatar.image.size.width < _avatar.image.size.height){ // avatar is a UIImageView
startingY = (_avatar.image.size.height-_avatar.image.size.width)/2; // image is taller, determine the origin of the width-sized square, which will be the new image
squareWidth = _avatar.image.size.width;
} else {
startingX = (_avatar.image.size.width-_avatar.image.size.height)/2; // image is wider, determine the origin of the height-sized square, which will be the new image
squareWidth = _avatar.image.size.height;
}
UIGraphicsBeginImageContextWithOptions(CGSizeMake(squareWidth, squareWidth), YES, 0.0);
[_avatar.image drawAtPoint:CGPointMake(-startingX, -startingY)]; // Make an offset to draw part of the image
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), YES, 0.0);
[croppedImage drawInRect:CGRectMake(0, 0, 200, 200)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Resources