I'm currently using two images for a menu that I've built. I was using this code a while ago for normal display systems and it was working fine, with the retina display I'm having some issues with CGImageRef creating the right masked image on a depress for the background display. I've tried importing using the Image extensions for retina images. The images are supplied using:
[UIImage imageNamed:#"filename.png"]
I've provided both a standard and a retina image with both the filename.png and the filename#2x.png names.
The problem comes when choosing the mask for the selected area. The code works fine with lower resolution resources, and a high resolution main resource, but when I use
CGImageCreateWithImageInRect
And specify the rect that I want to create the image within, the image's scale is increased meaning that the main button's resolution is fine, but the image that is returned and superimposed on the button downpress is not the correct resolution, but oddly scaled to twice the pixel density, which looks terrible.
I've tried both
UIImage *img2 = [UIImage imageWithCGImage:cgImg scale:[img scale] orientation:[img imageOrientation]];
UIImage *scaledImage = [UIImage imageWithCGImage:[img2 CGImage] scale:4.0 orientation:UIImageOrientationUp];
And I seem to be getting nowhere when I take the image and drawInRect:(Selected Rect)
I have been tearing my hair out for about 2 hours now, and can't seem to find a decent solution, does anyone have any ideas?
I figured out what is necessary to be done in this instance. I created a helper method that would take the scale of the image into account when building the pressed state image and made it scale the CGRect by the image scale like so
- (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect {
rect.size.height = rect.size.height * [image scale];
rect.size.width = rect.size.width * [image scale];
rect.origin.x = rect.origin.x * [image scale];
rect.origin.y = rect.origin.y * [image scale];
CGImageRef sourceImageRef = [image CGImage];
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef scale:[image scale] orientation:[image imageOrientation]];
CGImageRelease(newImageRef);
return newImage;
}
That should fix anyone having similar issues for mapping.
Related
I am trying to crop an image taken from AVCaptureStillImageOutput but unable to properly crop at the correct rectangles.
My preview of camera video is 320x458 frame and the cropping rectangle is present inside this preview frame which has the co-ordinates and size as CGRectMake(60, 20, 200, 420).
After taking the picture, I receive the image from
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
UIImage *finalImage = [self cropImage:image];
Afterwards I am trying to crop this actual image of size 1080x1920 with the below function. I am getting a wayward clipping and the resultant image is way out of the actual rectangle! ;(
- (UIImage *)cropImage:(UIImage *)oldImage {
CGRect rect = CGRectMake(60, 20, 200, 420);
CGSize boundSize = CGSizeMake(320, 458);
float widthFactor = rect.size.width * (oldImage.size.width/boundSize.width);
float heightFactor = rect.size.height * (oldImage.size.height/boundSize.height);
float factorX = rect.origin.x * (oldImage.size.width/boundSize.width);
float factorY = rect.origin.y * (oldImage.size.height/boundSize.height);
CGRect factoredRect = CGRectMake(factorX,factorY,widthFactor,heightFactor);
UIImage *croppedImage = [UIImage imageWithCGImage:CGImageCreateWithImageInRect([oldImage CGImage], factoredRect) scale:oldImage.scale orientation:oldImage.imageOrientation];
return croppedImage;
}
In the attached picture, I am trying to crop the coffee mug, but what I get is not the correct cropped image!
I think you should use PEPhotoCropEditor sample code for cropping. It's easy to use. you can download source code from https://www.cocoacontrols.com/controls/pephotocropeditor
i am also facing hard time in this i think the what you have to do is write image of file then crop that image or try out orientation issue to solve.
I want to crop Image according to red View . There are some points to keep in mind.
1.Image can be scrolled and Zoomed.
2.Red ImageView is created Dynamically according to Image
UIImage* whole = [UIImage imageNamed:#"9.png"]; //I uses this image
CGImageRef cgImg = CGImageCreateWithImageInRect(whole.CGImage, CGRectMake(x, y, incX, incY));
UIImage* part = [UIImage imageWithCGImage:cgImg];
I just want to know How to find the Values of
x, y, incX, incY
Thanks...
Scenario 1: Normal (Not Scrolled)
Expected Result (Ignore Black Border On Top and Bottom)
Scenario 2:Scrolled
Expected Result (Ignore Black Border On Top and Bottom)
Scenario 3: Zoomed
And same Expected Result for the Zoomed One.
In all cases I want the respective Images Inside the Red Rectangle.
For all These I am Using this Code...
-(void)cropClicked:(UIButton*)sender
{
float zoomScale = 1.0 / [mainScrollView zoomScale];
CGRect rect;
rect.size.width = [redImageView bounds].size.width * zoomScale ;
rect.size.height = [redImageView bounds].size.height * zoomScale ;
rect.origin.x = ([mainScrollView bounds].origin.x + redImageView.frame.origin.x );
rect.origin.y = ([mainScrollView bounds].origin.y + redImageView.frame.origin.y );
CGImageRef cr = CGImageCreateWithImageInRect([[mainImageView image] CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:cr];
mainImageView.image=cropped;
UIImageWriteToSavedPhotosAlbum(cropped, nil, nil, nil);
CGImageRelease(cr);
}
Well, as #HDdeveloper rightly said, you can use CGImageCreateWithImageInRect. This take 2 params, the first is the whole image, the second is the frame that you want to crop (so probably the frame of your red imageView).
The problem is that if you're targeting for both retina/non retina; if your whole image is an image #2x and you want to crop the image with the red imageview frame you have to double your frame to get the right screenshot.
So you can try with this method:
//Define the screen type:
#define isRetinaDisplay [[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0)
- (UIImage*)cropInnerImage:(CGRect)rect {
//Take a screenshot of the whole image
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, NO, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* ret = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGRect rct;
//Double the frame if you're in retina display
if (isRetinaDisplay) {
rct=CGRectMake(rect.frame.origin.x*2, rect.frame.origin.y*2, rect.size.width*2, rect.size.height*2);
} else {
rct=rect;
}
//Crop the image from the screenshot
CGImageRef imageRef = CGImageCreateWithImageInRect([ret CGImage], rct);
UIImage *result = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
//Save and open the result images with Preview.app
[UIImagePNGRepresentation(result) writeToFile: #"/tmp/testCrop.png" atomically: YES];
system("open /tmp/testCrop.png");
[UIImagePNGRepresentation(ret) writeToFile: #"/tmp/testRet.png" atomically: YES];
system("open /tmp/testRet.png");
//
return result;
}
Where the rect parameter must be your red image frame, and self.view.frame must be the equal to the wholeImageView.frame. You can skip the last 4 lines, these are just to see in your Mac what you're cropping.
PS: i use this method to crop an image and set it as background of UIView, this is the reason i have to double the frame.
You can use CGImageRef
pass your rect in the whole image. Then call this on button click
UIImage* whole = [UIImage imageNamed:#"9.png"]; //I uses this image
CGImageRef cgImg = CGImageCreateWithImageInRect(whole.CGImage, CGRectMake(x, y, incX, incY));
UIImage* part = [UIImage imageWithCGImage:cgImg];
I am working on creating an image gallery which has thumbnails in different sizes. I want to convert these rectangle thumbnails to square size so that all of them could appear similar in size. I dont mind cropping it from extended portion but I am not sure how to do it. can anyone please help me?
Thanks
Pankaj
You need to use the image in rect method passing in the image and the required bounds...
CGImageRef imageRef = CGImageCreateWithImageInRect([anImage CGImage], requiredBounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
I have added this to a UIImage category (UIImage+Resize) in the following post, you can download the source code as well - Categories example
Well if you use an UIImageView to display your images (wich I am more than sure that you do) you can set it's contentMode property to UIViewContentModeScaleAspectFill. This should 'crop' your image to the boundaries of your UIImageView. In case your image will go out of the boundaries of the UIImageView make sure clipsToBounds is also set to YES.
Let me know if that helps.
I'm using the next method. The input are the UIImage to scale and the size of the UIImageView's frame where the UIImage is. It works when the frame's height and width are equal.
One important thing: I keep the image's ratio. I don't expand the image to cover the full square. If you want to do it you have to change the 'drawInRect' line for [self drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; and remove the if-else.
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
CGFloat scaleRatio;
if (image.size.width > image.size.height) {
scaleRatio = image.size.height/image.size.width;
}else{
scaleRatio = image.size.width/image.size.height;
}
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleRatio, scaleRatio);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextConcatCTM(context, scaleTransform);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
if (image.size.width > image.size.height) {
[image drawInRect:CGRectMake(0, (newSize.height/2)-(newSize.height*scaleRatio/2), newSize.width, newSize.height*scaleRatio)];
}else{
[image drawInRect:CGRectMake((newSize.width/2)-(newSize.width*scaleRatio/2), 0, newSize.width*scaleRatio, newSize.height)];
}
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I use the following code to getting images from the sprite. And it works fine everywhere except the iPhone 4 (HD version).
- (UIImage *)croppedImage:(CGRect)rect {
CGImageRef image = CGImageCreateWithImageInRect([self CGImage], rect);
UIImage *result = [UIImage imageWithCGImage:image];
CGImageRelease(image);
return result;
}
The iPhone 4 automatically load HD version of the image (sprite#2x.png) instead sprite.png. The original image has a scale 2, but the resulting image has a scale 1 and wrong size.
How to handle this behavior taking into account the different scales for iPhone 3G[s] and the iPhone 4?
I have read this document, but about the use CGImageCreateWithImageInRect here says nothing.
From what I can tell the CGImageCreateWithImageInRect will do the right thing. What you need to change is the UIImage initilization
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIImage_Class/Reference/Reference.html#//apple_ref/occ/clm/UIImage/imageWithCGImage:scale:orientation:
Change it to [UIImage imageWithCGImage:image scale:self.scale orientation:self. imageOrientation] and it should work just fine. (this is assuming this is a category on UIImage which it looks like it is)
You should multiply the crop rect by the image scale. From my experience, it's unnecessary to use any different image initilization.
- (UIImage *)_cropImage:(UIImage *)image withRect:(CGRect)cropRect
{
cropRect = CGRectMake(cropRect.origin.x * image.scale,
cropRect.origin.y * image.scale,
cropRect.size.width * image.scale,
cropRect.size.height * image.scale);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return croppedImage;
}
I am developing an iPhone app that resizes and merges images.
I want to select two photos of size 1600x1200 from photo library and then merge both into a single image and save that new image back to the photo library.
However, I can't get the right size for the merged image.
I take two image views of frame 320x480 and set the view's image to my imported images. After manipulating the images (zooming, cropping, rotating), I then save the image to album. When I check the image size it shows 600x800. How do I get the original size of 1600*1200?
I've been stuck on this problem from two weeks!
Thanks in advance.
The frame of the UIImageView has nothing to do with the size of the image it displays. If you display a 1200x1600 pixel in a 75x75 imageView the image size in memory is still 1200x1600. Somewhere in your processing of the image you are resetting its size.
You need to resize the images programmatically behind the scenes and ignore how they are displayed. For highest fidelity, I suggest preforming all processing on the image at full size and then resizing only the final result. For speed and low memory use, resize smaller first, process and then resize again as needed.
I use Trevor Harmon's UIImage+Resize to resize images.
His core method looks like this:
- (UIImage *)resizedImage:(CGSize)newSize
transform:(CGAffineTransform)transform
drawTransposed:(BOOL)transpose
interpolationQuality:(CGInterpolationQuality)quality
{
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
CGImageRef imageRef = self.CGImage;
// Build a context that's the same dimensions as the new size
CGContextRef bitmap = CGBitmapContextCreate(NULL,
newRect.size.width,
newRect.size.height,
CGImageGetBitsPerComponent(imageRef),
0,
CGImageGetColorSpace(imageRef),
CGImageGetBitmapInfo(imageRef));
// Rotate and/or flip the image if required by its orientation
CGContextConcatCTM(bitmap, transform);
// Set the quality level to use when rescaling
CGContextSetInterpolationQuality(bitmap, quality);
// Draw into the context; this scales the image
CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, 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;
}
Harmon saved me dozens of man hours trying to get resizing done correctly.
Solved as follows.
UIView *bgView = [[UIView alloc] initwithFrame:CGRectMake(0, 0, 1600, 1200)];
UIGraphicsBeginImageContext(tempView.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, self, nil, nil);
Thanks for all your support to solve the issue