Crop UIImage from a transformed UIImageView - ios

I am letting the user capture an image from the camera or picking one from the library.
This image I display in an UIImageView.
The user can now scale and position the image within a bounding box, exactly like you would do using the UIImagePickerController when allowsEditing is set to YES.
When the user is satisfied with the result and taps Done I would like to produce a cropped UIImage.
The problem arises when using CGImageCreateWithImageInRect as this does not take the scaling into account. The transform is applied to the imageView like this:
CGAffineTransform transform = CGAffineTransformScale(self.imageView.transform, newScale, newScale);
[self.imageView setTransform:transform];
Using a gestureRecognizer.
I assume what is happening is; the UIImageView is scaled and moved, it then applies the UIViewContentModeScaleAspectFit to the UIImage is holds and when I ask it to crop the image, it does exactly that - whit no regards to the scaling positioning. The reason I think this, is that if I don't scale or move the image but just tap Done straight away the cropping works.
I crop the image like this:
- (UIImage *)cropImage:(UIImage*) img toRect:(CGRect)rect {
CGFloat scale = [[UIScreen mainScreen] scale];
if (scale>1.0) {
rect = CGRectMake(rect.origin.x*scale , rect.origin.y*scale, rect.size.width*scale, rect.size.height*scale);
}
CGImageRef imageRef = CGImageCreateWithImageInRect([img CGImage], rect);
UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.imageView.image.scale orientation:self.imageView.image.imageOrientation];
// UIImage *result = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return result;
}
Passing in a cropRect from a view that is a subView of my main view (the square overlay box, like in UIImagePickerController). Main UIView has a UIImageView that gets scaled and a UIView that displays the crop rectangle.
How can I get the "what you see is what you get" cropping and which factors must I take into account. Or maybe suggestions if I should implemented the hierarchy or scaling differently.

Try a simple trick. Apple has got samples on its site to show how to zoom into a photo using code. Once done zooming, using graphic context take the frame size of the bounding view, and take the image with that. Eg Uiview contains scroll view which has the zoomed image. So the scrollview zooms and so does your image, now take the frame size of your bounding UIview, and create an image context out of it and then save that as a new image. Tell me if that makes sense.
Cheers :)

Related

UIImageView image aspect ratio is messed up after redrawing it to create a round mask

My app sends a GET request to google to attain certain user information. One piece of crucial returned data is a users picture which is placed inside a UIImageView that is always exactly (100, 100) then redrawn to create a round mask for this imageView. These pictures come from different sources and thus always have different aspect ratios. Some have a smaller width compared to their height, sometimes it's vice-versa. This results in the image looking compressed. I've tried things such as the following (none of them worked):
_personImage.layer.masksToBounds = YES;
_personImage.layer.borderWidth = 0;
_personImage.contentMode = UIViewContentModeScaleAspectFit;
_personImage.clipsToBounds = YES;
Here is the code I use to redraw my images (it was attained from user fnc12 as the third answer in Making a UIImage to a circle form):
/** Returns a redrawn image that had a circular mask created for the inputted image. */
-(UIImage *)roundedRectImageFromImage:(UIImage *)image size:(CGSize)imageSize withCornerRadius:(float)cornerRadius
{
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0); //<== Notice 0.0 as third scale parameter. It is important because default draw scale ≠ 1.0. Try 1.0 - it will draw an ugly image...
CGRect bounds = (CGRect){CGPointZero, imageSize};
[[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius] addClip];
[image drawInRect:bounds];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return finalImage;
}
This method is always called like so:
[_personImage setImage:[self roundedRectImageFromImage:image size:CGSizeMake(_personImage.frame.size.width, _personImage.frame.size.height) withCornerRadius:_personImage.frame.size.width/2]];
So I end up having a perfectly round image but the image it self isn't right aspect-wise. Please help.
P.S. Here's how images look when their width is roughly 70% that of their height before the redrawing of the image to create a round mask:
Hello dear friend there!
Here is my version that works:
Code in ViewController:
[self.profilePhotoImageView setContentMode:UIViewContentModeCenter];
[self.profilePhotoImageView setContentMode:UIViewContentModeScaleAspectFill];
[CALayer roundView:self.profilePhotoImageView];
roundView function in My CALayer+Additions class:
+(void)roundView:(UIView*)view{
CALayer *viewLayer = view.layer;
[viewLayer setCornerRadius:view.frame.size.width/2];
[viewLayer setBorderWidth:0];
[viewLayer setMasksToBounds:YES];
}
May be you should try to change your way to create rounded ImageView using my version that create rounded ImageView by modifying ImageView's view layer . Hope it helps.
To maintain aspect ratio of UIImageView, after setting image use following line of code.
[_personImage setContentMode:UIViewContentModeScaleAspectFill];
For detailed description follow reference link:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImageView_Class/

ios - Can crop photo vertical but not horizontal

I have a UIScrollView with a UIImageView inside of it. For this part of my app, the user can select photos from their camera roll and scale and crop them.
I have successfully made the user be able select different photos, then zoom in and out & pan around the image. Also, the user can zoom out to make the image centre vertically or horizontally depending on if the image is portrait or landscape.
The problem is, I try to then crop the photo from the visible rect in the scroll view to a new image, however its only working for portrait photos.
Here is an example of it working then not working:
Here is a portrait image that is zoomed out to fit the screen:
Next, I zoom in the image so there is no black space.
Finally, I crop the photo and you can see it crops perfectly in the top left hand corner.
However, for some reason when I try to do this with a landscape image the cropping messes up?! Here is an example of it not working.
Here is a zoomed out landscape image.
Next, I zoom in so there is no black space left. Notice how I zoomed in specifically so there is no physical boarder of the white board visible in the photo.
Now, I crop the photo just like before and it doesn't crop it properly. Notice how in the top left hand corner the image is different from before. It appears to have been zoomed out and you can see more of the bottom of the white board.
I need to figure out why this is happening and how to fix it.
Here is the exact code I use to crop the photo from the UIScrollView.
//Get the scale
float scale = 1.0f/_libraryScrollView.zoomScale;
//Create a new rect
CGRect visibleRect;
visibleRect.origin.x = _libraryScrollView.contentOffset.x * scale;
visibleRect.origin.y = _libraryScrollView.contentOffset.y * scale;
visibleRect.size.width = _libraryScrollView.bounds.size.width * scale;
visibleRect.size.height = _libraryScrollView.bounds.size.height * scale;
//Get the source image
UIImage *src = libraryPreviewImageView.image;
//Create the new cropped image with the rect
CGImageRef cr = CGImageCreateWithImageInRect(src.CGImage, visibleRect);
UIImage *finalImage = [[UIImage alloc]initWithCGImage:cr];
//Set the new image to the preview image view
self.imagePreviewView.image = finalImage;
This code works for portrait images but doesn't work for landscape images as shown above in the examples. Is this error to do with my cropping code or is it to do with something else?
Any help would be appreciated.
In the end, I had no idea what was the problem but trying to use maths to crop an image from a scroll view is extremely difficult!
I found a really easy way and that is to take a screen shot of the visible content in the scroll view, its as easy as this:
UIGraphicsBeginImageContextWithOptions(_libraryScrollView.bounds.size, YES, [UIScreen mainScreen].scale);
CGPoint offset = _libraryScrollView.contentOffset;
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y);
[_libraryScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Set the new image to the preview image view
self.imagePreviewView.image = finalImage;
I really hope this answer can help other people out too!

Crop an area of oversized image to what is currently showing onscreen

I have an oversized image loaded in a image view that goes out of bounds both vertically and horizontally.
The end user can scroll around the image (the oversized imageview is in a scrollview) and when they find an area that they like I would like to crop out the area of the image that is shown on the screen. (much like a screenshot but only of the imageview.image I'm then going to put that into a different Imageview.
I can't seem to work out how to accomplish the "screenshot" of the area of the image view's image that is currently showing on the screen.
You can use CGImageCreateWithImageInRect to create a subimage of the displayed image. Use contentOffset and the scrollViews bounds to create the rect from which you want to create the image.
CGRect rect = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, CGRectGetWidth(scrollView.bounds), CGRectGetHeight(scrollView.bounds));
CGImageRef subImageRef = CGImageCreateWithImageInRect([originalImage CGImage], rect);
If you zoom your scrollView you will need to take the zoomLevel into account too.
I ended up using the following code to achieve what I was looking for to grab the image. Thank you to Karl for his input and a thank you to iNoob whom answer to a previous question [Located here on StackOverflow][1] I used for mine.
Just use the below code to take a "screenshot" just set anything you don't want in the image to.hidden = True; before the code to hide it from the screenshot and set them to .Hidden = FALSE; after the code to bring them back.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

How to apply custom zoom to UIImagePicker camera?

I have an custom camera control having slider to apply zoom. I am able to zoom image with following code:
self.pickerReference.cameraViewTransform = CGAffineTransformScale(CGAffineTransformIdentity, zoom, zoom);
But when i get image in didFinishPickingMediaWithInfo I get original image for UIImagePickerControllerOriginalImage, not the zoomed one. And for UIImagePickerControllerEditedImage there is no image.
I have also tried:
currentImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
UIImageView *v = [[UIImageView alloc]initWithImage:currentImage];
UIGraphicsBeginImageContext(v.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextScaleCTM(context, zoom, zoom);
[v drawRect:pickerReference.view.bounds];
CGContextRestoreGState(context);
zoomedCurImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Write image to PNG file
[UIImageJPEGRepresentation(zoomedCurImg, 0.4) writeToFile:imgPath atomically:YES];
This does apply zoom to original image but zoom is applied always at top left corner & not to where it is to be applied.
Please suggest solution. Thanks in advance.
I had a similar issue with a different piece of code and turning off auto layout fixed it for me. Not sure if that applies here but it's worth a shot.

How to truncate a UIImage in iOS

How can I truncate the left side of an image stored in a UIImage object. Basically in certain situations I just want to show part of an image.
How can I do this on with the iOS sdk?
P.S. I tried changing the frame size of the UIImage but that just scales the image and distorts it.
A very simple way is to load the image into a UIImageView, and then add the view to another view. You can then position the image view so that its .frame.origin.x property is negative, which will place it off to the left. The parent view needs to have setMasksToBounds:YES called on it, or else the image view will still be fully-visible.
There are many other ways to achieve this effect as well, but this may be the simplest for you to implement.
to crop a UIImage, you can use one of the UIImage categories available out there, such as http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/
For example, this frame will remove 100 pixel from the left side of a 200x200 pixel UIImage
CGRect clippedRect = CGRectMake(100, 0, 100, 200);
UIImage *cropped = [self imageByCropping:lightsOnImage toRect:clippedRect];

Resources