Resizing image to fit UIImageView - ios

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.

Related

Where is the first good moment to take a screenshot in UIViewController

I would like to make a screenshot of my view when view is loaded. I use this method:
- (UIImage *)screenshot {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0f);
if( [self respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)] ) {
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
} else {
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenshot;
}
The screenshot method was tested and works well. I am using the method in my UIViewController in viewDidLoad. The problem is that the result is a grey image! It's mean that view is not loaded in viewDidLoad method. The same issue can be observe in viewDidAppear. So viewDidLoad and viewDidAppear are too early. I have made workaround in viewDidLoad method:
__weak MyUIViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^() {
UIImage* image = [weakSelf.view screenshot]
// do sth with image...
});
How to make a screenshot without dispatach_async ?
Try This:
- (UIImage *)screenshot {
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, [UIScreen mainScreen].scale);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
UIView-JTViewToImage project also usefull.
You could also try the snapshotViewAfterScreenUpdates method of UIView:
[self.view snapshotViewAfterScreenUpdates:YES];
Try this
New API has been added since iOS 7, that should provide efficient way of getting snapshot
snapshotViewAfterScreenUpdates: renders the view into a UIView with unmodifiable content
resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets : same thing, but with resizable insets
drawViewHierarchyInRect:afterScreenUpdates:
same thing if you need all subviews to be drawn too (like labels, buttons...)
Hope it helps.

UITableViewCell ImageView Resize - Selected Row Changes Image Size

I am setting an table cell ImageView from a URL like the following:
NSURL *url = [[NSURL alloc] initWithString:[account valueForKeyPath:#"Avatar"]];
[cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:#"default.png"]];
I am then using a table cell subclass and resizing the image and making it round like the following:
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.bounds = CGRectMake(0,0,32,32);
self.imageView.layer.cornerRadius = 16;
self.imageView.clipsToBounds = YES;
}
This works great until I actually tap on a table row. It will then shift the image to the left some pixels.
It's only the images that aren't a perfect square. Example 100x75 instead of 100x100
I must be missing something small here? Here is a small image showing the offset:
FYI I'm referencing this post: How do I make UITableViewCell's ImageView a fixed size even when the image is smaller
EDIT
I've also tried this as the table cell cellForRowAtIndexPath:
This seems to work, however, for some reason when the table view is loaded not all images are loaded in until I start scrolling
[[SDWebImageManager sharedManager] downloadImageWithURL:url options:0 progress: nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
// resize image code here, then set below
cell.imageView.image = image;
}];
In my case I did this
-(void)layoutSubviews
{
[super layoutSubviews];
[self layoutIfNeeded];
self.imageView.layer.cornerRadius = (self.imageView.bounds.size.width / 2.0);
self.imageView.layer.masksToBounds = YES;
}
I haven't change bounds at run time. Hope it helps
FYI I ended up just creating a custom UITableViewCell with a UIImageView defined width/height 32x32 and custom labels to essentially mimic the Right Detail view.
You can try adding cell.setNeedsLayout() after setting Cell's image view, if all images have same dimensions!
MenuController.shared.fetchImage(url: item.imageURL) { (image) in
if let image = image {
DispatchQueue.main.async {
cell.imageView?.image = image
cell.setNeedsLayout()
}
}
}
Try this:
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0,self.frame.size.width/2-16,32,32);
self.imageView.layer.cornerRadius = 16;
self.imageView.clipsToBounds = YES;
}
Or you may try set autoresizingMask

How can I programmatically put together some UIImages to have one big UIImage?

This is my code:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
// at this point the webView scrolled to the next section
// I save the offset to make the code a little easier to read
CGFloat offset = _webPage.scrollView.contentOffset.y;
UIGraphicsBeginImageContextWithOptions(_webPage.bounds.size, NO, 0);
[_webPage.layer renderInContext:UIGraphicsGetCurrentContext()];
viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
// if we are not done yet, scroll to next section
if (offset < _webPage.scrollView.contentSize.height)
{
[_webPage.scrollView scrollRectToVisible:CGRectMake(0, _webPage.frame.size.height+offset, _webPage.frame.size.width, _webPage.frame.size.height) animated:YES];
}
}
In which I save an undefined number of screenshots (UIImages) by scrolling the web view. This works, I have in my photo gallery all the parts of the web page.
But I don't want parts, I want ONE long UIImage. So how do I put (one by one?) my UIImages together?
You can write a UIImage category to do that
UIImage+Combine.h
#import <UIKit/UIKit.h>
#interface UIImage (Combine)
+ (UIImage*)imageByCombiningImage:(UIImage*)firstImage withImage:(UIImage*)secondImage;
#end
UIImage+Combine.m
#import "UIImage+Combine.h"
#implementation UIImage (Combine)
+ (UIImage*)imageByCombiningImage:(UIImage*)firstImage withImage:(UIImage*)secondImage {
UIImage *image = nil;
CGSize newImageSize = CGSizeMake(MAX(firstImage.size.width, secondImage.size.width), firstImage.size.height + secondImage.size.height);
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]);
} else {
UIGraphicsBeginImageContext(newImageSize);
}
[firstImage drawAtPoint:CGPointMake(roundf((newImageSize.width-firstImage.size.width)/2), 0)];
[secondImage drawAtPoint:CGPointMake(roundf(((newImageSize.width-secondImage.size.width)/2) ),
roundf((newImageSize.height-secondImage.size.height)))];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
and then you can call the function in your code with:
UIImage *img = [UIImage imageByCombiningImage:image1 withImage:image2];
This will draw a new image that has the width of the biggest of the two images and the height of both images combined. image1 will be at the top position and image2 below that.

iOS - Cell image blurred

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

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

Resources