iOS - Cell image blurred - ios

I have placed an image in a UITableViewCell and for some reason, the image is a bit blurred...
This is what I'm using:
NSURL *urlForProfileImage = [NSURL URLWithString: [_currentTweet[#"user"] objectForKey:#"profile_image_url_https"]];
UIImage *thumbnail = [UIImage imageWithData: [NSData dataWithContentsOfURL:urlForProfileImage]];
cell.imageView.image = thumbnail;
Is there another way to provide the desired result but maintain the images quality?

Reason :
The default imageView size is 40x40 and so your image needs to be 80x80 pixels (retina display).
But the image that you are getting from the "pbs.twimg.com/profile_images/192098593/Apple_normal.png" is 48x48.
And so it is blurred.
Solution :
One option is that you add a custom imageView which is 24x24. (width : 24 & height : 24) Then your image will not show blurred.
Or, you can try modifying the height and width of the imageView by subclassing the class UITableViewCell and using its layoutSubviews method. The "trick" is to write layout code in this method, otherwise the code does not have any effect :
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.bounds = CGRectMake(0,0,24,24);
self.imageView.frame = CGRectMake(0,0,24,24);
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
CGRect tmpFrame = self.textLabel.frame;
tmpFrame.origin.x = 30;
self.textLabel.frame = tmpFrame;
tmpFrame = self.detailTextLabel.frame;
tmpFrame.origin.x = 30;
self.detailTextLabel.frame = tmpFrame;
}

Related

IOS UIImageView in cell has wrong size

I'm trying to replace an Image from an URL if it exists.
The problem seems to be that I can't set the size of my UIImageView.
My Code looks like this:
UIImageView *partnerIcon = (UIImageView*)[cell viewWithTag:0];
NSURL *imageUrl = [NSURL URLWithString:[[#"http://www.fitpas.ch/coreapp/resources/images/center/" stringByAppendingString:[[result objectAtIndex:indexPath.row] objectForKey:#"cid"]] stringByAppendingString:#".jpg"]];
UIImage* partnerImage = [UIImage imageWithData: [NSData dataWithContentsOfURL: imageUrl]];
if (partnerImage != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
//change image
partnerIcon.image = partnerImage;
partnerIcon.contentMode = UIViewContentModeScaleToFill;
});
}
This results in:
In the Image above the last row partnerImage is nil and that shows how it should be.
I tried to scale the UIImage with
partnerIcon.image = [UIImage imageWithCGImage:partnerImage.CGImage
scale:1/100 orientation:partnerImage.imageOrientation];
but this won't change anything.
I also tried to set to change the dimension of the UIImageView with:
partnerIcon.bounds = CGRectMake(0, 0, 50, 50);
and also
partnerIcon.frame = CGRectMake(0, 0, 50, 50);
but this isn't working either.
Set an explicit width and height constraint on the image view. If you don't do this then the content hugging and compression values will be used across all of the views to decide how big each should be based on the content size.

Image resizing inside tableviewcell

I ran into a problem that can not solve 2 days. On the server image and come before inserting them in the box, I cut them on the client to fit the screen. Everything is good but the images change randomly height. Now the height is calculated independently - in proportion to the width.
Normal image:
Bad image
I can not ask explicitly UIImageView because I dynamically I rely all the cells to different devices.
My resize function:
-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
CGFloat height = theImage.size.height;
CGFloat newHeight = 0;
newHeight = (theNewSize.width * height) / theImage.size.width;
newHeight = floorf(newHeight);
NSLog(#"new height image %f", newHeight);
[theImage drawInRect:CGRectMake(0, 0, theNewSize.width, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
inside layoutSubviews:
if(device == thisDeviceClass_iPhone5) {
[self.imageView setFrame:CGRectMake(0,0, 320, 255)]; //180
offset = 0;
padding = 5;
} else if(device == thisDeviceClass_iPhone6){
[self.imageView setFrame:CGRectMake(0,0, 375, 255)]; //211
offset = 25;
} else if(device == thisDeviceClass_iPhone6plus) {
[self.imageView setFrame:CGRectMake(0,0, 414, 255)]; //233
offset = 40;
}
Your approach is very old school. You are "hard coding" the size of the image which means that if next year Apple came up with a new iPhone that have, yet again, a different size you'll be in trouble. You should consider using auto-layout constrains which is Apple's recommended approach (here is a good tutorial: http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1).
You can also set the ImageView.contentMode to UIViewContentModeScaleAspectFill which will do the crop and resize for you.

Loading Remote images in TableView while keeping sizes intact

I want to show a table view where each cell will just contain one image. Images are loaded from respective URLs and there is no restriction on the size of the image.
I want to show the image in each cell with their proper sizes - that is maintain the aspect ratio. I am guessing this would entail having dynamic heights for each cell. But I am not sure and can't find a resource which explains how to achieve this.
What would be the best way to do this?
You need to get the image height and width dynamically first and set the same hieght and width to your table view cells.
I have not added table view but just some code will help you see how you can show two different images with their original height and width and adding the same to a view.
NSURL *imageURL1 = [NSURL URLWithString:#"http://cdn.macrumors.com/article-new/2014/12/applelogo.png"];
NSData *imageData1 = [NSData dataWithContentsOfURL:imageURL1];
UIImage *image1 = [UIImage imageWithData:imageData1];
UIImageView *imageView1 = [[UIImageView alloc] initWithImage: image1];
//CGFloat height = imageView.frame.size.height;
//CGFloat width = imageView.frame.size.width;
[self.view addSubview:imageView1];
//sample urls :- http://pre01.deviantart.net/e711/th/pre/f/2013/179/2/c/ios_7_icons__updated__by_iynque-d69mme1.png
NSURL *imageURL2 = [NSURL URLWithString:#"http://icons.iconarchive.com/icons/position-relative/social-2/128/ios-icon.png"];
NSData *imageData2 = [NSData dataWithContentsOfURL:imageURL2];
UIImage *image2 = [UIImage imageWithData:imageData2];
UIImageView *imageView2 = [[UIImageView alloc] initWithImage: image2];
CGFloat height = imageView2.frame.size.height;
CGFloat width = imageView2.frame.size.width;
imageView2.frame = CGRectMake(0, 300, width, height);
NSLog(#"height :- %f, Width :- %f ",height, width);
[self.view addSubview:imageView2];
Hopefully, you are loading the images asynchronously, as answered here: Loading images for UITableViewCell from URL (need to load them asynchronously)
You'll need a custom cell or prototype cell with a UIImageView set to UIViewContentModeScaleAspectFit. In the cell, set the constraints how you want them: that is, if you want the image to be the full width of the screen, set leading and trailing constraints, and constrain to the top and bottom.
Then, set your table view to use dynamic sizing:
tableView.estimatedRowHeight = 80.0; //or some reasonable first approximation
tableView.rowHeight = UITableViewAutomaticDimension;

Fast blurring for UITableViewCell contentView Background

I have made a UIViewController which conforms to the UITableViewDataSource and UITableViewDelegate protocol and has a UITableView as it's subview.
I have set the backgroundView property of the table to be a UIImageView in order to display an image as the background of the table.
In order to have custom spacings between the cells I made the row height larger than I wanted and customised the cell's contentView to be the size I wanted, making it look like there is extra space (Following this SO answer).
I wanted to add a blur to the cell so that the background was blurred and I did this through Brad Larson's GPUImage framework. This works fine however, since I want the background blur to update as it scrolls, the scroll becomes very laggy.
My code is:
//Gets called from the -scrollViewDidScroll:(UIScrollView *)scrollView method
- (void)updateViewBG
{
UIImage *superviewImage = [self snapshotOfSuperview:self.tableView];
UIImage* newBG = [self applyTint:self.tintColour image:[filter imageByFilteringImage:superviewImage]];
self.layer.contents = (id)newBG.CGImage;
self.layer.contentsScale = newBG.scale;
}
//Code to create an image from the area behind the 'blurred cell'
- (UIImage *)snapshotOfSuperview:(UIView *)superview
{
CGFloat scale = 0.5;
if (([UIScreen mainScreen].scale > 1 || self.contentMode == UIViewContentModeScaleAspectFill)) {
CGFloat blockSize = 12.0f/5;
scale = blockSize/MAX(blockSize * 2, floor(self.blurRadius));
}
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, -self.frame.origin.x, -self.frame.origin.y);
NSArray *hiddenViews = [self prepareSuperviewForSnapshot:superview];
[superview.layer renderInContext:context];
[self restoreSuperviewAfterSnapshot:hiddenViews];
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshot;
}
-(UIImage*)applyTint:(UIColor*)colour image:(UIImage*)inImage{
UIImage *newImage;
if (colour) {
UIGraphicsBeginImageContext(inImage.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, inImage.size.width, inImage.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, area, inImage.CGImage);
[[colour colorWithAlphaComponent:0.8] set];
CGContextFillRect(ctx, area);
CGContextRestoreGState(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeLighten);
CGContextDrawImage(ctx, area, inImage.CGImage);
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
} else {
newImage = inImage;
}
return newImage;
}
Now for the question:
Is there a better way to add the blur? Maybe so that the layer doesn't have to be rendered each movement? iOS7's control centre/notification centre seem to be able to do this without any lagging.
Maybe with the GPUImageUIElement class? If so, how do I use this?
Another way I looked at was to create the blur on the background image initially and then crop just the areas I needed to use out, however I couldn't get this to work, since the images may or may not be the same size as the screen so the scaling was a problem (Using CGImageCreateWithImageInRect() and the rect being the cell's position on the table).
I also found out that I have to add the blur to the tableview itself with the frame being that of the cell, and the cell having a clear colour.
Thanks in advance
EDIT
Upon request, here is the code for the image cropping I attempted before:
- (void)updateViewBG
{
//self.bgImg is the pre-blurred image, -getContentViewFromCellFrame: is a convenience method to get just the content area from the whole cell (since the contentarea is smaller than the cell)
UIImage* bg = [self cropImage:self.bgImg
toRect:[LATableBlur getContentViewFromCellFrame:[self.tableView rectForRowAtIndexPath:self.cellIndexPath]]];
bg = [self applyTint:self.tintColour image:bg];
self.layer.contents = (id)bg.CGImage;
self.layer.contentsScale = bg.scale;
}
- (UIImage*)cropImage:(UIImage*)image toRect:(CGRect)frame
{
CGSize imgSize = [image size];
double heightRatio = imgSize.height/self.tableView.frame.size.height;
double widthRatio = imgSize.width/self.tableView.frame.size.width;
UIImage* cropped = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(image.CGImage,
CGRectMake(frame.origin.x*widthRatio,
frame.origin.y*heightRatio,
frame.size.width*widthRatio,
frame.size.height*heightRatio))];
return cropped;
}
I managed to solve it with a solution I, at first, didn't think it would work.
Generating several blurred images is certainly not the solution as it costs a lot.
I used only one blurred image and cached it.
So I subclassed UITableViewCell :
#interface BlurredCell : UITableViewCell
#end
I implemented two class methods to access the cached images (blurred and normal ones)
+(UIImage *)normalImage
{
static dispatch_once_t onceToken;
static UIImage *_normalImage;
dispatch_once(&onceToken, ^{
_normalImage = [UIImage imageNamed:#"bg.png"];
});
return _normalImage;
}
I used REFrostedViewController's category on UIImage to generate the blurred image
+(UIImage *)blurredImage
{
static dispatch_once_t onceToken;
static UIImage *_blurredImage;
dispatch_once(&onceToken, ^{
_blurredImage = [[UIImage imageNamed:#"bg.png"] re_applyBlurWithRadius:BlurredCellBlurRadius
tintColor:[UIColorcolorWithWhite:1.0f
alpha:0.4f]
saturationDeltaFactor:1.8f
maskImage:nil];
});
return _blurredImage;
}
In order to have the effect of blurred frames inside the cell but still see the non blurred image on the sides, I used to scroll views.
One with an image view with the normal image and the other one with an image view with the blurred image. I set the content size to be the size of the image and the contentOffset will be set through an interface.
So the table view ends up with each cell holding the whole background image but cropping it at certain offset and still showing the entire image
#implementation BlurredCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
[self.contentView addSubview:self.normalScrollView];
[self.contentView addSubview:self.blurredScrollView];
}
return self;
}
-(UIScrollView *)normalScrollView
{
if (!_normalScrollView) {
_normalScrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
_normalScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_normalScrollView.scrollEnabled = NO;
UIImageView *imageView =[[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.image = [BlurredCell normalImage];
_normalScrollView.contentSize = imageView.frame.size;
[_normalScrollView addSubview:imageView];
}
return _normalScrollView;
}
-(UIScrollView *)blurredScrollView
{
if (!_blurredScrollView) {
_blurredScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(BlurredCellPadding, BlurredCellPadding,
self.bounds.size.width - 2.0f * BlurredCellPadding,
self.bounds.size.height - 2.0f * BlurredCellPadding)];
_blurredScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_blurredScrollView.scrollEnabled = NO;
_blurredScrollView.contentOffset = CGPointMake(BlurredCellPadding, BlurredCellPadding);
UIImageView *imageView =[[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.image = [BlurredCell blurredImage];
_blurredScrollView.contentSize = imageView.frame.size;
[_blurredScrollView addSubview:imageView];
}
return _blurredScrollView;
}
-(void)setBlurredContentOffset:(CGFloat)offset
{
self.normalScrollView.contentOffset = CGPointMake(self.normalScrollView.contentOffset.x, offset);
self.blurredScrollView.contentOffset = CGPointMake(self.blurredScrollView.contentOffset.x, offset + BlurredCellPadding);
}
#end
setBlurredContentOffset: should be called each time the table view's content offset changes.
So in the table view delegate's implementation (the view controller) we do it in those two methods :
// For the first rows
-(void)tableView:(UITableView *)tableView willDisplayCell:(BlurredCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
[cell setBlurredContentOffset:cell.frame.origin.y];
}
// Each time the table view is scrolled
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
for (BlurredCell *cell in [self.tableView visibleCells]) {
[cell setBlurredContentOffset:cell.frame.origin.y - scrollView.contentOffset.y];
}
}
Here is a complete working demo

Resizing image to fit UIImageView

I am very new to objective c and I'm just getting my bearings. I want to do something really simple but it proves to be quite a challenge:
I am trying to display an image into an UIImageView. The image I'm showing is large and I want it scaled down to fit the UIImageView. I tried setting the AspectFit View mode but the image gets displayed to the original size and is clipped by the UIImageView. My code is below:
- (void)changeImages
{
UIImage* img11 = nil;
img11 = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"dog" ofType:#"jpeg"]];
u11.contentMode = UIViewContentModeScaleAspectFit;
u11.image = img11;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self changeImages];
}
Can anyone shed some light on this please?
Thanks!
Hi I would try this...
- (void)changeImages
{
UIImage *img11 = [UIImage imageNamed#"dog.jpeg"];
u11.contentMode = UIViewContentModeScaleAspectFit;
u11.clipsToBounds = YES;
[u11 setImage:img11];
}
- (void)viewWillAppear:animated
{
[super viewWillAppear:animated];
[self changeImages];
}
This will scale the image (up or down) so that it fits inside the imageView. Having clipsToBounds isn't necessary but will stop the image from displaying outside the frame of your imageView.
HTH.
Add to your UIViewController.m:
-(UIImage *)resizeImage:(UIImage *)image imageSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
// here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
return newImage;
}
Using:
UIImage *image = [UIImage imageNamed:#"image.png"];
CGSize size = CGSizeMake(50, 63); // set the width and height
UIImage *resizedImage = [self resizeImage:image imageSize:size];
I hope it helps.
CGSize size=CGSizeMake(79, 84);//set the width and height
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
//here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
This works for sure and don't forget to import QuartzCore FrameWork..
Have a Happy Coding (^_^)....
You can also set View:Mode to Aspect Fit in the Attributes Inspector in Interface Builder
I did the following and it helped
change the mode to "aspect fill" from the default value "Scale to fill"
and add a line of code as follows (I did it in a cell configuration):
cell.photo.clipsToBounds = true
I know this is old but I wanted to add a response based on the Stanford 193p 2017 lecture 11 (around 18:45) and for anyone looking in swift as this is the first search result that showed up for me.
Basically, subclass UIView and make it look like:
class U11: UIView {
var myImage: UIImage? { didSet { setNeedsDisplay() }}
override func draw(_ rect: CGRect) {
myImage?.draw(in: bounds)
}
}
Then set the image with:
func changeImage() {
if let img11 = UIImage(named: "dog.jpeg"){
u11.myImage = img11
}
}
This is super simple and the image takes up the whole space inside of the views bounds.

Resources