In my application I capture image from camera. At that time sharpness of my image is fantastic but with the following lines of code my image is moved to next view.
- (UIImage *) imageFromView:(UIView *)view {
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage;
}
When I see the image in next view at that time it is less sharper than before.
I want to mention, on both screens height and width of image view is same.
then what should be the problem with sharpness of image?
Use this Line
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0);
instead of
UIGraphicsBeginImageContext(view.bounds.size);
You need to offset the image by 0.5,0.5. Otherwise Quartz distributes each point amongst the 4 neighbors.
In Quartz 0.0 is the corner of a pixel, not its center.
CGContextTranslateCTM(context, 0.5, 0.5);
See: https://developer.apple.com/library/mac/ipad/#documentation/graphicsimaging/reference/CGContext/Reference/reference.html
Related
I've been having issues rendering images with the UIImageView class. The pixelation seems to occur mostly on the edges of the image I am trying to show.
I have tried changing the property 'Render with edge antialiasing' to no avail.
The image files contain images that are larger than what will appear on the screen.
It seems to be royally messing with the quality of the image and then displaying it. I tried to post images here, but StackOverflow is denying me that privilege. So here's a link to what's going on.
http://i.imgur.com/QpUOTOF.png
The sun in this image is the problem I'm speaking of. Any ideas?
On-the-fly image resizing is quick and of low quality. For bundled images, it is worth the extra bundle space to include downsized versions. For downloaded images, you can achieve better results by resizing with Core Graphics into a new UIImage before you set the image property.
CGSize newSize = CGSizeMake(newWidth, newHeight);
UIGraphicsBeginImageContextWithOptions(newSize, // context size
NO, // opaque?
0); // image scale. 0 means "device screen scale"
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
[bigImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Use following method use for get specific hight and width with image
+ (UIImage*)resizeImage:(UIImage*)image withWidth:(int)width withHeight:(int)height
{
CGSize newSize = CGSizeMake(width, height);
float widthRatio = newSize.width/image.size.width;
float heightRatio = newSize.height/image.size.height;
if(widthRatio > heightRatio)
{
newSize=CGSizeMake(image.size.width*heightRatio,image.size.height*heightRatio);
}
else
{
newSize=CGSizeMake(image.size.width*widthRatio,image.size.height*widthRatio);
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
This method return NewImage, with specific size that you specified.
How big is your image and what is the size of the imageView? Don't rely on UIImageView to scale it down for you. You probably need to resize it manually. This would also be a bit more memory efficient.
I use categories like these:
>>>github link <<<
to do image resizing.
This also gives you some other nice function for rounded corners etc.
Also keep in mind, that you need a transparent border at the edge of an image if you want to rotate it to avoid aliasing.
In my app, I want to high quality Image. Image is loaded from Facebook friend list. When that image is loaded in smaller size (50 * 50), its quality is fine. But when I try to get that image in bigger size(280 *280) quality of image diminished.
For round corner m doing like :
self.mImageView.layer.cornerRadius = 10.0;
self.mImageView.layer.borderColor = [UIColor blackColor].CGColor;
self.mImageView.layer.borderWidth = 1.0;
self.mImageView.layer.masksToBounds = YES;
For getting image m using following code :
self.mImageView.image = [self imageWithImage:profileImage scaledToSize:CGSizeMake(280, 280)];
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
UIGraphicsBeginImageContextWithOptions(newSize, YES,0.0);
CGContextRef context = CGContextRetain(UIGraphicsGetCurrentContext());
CGContextTranslateCTM(context, 0.0, newSize.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetInterpolationQuality(context, kCGInterpolationLow);
CGContextSetAllowsAntialiasing (context, TRUE);
CGContextSetShouldAntialias(context, TRUE);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, newSize.width, newSize.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I have checked my code several times, but could not figure out how to make image perfect. So, guys how this quality of image will be improved?
Thanx in advance...
…quality of image diminished.
The 'quality' of the image is still present. (Technically, you are introducing a small amount of error by resizing it, but that's not the real problem…)
So, you want to scale a 50x50px image to 280x280px? The information/detail does not exist in the source signal. Ideally, you would download a more appropriately sized image, for the size you want to display at.
If that's not an option, you could reduce pixelation by means of proper resampling and/or interpolation. This would simply smooth out the pixels your program magnifies by 5.6 -- the image would then look like a cross between pixelated and blurred (see CGContextSetAllowsAntialiasing, CGContextSetShouldAntialias, CGContextSetInterpolationQuality and related APIs to accomplish this using quartz).
I have an imageview, the image within this imageview is for you to choose from the photoroll. I also have a button, when you click this button, there's an image added to a view with the addSubview code. This piece of image is draggable, resizeable and rotatable.
One problem, when I finish the image I use the method drawInRect. This draws all the layers onto eachother and creates an image. However the layers are on the wrong place and are the wrong size. It's also never rotated. I don't know how to fix this, the piece of code is beneath this text. Is it possible to keep the original image size and still have the layers drawn on the same place I drag them onto the imageview, if not how do I create a new size for this and have the result I want. And how do I draw the image rotated.
UIGraphicsBeginImageContext(imageView2.image.size);
// Draw image1
[imageView2.image drawInRect:CGRectMake(0, 0, imageView2.image.size.width, imageView2.image.size.height)];
// Draw image2
for(UIImageView *viewsSub in [self.imageViewer subviews])
{
[viewsSub.image drawInRect:CGRectMake(viewsSub.frame.origin.x, viewsSub.frame.origin.y, viewsSub.frame.size.width, viewsSub.frame.size.height)];
}
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
pld.imageChosen2 = resultingImage;
UIGraphicsEndImageContext();
So you want something like taking a "screenshot" of your actual imageview (with subviews included), don't you?
I used this piece of code to do something similar, but don't know if would work for you.
- (UIImage *)screenshot {
CGFloat scale = [UIScreen screenScale];
if(scale > 1.5) {
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, scale);
} else {
UIGraphicsBeginImageContext(self.frame.size);
}
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenshot;
}
You should add this method inside your imageview (the one that contains all the subviews you're adding).
i am trying to scale down a image i get from photo library on touchesmoved by user in a similar way like when we take picture with camera using UIImagepicker setEditing to Yes method(or like the camera app).
I am trying to use the following method passing in some parameters based on touchesmoved but i am not getting the desired effect? what am i possibly doing wrong??
-(UIImage*)scaleToSize:(UIImage *)img:(CGSize)size
{
// Create a bitmap graphics context
// This will also set it as the current context
UIGraphicsBeginImageContext(size);
// Draw the scaled image in the current context
[img drawInRect:CGRectMake(0, 0, size.width, size.height)];
// Create a new image from current context
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
// Pop the current context from the stack
UIGraphicsEndImageContext();
// Return our new scaled image
return scaledImage;
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UIImage *img = [self scaleToSize:imgView.image:CGSizeMake(touch1.x,touch1.y)];
imgView.image=img;
}
also how can i save the scaled image once somehow i scale it??
Building on your comment, the image will distort as it will draw the image into the rectangle specified and if the new dimensions are not the same aspect ratio (the width / height) as the original image then it will appear distorted.
You need some logic to ensure that your new width and height have the same aspect ratio, for example:
CGFloat newHeight = imageView.frame.size.height * size.width / imageView.frame.size.width;
If you make your Graphics context size.width and newHeight and then draw your image into this rect it will maintain the aspect ratio.
You will likely want to put some extra logic in there to either create a new width given the height or new height given the width, depending on which dimension was the largest change.
Hope this helps,
Dave
I've got a UIImageView (full frame and rectangular) that i'm rotating with a CGAffineTransform. The UIImage of the UIImageView fills the entire frame. When the image is rotated and drawn the edges appear noticeably jagged. Is there anything I can do to make it look better? It's clearly not being anti-aliased with the background.
The edges of CoreAnimation layers aren't antialiased by default on iOS. However, there is a key that you can set in Info.plist that enables antialiasing of the edges: UIViewEdgeAntialiasing.
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html
If you don't want the performance overhead of enabling this option, a work-around is to add a 1px transparent border around the edge of the image. This means that the 'edges' of the image are no longer on the edge, so don't need special treatment!
New API – iOS 6/7
Also works for iOS 6, as noted by #Chris, but wasn't made public until iOS 7.
Since iOS 7, CALayer has a new property allowsEdgeAntialiasing which does exactly what you want in this case, without incurring the overhead of enabling it for all views in your application! This is a property of CALayer, so to enable this for a UIView you use myView.layer.allowsEdgeAntialiasing = YES.
just add 1px transparent border to your image
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0.0);
[image drawInRect:CGRectMake(1,1,image.size.width-2,image.size.height-2)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Remember to set the appropriate anti-alias options:
CGContextSetAllowsAntialiasing(theContext, true);
CGContextSetShouldAntialias(theContext, true);
just add "Renders with edge antialiasing" with YES in plist and it will work.
I would totally recommend the following library.
http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
It contains lots of useful extensions to UIImage that solve this problem and also include code for generating thumbnails etc.
Enjoy!
The best way I've found to have smooth edges and a sharp image is to do this:
CGRect imageRect = CGRectMake(0, 0, self.photo.image.size.width, self.photo.image.size.height);
UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0.0);
[self.photo.image drawInRect:CGRectMake(1, 1, self.photo.image.size.width - 2, self.photo.image.size.height - 2)];
self.photo.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Adding the Info.plist key like some people describe has a big hit on performance and if you use that then you're basically applying it to everything instead of just the one place you need it.
Also, don't just use UIGraphicsBeginImageContext(imageRect.size); otherwise the layer will be blurry. You have to use UIGraphicsBeginImageContextWithOptions like I've shown.
I found this solution from here, and it's perfect:
+ (UIImage *)renderImageFromView:(UIView *)view withRect:(CGRect)frame transparentInsets:(UIEdgeInsets)insets {
CGSize imageSizeWithBorder = CGSizeMake(frame.size.width + insets.left + insets.right, frame.size.height + insets.top + insets.bottom);
// Create a new context of the desired size to render the image
UIGraphicsBeginImageContextWithOptions(imageSizeWithBorder, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Clip the context to the portion of the view we will draw
CGContextClipToRect(context, (CGRect){{insets.left, insets.top}, frame.size});
// Translate it, to the desired position
CGContextTranslateCTM(context, -frame.origin.x + insets.left, -frame.origin.y + insets.top);
// Render the view as image
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
// Fetch the image
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup
UIGraphicsEndImageContext();
return renderedImage;
}
usage:
UIImage *image = [UIImage renderImageFromView:view withRect:view.bounds transparentInsets:UIEdgeInsetsZero];