CGImageCreateWithImageInRect not cropping properly - ios

I have an image which I want to cut in half, so that it is only the bottom half of the image. I've been trying to do this by cropping the image, however it doesn't seem to be doing anything, the image is the same size, no matter what crop I apply to it. Is there something that I'm doing wrong in my implementation? My code is below.
NSString *imageString = [NSString stringWithFormat:#"grey_%#", imagePath];
greyImage = [UIImage imageNamed:imageString];
int width = greyImage.size.width;
int height = greyImage.size.height;
CGRect myRect = CGRectMake(0, 0, width, height / 2);
CGImageRef ref = CGImageCreateWithImageInRect([greyImage CGImage], myRect);
cropGrey = [UIImage imageWithCGImage:ref scale:greyImage.scale orientation:greyImage.imageOrientation];
CGImageRelease(ref);
[self addCreatedImage:greyImage toSubview:badgeView atX:30 atY:30 atWidth:badgeViewWidth - 60 atHeight:(badgeViewWidth - 60) / 2 isRounded:NO];
Whether I use greyImage, or cropGrey the image shows up exactly the same. I'm not sure why this is, any help would be appreciated. Thank you!

Related

ios 7:How to show images from photo album without strectch while placing it in uiimageview in larger size

My task is to get the images from photo album and show it in one ViewController which has one UIImageView in full screen. The problem am facing here is while showing the small size photos captured in camera are getting stretched when it comes to UIImageView
I have tried with all aspect mode for keeping the image as normal. but no luck
Thanks in advance!!
If you want the image selected from Photo Album with same size then
self.photoImgView.contentMode=UIViewContentModeScaleAspectFit;// is best
self.photoImgView.contentMode=UIViewContentModeScaleAspectFill; //if you want to fill the large imageview size with selected photo
self.photoImgView.contentMode=UIViewContentModeScaleToFill; // if you want to fill the large imageview size with selected photo
Else you can try with below solution for resizing image before assigning to imageview.
UIImage *uiImage=[info valueForKey:#"UIImagePickerControllerOrignalImage"];//UIImagePickerControllerEditedImage
CGSize size;
NSData *imageData;
imageData= UIImageJPEGRepresentation(uiImage, 1.0);
UIImage *galleryImage=[self squareImageWithImage:[UIImage imageWithData:imageData] scaledToSize:CGSizeMake(320, 320)];
photoImgView.image=galleryImage;
-(UIImage *)squareImageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
double ratio;
double delta;
CGPoint offset;
//make a new square size, that is the resized imaged width
CGSize sz = CGSizeMake(newSize.width, newSize.width);
//figure out if the picture is landscape or portrait, then
//calculate scale factor and offset
if (image.size.width > image.size.height) {
ratio = newSize.width / image.size.width;
delta = (ratio*image.size.width - ratio*image.size.height);
offset = CGPointMake(delta/2, 0);
} else {
ratio = newSize.width / image.size.height;
delta = (ratio*image.size.height - ratio*image.size.width);
offset = CGPointMake(0, delta/2);
}
//make the final clipping rect based on the calculated values
CGRect clipRect = CGRectMake(-offset.x, -offset.y,
(ratio * image.size.width) + delta,
(ratio * image.size.height) + delta);
//start a new context, with scale factor 0.0 so retina displays get
//high quality image
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
} else {
UIGraphicsBeginImageContext(sz);
}
UIRectClip(clipRect);
[image drawInRect:clipRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Hope it helps you..
Set the content mode of your image view. Try this:
imageView.contentMode = UIViewContentModeScaleAspectFit;
Hope this helps.. :)
I assume when you say
"I have tried with all aspect mode for keeping the image as normal. but no luck"
You mean you used the contentMode or UIImageView?
e.g.
self.myImageView.contentMode = UIViewContentModeScaleAspectFit;
or one of the others AspectFill is another common one fit letterboxes I think and fill scales past the edge until the entire screen is filled.
But if your image is too small then it is going to look stretched even if the aspect ratio is correct, as there just wont be enough data for a full image
I would use:
UIImageView *someImage = [UIImageView new];
someImage.contentMode = UIViewContentModeScaleAspectFill;
someImage.clipsToBounds = YES;

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;
}

Cropping and placing image to achieve battery level effect

I am trying to achieve the battery level effect by drawing on a plain battery image another cropped image based on current battery level.
At the moment I am able to change the colour of the empty battery image but I don't know how to crop, the new one, and place it on top of the original.
I've found some useful links on how to crop but, every single of them, is cropping from top-left corner of the image. I would like to have as a starting point the bottom-left and set the height according to current level.
In addition, it is possible to combine or place the cropped image on top of the original?
Here is my original image.
...and what I am trying to achieve
At the moment I am trying this code,
int width = emptyBm.size.width;
int height = fullBm.size.height * level / 100;
UIImage *image = [UIImage imageNamed:#"battery_icon"];
UIImage *image2 = [UIImage imageNamed:#"battery_icon_full"];
CGRect rect = CGRectMake(0, image.size.height-height, width, height);
CGImageRef imageRef = CGImageCreateWithImageInRect([image2 CGImage], rect);
CGImageRef actualMask = CGImageMaskCreate(CGImageGetWidth([image CGImage]),
CGImageGetHeight([image CGImage]),
CGImageGetBitsPerComponent([image CGImage]),
CGImageGetBitsPerPixel([image CGImage]),
CGImageGetBytesPerRow([image CGImage]),
CGImageGetDataProvider([image CGImage]), NULL, false);
CGImageRef masked = CGImageCreateWithMask(imageRef, actualMask);
batteryBackground.image = [UIImage imageWithCGImage:masked];
However, because I am using CGImageCreateWithImageInRect the cropped part is stretched
Use the gray battery image as mask. Create a green rectangle and apply the mask you created. Here is a link to iOS masking: link
EDIT:
I hope this works (not tested):
int width = emptyBm.size.width;
int height = fullBm.size.height * level / 100;
UIImage *image = [UIImage imageNamed:#"battery_icon"];
UIImage *image2 = [UIImage imageNamed:#"battery_icon_full"];
// For clarity, just pretend the mask method I gave link to you is defined in your class.
UIImage *maskedImage = [self maskImage:image2 withMask:image];
// I assume the two imageviews are already connected to outlets.
self.backgroundImageView = [[UIImageView alloc] initWithImage:image];
self.foregroundImageView = [[UIImageView alloc] initWithImage:maskedImage];
// Make it's image stick to bottom so it won't stretch.
self.foregroundImageView.contentMode = UIViewContentModeBottom;
// Then calculate the frame again to reflect changes of battery status.
CGRect rect = self.backgroundImageView.frame;
rect.size.height = height;
// Push the masked imageview a to bottom as amount of missing battery height.
rect.origin.y = rect.origin.y + self.backgroundImageView.frame.size.height - height;
self.foregroundImageView.frame = rect;

How to set MediaItemArtwork Image Fill in UITableViewCell in iOS?

I am trying to enter MPMediaItemArtwork Image into UITableView's cell's ImageView with following code.
MPMediaItemArtwork *artwork = [[[self.arrayOfAlbums objectAtIndex:indexPath.row] representativeItem]valueForProperty:MPMediaItemPropertyArtwork];
UIImage *artworkImage = [artwork imageWithSize: cell.imageView.bounds.size];
if (artworkImage)
{
cell.imageView.image = artworkImage;
}
else
{
cell.imageView.image = [UIImage imageNamed: #"noArtwork.png"];
}
It's okay when i insert Artwork image in UITableView's cell ImageView.
But when my artwork image is too small or big , it's happened like following pic.
Not in completely fill in cell's ImageView.
You see that? I want to set Fill with Stretch like iOS Music App
Here is Build-in App Artwork Image that set Completely fill with Stretch
I want to do like that.
So i used cell.imageView.contentMode = UIViewContentModeScaleAspectFill; however it's not effect.
So how can i do that?
Thanks you for your work.
Try this for calculating a new and fitting image;
Adjust newRect to the rect of your cell.
// scale and center the image
CGSize sourceImageSize = [artworkImage size];
// The rectangle of the new image
CGRect newRect;
newRect = CGRectMake(0, 0, 40, 33);
// Figure out a scaling ratio to make sure we maintain the same aspect ratio
float ratio = MAX(newRect.size.width / sourceImageSize.width, newRect.size.height / sourceImageSize.height);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, 1.0);
// Center the image in the thumbnail rectangle
CGRect projectRect;
projectRect.size.width = ratio * sourceImageSize.width;
projectRect.size.height = ratio * sourceImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
[sourceImage drawInRect:projectRect];
UIImage *sizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.imageView.image = sizedImage;
The line
UIImage *artworkImage = [artwork imageWithSize: cell.imageView.bounds.size];
creates an image with the size of the cell. So, it's scaled in this line and the image won't be bigger than the cell and therefore it will not scale afterwards.
I would leave the image at it's original size or at a size 2x the cell size and leave the scaling up to contentMode.
CGSize newSize = CGSizeMake(artwork.bounds.size.width, artwork.bounds.size.height)
UIImage *artworkImage = [artwork imageWithSize: newSize];

Image cropping issue in iOS

I am creating an iPhone app which has image cropping feature. In this, I am getting the photos from the UIImagePickerController and passing it for cropping. There it has a scrollview and the selected image will be added as a subview to the scrollview. And I am using a UIButton for selecting the area for cropping. User can move the button over the imageview and place it anywhere, and when click on CROP button, the area similar to the frame size of the button should be cropped from the imageview.
I used the following code, but it is not returning the actual image.
CGRect clippedRect = CGRectMake(self.scrollView.frame.origin.x+90, self.scrollView.frame.origin.y, self.scrollView.frame.size.width-180, self.scrollView.frame.size.height-220);
CGImageRef imageRef = CGImageCreateWithImageInRect([self.myPhoto CGImage], clippedRect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
self.imageView.image = newImage;
also used
- (UIImage *)cropImage:(UIImage *)oldImage {
CGSize imageSize = self.cropFrame.frame.size;
UIGraphicsBeginImageContextWithOptions( CGSizeMake( imageSize.width, imageSize.height), NO, 0.);
[oldImage drawAtPoint:CGPointMake( xPosition, yPosition)
blendMode:kCGBlendModeCopy
alpha:1.];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
but the result image is not the exact image as per the button frame. I am getting the image from another area.
Updated code
- (void)loadPhoto{
CGFloat w = self.myPhoto.size.width;
CGFloat h = self.myPhoto.size.height;
CGRect imageViewFrame = CGRectMake(0.0f, 0.0f, roundf(w / 2.0f), roundf(h / 2.0f));
self.scrollView.contentSize = imageViewFrame.size;
UIImageView *iv = [[UIImageView alloc] initWithFrame:imageViewFrame];
iv.contentMode = UIViewContentModeScaleAspectFit;
iv.image = self.myPhoto;
[self.view addSubview:iv];
self.imageView = iv;
[iv release];
}
CGRect crop;//= CGRectMake(10, 10, 360, 360);
crop.origin.x = self.cropFrame.frame.origin.x;
crop.origin.y = self.cropFrame.frame.origin.y;
crop.size.width = roundf(self.cropFrame.frame.size.width * 2.0f); //self.cropFrame.frame.size.width * 2;
crop.size.height = roundf(self.cropFrame.frame.size.height * 2.0f); //self.cropFrame.frame.size.height * 2;
NSLog(#"Rect: %#", NSStringFromCGRect(crop));
self.imageView.image = [self croppedImage:crop];
- (UIImage *)croppedImage:(CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect([self.imageView.image CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:self.myPhoto.imageOrientation];
CGImageRelease(imageRef);
return croppedImage;
}
Please help to find a solution.
The iOS has a default feature for cropping images.Try this code.
picker.allowsEditing = YES;
and also check this controller for cropping..this is exactly the one you are looking for I think https://github.com/barrettj/BJImageCropper .Hope this helps you..
Since you are using a scrollView that allows the image to be scrolled, you need to adjust your crop rect to the scrollView's position:
float zoomScale = self.scrollView.zoomScale;
int cropX = (self.scrollView.contentOffset.x-imageView.frame.origin.x)/zoomScale;
int cropY = (self.scrollView.contentOffset.y-imageView.frame.origin.y)/zoomScale;
You could use this crop tool that I made. It essentially gives you an interface to allow the user to select the crop area. I think it is in line with that you are looking for.
https://github.com/nicholjs/BFCropInterface
Believing you have solve this problem. Me too had this when tried cropping functionality
Set image.size as the imageView.size & scrollView.contentSize. Below code will give the rect to crop
cropRect.origin = scrollView.contentOffset;
cropRect.size = scrollView.bounds.size;
cropRect.origin.x /= scrollView.zoomScale;
cropRect.origin.y /= scrollView.zoomScale;
cropRect.size.width /= scrollView.zoomScale;
cropRect.size.height /= scrollView.zoomScale;
If planning to show the full image first on visible rect. Setting the imageView.size & scrollView.contentSize to visible view size will give crop image of some other area. Instead try finding the zoom scale by
CGFloat dxWidth = viewCrop.frame.size.width / imageView.image.size.width;
CGFloat dxHeight = viewCrop.frame.size.height / imageView.image.size.height;
CGFloat zoomScale = fmaxf(dWidth, dHeight)
and apply (if by adding subView then after addSubView)
scrollView.minimumZoomScale = zoomScale; // to disable further zoom-out
[scrollView setZoomScale: zoomScale];

Resources