Fitting a UIImage in UIImageView - ios

I need to resize my UIImage according to the size of UIImageView. My image is too small, so i need to scale it up. I was not able to do it using:
self.firstImage.contentMode = UIViewContentModeScaleAspectFit;
Please help.

In Swift 3.0 , it will be
func imageWithImage(image:UIImage, scaledToSize newSize:CGSize ) -> UIImage {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.width))
let newImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext();
return newImage;
}

try with this:
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.imageView.clipsToBounds = YES;

Related

Fill UIImage with UIColor

I have a UIImage that I want to fill with UIColor
I've tried this code but the app crashes on the 10th row.
Here's the code:
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0.0, y: size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(CGBlendMode.normal)
let rect = CGRect(origin: CGPoint.zero, size: size)
context?.clip(to: rect, mask: context as! CGImage)// crashes
color.setFill()
context?.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
return newImage!
}
}
The problem is probably on context?.clip(to: rect, mask: context as! CGImage) (I think I shouldn't send context as the mask, but what should I send? Both CGImage() and CGImage.self don't work.
You have to do as follow:
extension UIImage {
func tinted(with color: UIColor) -> UIImage? {
defer { UIGraphicsEndImageContext() }
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
You need to end the image context when you finish drawing:
UIGraphicsEndImageContext();
Or you could add a category method for UIImage:
- (UIImage *)imageByTintColor:(UIColor *)color
{
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
[color set];
UIRectFill(rect);
[self drawAtPoint:CGPointMake(0, 0) blendMode:kCGBlendModeDestinationIn alpha:1];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Using as:
image = [image imageByTintColor:color];
Simplest way to doing this
theImageView.image? = (theImageView.image?.imageWithRenderingMode(.AlwaysTemplate))!
theImageView.tintColor = UIColor.magentaColor()
let image = UIImage(named: "whatever.png")?.imageWithRenderingMode(.alwaysTemplate)
When you set this image later to UIButton or UIImageView - just change tint color of that control, and image will be drawn using tint color you specified.

Capture UITableView as Image - With Scrolling

My Swift code for capturing a UITableView as an image isn't working when the table is scrolled down. I essentially have the answer in Objective-C but can't seem to make it work in Swift. Currently this is what I have in Swift:
func snapshotOfCell (inputView: UIView) -> UIView {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
inputView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext() as UIImage
UIGraphicsEndImageContext()
let cellSnapshot : UIView = UIImageView(image: image)
cellSnapshot.layer.masksToBounds = false
return cellSnapshot
}
I found this answer but it's in Objective-C:
-(UIImage *) imageWithTableView:(UITableView *)tableView {
UIView *renderedView = tableView;
CGPoint tableContentOffset = tableView.contentOffset;
UIGraphicsBeginImageContextWithOptions(renderedView.bounds.size, renderedView.opaque, 0.0);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(contextRef, 0, -tableContentOffset.y);
[tableView.layer renderInContext:contextRef];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
It seems to fix the scroll problem by using a contentOffset. However, I've been trying to integrate it into my Swift function without success. Anyone good with both Objective-C and Swift? Thanks!
capture whole tableview as a image
UIGraphicsBeginImageContextWithOptions(CGSizeMake(tableView.contentSize.width, tableView.contentSize.height),false, 0.0)
let context = UIGraphicsGetCurrentContext()
let previousFrame = tableView.frame
tableView.frame = CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.contentSize.width, tableView.contentSize.height);
tableView.layer.renderInContext(context!)
tableView.frame = previousFrame
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
imageView.image = image;
capture the screenshot of tableview in a scrolled position
let contentOffset = tableView.contentOffset
UIGraphicsBeginImageContextWithOptions(tableView.bounds.size, true, 1)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, -contentOffset.y)
tableView.layer.renderInContext(context!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageView.image = image;
Swift 3.0 version for capturing entire tableview based on #Jeyamahesan's answer
UIGraphicsBeginImageContextWithOptions(CGSize(width:tableView.contentSize.width, height:tableView.contentSize.height),false, 0.0)
let context = UIGraphicsGetCurrentContext()
let previousFrame = tableView.frame
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.contentSize.width, height: tableView.contentSize.height)
tableView.layer.render(in: context!)
tableView.frame = previousFrame
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
Try this piece of code:
-(UIImage *)screenshot {
UIImage *image = nil;
UIGraphicsBeginImageContextWithOptions(tableView.contentSize, false, 0.0);
{
CGPoint savedContentOffset = tableView.contentOffset;
CGRect savedFrame = tableView.frame;
tableView.contentOffset = CGPointMake(0.0, 0.0);
tableView.frame = CGRectMake(0, 0.0, tableView.contentSize.width, tableView.contentSize.height);
[tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
tableView.contentOffset = savedContentOffset;
tableView.frame = savedFrame;
}
UIGraphicsEndImageContext();
return image;
}
Happy Coding..!!
Please try this one Its may be help to you
- (UIImage*)buildImage:(UIImage*)image
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
[image drawAtPoint:CGPointZero];
CGFloat scale;
scale = image.size.width / _workingView.frame.size.width;
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
NSLog(#"%f",scale);
[tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tmp;
}

How can I change image tintColor

I'm receiving image from a server, then based on a color chosen by the user, the image color will be changed.
I tried the following :
_sketchImageView.image = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[_sketchImageView setTintColor:color];
i got the opposite of my goal (the white color outside UIImage is colored with the chosen color).
what is going wrong?
i need to do the same in this question,the provided solution doesn't solve my case.
How can I change image tintColor in iOS and WatchKit
Try to generate new image for yourself
UIImage *newImage = [_sketchImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
[yourTintColor set];
[newImage drawInRect:CGRectMake(0, 0, image.size.width, newImage.size.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
_sketchImageView.image = newImage;
And use it.
Good luck
======= UPDATE =======
This solution will only change color of all pixel's image.
Example: we have a book image: http://pngimg.com/upload/book_PNG2113.png
And after running above code (exp: TintColor is RED). We have:
SO: how your image is depends on how you designed it
In Swift you can use this extension: [Based on #VietHung's objective-c solution]
Swift 5:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
Previous Swift version:
extension UIImage {
func imageWithColor(color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.AlwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.drawInRect(CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
In swift 2.0 you can use this
let image = UIImage(named:"your image name")?.imageWithRenderingMode(.AlwaysTemplate)
let yourimageView.tintColor = UIColor.redColor()
yourimageView.image = image
In swift 3.0 you can use this
let image = UIImage(named:"your image name")?.withRenderingMode(.alwaysTemplate)
let yourimageView.tintColor = UIColor.red
yourimageView.image = image
Try something like this
UIImage *originalImage = _sketchImageView.image
UIImage *newImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,50,50)]; // your image size
imageView.tintColor = [UIColor redColor]; // or whatever color that has been selected
imageView.image = newImage;
_sketchImageView.image = imageView.image;
Hope this helps.
In Swift 3.0 you can use this extension: [Based on #VietHung's objective-c solution]
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image = imageWithRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
For Swift 3.0, I made a custom subclass of UIImageView called TintedUIImageView. Now the image uses whatever tint color is set in interface builder or code
class TintedUIImageView: UIImageView {
override func awakeFromNib() {
if let image = self.image {
self.image = image.withRenderingMode(.alwaysTemplate)
}
}
}
You can try:
_sketchImageView.image = [self imageNamed:#"imageName" withColor:[UIColor blackColor]];
- (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color
{
// load the image
//NSString *name = #"badge.png";
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContext(img.size);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[color setFill];
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to color burn, and the original image
CGContextSetBlendMode(context, kCGBlendModeColorBurn);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the color-burned image
return coloredImg;
}
Try setting the tint color on the superview of the image view. E.g. [self.view setTintColor:color];
in Swift 4 you can simply make an extension like that:
import UIKit
extension UIImageView {
func tintImageColor(color: UIColor) {
guard let image = image else { return }
self.image = image.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
self.tintColor = color
}
}
- SWIFT 4
extension UIImage {
func imageWithColor(_ color: UIColor) -> UIImage? {
var image: UIImage? = withRenderingMode(.alwaysTemplate)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.set()
image?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Here's how I apply and use tints in IOS 9 with Swift.
//apply a color to an image
//ref - http://stackoverflow.com/questions/28427935/how-can-i-change-image-tintcolor
//ref - https://www.captechconsulting.com/blogs/ios-7-tutorial-series-tint-color-and-easy-app-theming
func getTintedImage() -> UIImageView {
var image : UIImage;
var imageView : UIImageView;
image = UIImage(named: "someAsset")!;
let size : CGSize = image.size;
let frame : CGRect = CGRectMake((UIScreen.mainScreen().bounds.width-86)/2, 600, size.width, size.height);
let redCover : UIView = UIView(frame: frame);
redCover.backgroundColor = UIColor.redColor();
redCover.layer.opacity = 0.75;
imageView = UIImageView();
imageView.image = image.imageWithRenderingMode(UIImageRenderingMode.Automatic);
imageView.addSubview(redCover);
return imageView;
}
One thing you can do is, just add your images to Assets folder in XCode and then change the rendering mode to Template Image, so whenever you change the tint color of UIImageView, it will automatically makes change to image.
Check this link out -> https://www.google.co.in/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwiM0YXO0ejTAhUIQ48KHfGpBpgQjRwIBw&url=https%3A%2F%2Fkrakendev.io%2Fblog%2F4-xcode-asset-catalog-secrets-you-need-to-know&psig=AFQjCNGnAzVn92pCqM8612o1R0J9q1y7cw&ust=1494619445516498
let image = UIImage(named: "i m a g e n a m e")?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = UIColor.white // Change to require color
imageView.image = image
Try this
iOS 13.4 and above
UIImage *image = [UIImage imageNamed:#"placeHolderIcon"];
[image imageWithTintColor:[UIColor whiteColor] renderingMode: UIImageRenderingModeAlwaysTemplate];

How to create a black UIImage?

I've looked around everywhere, but I can't find a way to do this. I need to create a black UIImage of a certain width and height (The width and height change, so I can't just create a black box and then load it into a UIImage). Is there some way to make a CGRect and then convert it to a UIImage? Or is there some other way to make a simple black box?
Depending on your situation, you could probably just use a UIView with its backgroundColor set to [UIColor blackColor]. Also, if the image is solidly-colored, you don't need an image that's actually the dimensions you want to display it at; you can just scale a 1x1 pixel image to fill the necessary space (e.g., by setting the contentMode of a UIImageView to UIViewContentModeScaleToFill).
Having said that, it may be instructive to see how to actually generate such an image:
Objective-C
CGSize imageSize = CGSizeMake(64, 64);
UIColor *fillColor = [UIColor blackColor];
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[fillColor setFill];
CGContextFillRect(context, CGRectMake(0, 0, imageSize.width, imageSize.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Swift
let imageSize = CGSize(width: 420, height: 120)
let color: UIColor = .black
UIGraphicsBeginImageContextWithOptions(imageSize, true, 0)
let context = UIGraphicsGetCurrentContext()!
color.setFill()
context.fill(CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
UIGraphicsBeginImageContextWithOptions(CGSizeMake(w,h), NO, 0);
UIBezierPath* p =
[UIBezierPath bezierPathWithRect:CGRectMake(0,0,w,h)];
[[UIColor blackColor] setFill];
[p fill];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Now im is the image.
That code comes almost unchanged from this section of my book: http://www.apeth.com/iOSBook/ch15.html#_graphics_contexts
Swift 3:
func uiImage(from color:UIColor?, size:CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
defer {
UIGraphicsEndImageContext()
}
let context = UIGraphicsGetCurrentContext()
color?.setFill()
context?.fill(CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
return UIGraphicsGetImageFromCurrentImageContext()
}
Like this
let image = UIGraphicsImageRenderer(size: bounds.size).image { _ in
UIColor.black.setFill()
UIRectFill(bounds)
}
As quoted in this WWDC vid
There's another function that's older; UIGraphicsBeginImageContext. But please, don't use that.
Here is an example that creates a black UIImage that is 1920x1080 by creating it from a CGImage created from a CIImage:
let frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 1920, height: 1080))
let cgImage = CIContext().createCGImage(CIImage(color: .black()), from: frame)!
let uiImage = UIImage(cgImage: cgImage)

The simplest way to resize an UIImage?

In my iPhone app, I take a picture with the camera, then I want to resize it to 290*390 pixels. I was using this method to resize the image :
UIImage *newImage = [image _imageScaledToSize:CGSizeMake(290, 390)
interpolationQuality:1];
It works perfectly, but it's an undocumented function, so I can't use it anymore with iPhone OS4.
So... what is the simplest way to resize an UIImage ?
The simplest way is to set the frame of your UIImageView and set the contentMode to one of the resizing options.
Or you can use this utility method, if you actually need to resize an image:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Example usage:
#import "MYUtil.h"
…
UIImage *myIcon = [MYUtil imageWithImage:myUIImageInstance scaledToSize:CGSizeMake(20, 20)];
Proper Swift 3.0 for iOS 10+ solution: Using ImageRenderer and closure syntax:
func imageWith(newSize: CGSize) -> UIImage {
let image = UIGraphicsImageRenderer(size: newSize).image { _ in
draw(in: CGRect(origin: .zero, size: newSize))
}
return image.withRenderingMode(renderingMode)
}
And here's the Objective-C version:
#implementation UIImage (ResizeCategory)
- (UIImage *)imageWithSize:(CGSize)newSize
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize];
UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) {
[self drawInRect:(CGRect) {.origin = CGPointZero, .size = newSize}];
}];
return [image imageWithRenderingMode:self.renderingMode];
}
#end
Here's a Swift version of Paul Lynch's answer
func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
And as an extension:
public extension UIImage {
func copy(newSize: CGSize, retina: Bool = true) -> UIImage? {
// In next line, pass 0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(
/* size: */ newSize,
/* opaque: */ false,
/* scale: */ retina ? 0 : 1
)
defer { UIGraphicsEndImageContext() }
self.draw(in: CGRect(origin: .zero, size: newSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
A more compact version for Swift 4 and iOS 10+:
extension UIImage {
func resized(to size: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}
Usage:
let resizedImage = image.resized(to: CGSize(width: 50, height: 50))
Swift solution for Stretch Fill, Aspect Fill and Aspect Fit
extension UIImage {
enum ContentMode {
case contentFill
case contentAspectFill
case contentAspectFit
}
func resize(withSize size: CGSize, contentMode: ContentMode = .contentAspectFill) -> UIImage? {
let aspectWidth = size.width / self.size.width
let aspectHeight = size.height / self.size.height
switch contentMode {
case .contentFill:
return resize(withSize: size)
case .contentAspectFit:
let aspectRatio = min(aspectWidth, aspectHeight)
return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
case .contentAspectFill:
let aspectRatio = max(aspectWidth, aspectHeight)
return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
}
}
private func resize(withSize size: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
and to use you can do the following:
let image = UIImage(named: "image.png")!
let newImage = image.resize(withSize: CGSize(width: 200, height: 150), contentMode: .contentAspectFill)
Thanks to abdullahselek for his original solution.
Trevor Howard has some UIImage categories that handle resize quite nicely. If nothing else you can use the code as examples.
Note: As of iOS 5.1, this answer maybe invalid. See comment below.
I've also seen this done as well (which I use on UIButtons for Normal and Selected state since buttons don't resize to fit). Credit goes to whoever the original author was.
First make an empty .h and .m file called UIImageResizing.h and UIImageResizing.m
// Put this in UIImageResizing.h
#interface UIImage (Resize)
- (UIImage*)scaleToSize:(CGSize)size;
#end
// Put this in UIImageResizing.m
#implementation UIImage (Resize)
- (UIImage*)scaleToSize:(CGSize)size {
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage);
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
#end
Include that .h file in whatever .m file you're going to use the function in and then call it like this:
UIImage* image = [UIImage imageNamed:#"largeImage.png"];
UIImage* smallImage = [image scaleToSize:CGSizeMake(100.0f,100.0f)];
This improvement to Paul's code will give you a sharp high res image on an iPhone with a retina display. Otherwise when scaling down it's blurry.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);
} else {
UIGraphicsBeginImageContext(newSize);
}
} else {
UIGraphicsBeginImageContext(newSize);
}
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Here is a simple way:
UIImage * image = [UIImage imageNamed:#"image"];
CGSize sacleSize = CGSizeMake(10, 10);
UIGraphicsBeginImageContextWithOptions(sacleSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, sacleSize.width, sacleSize.height)];
UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
resizedImage is a new image.
Here's a modification of the category written by iWasRobbed above. It keeps the aspect ratio of the original image instead of distorting it.
- (UIImage*)scaleToSizeKeepAspect:(CGSize)size {
UIGraphicsBeginImageContext(size);
CGFloat ws = size.width/self.size.width;
CGFloat hs = size.height/self.size.height;
if (ws > hs) {
ws = hs/ws;
hs = 1.0;
} else {
hs = ws/hs;
ws = 1.0;
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(size.width/2-(size.width*ws)/2,
size.height/2-(size.height*hs)/2, size.width*ws,
size.height*hs), self.CGImage);
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
Why so complicated? I think using system API can achieve the same result:
UIImage *largeImage;
CGFloat ratio = 0.4; // you want to get a new image that is 40% the size of large image.
UIImage *newImage = [UIImage imageWithCGImage:largeImage.CGImage
scale:1/ratio
orientation:largeImage.imageOrientation];
// notice the second argument, it is 1/ratio, not ratio.
The only gotcha is you should pass inverse of target ratio as the second argument, as according to the document the second parameter specifies the ratio of original image compared to the new scaled one.
For Swift 5:
extension UIImage {
func resized(to newSize: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: newSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
If you just want an image smaller and don't care about exact size:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToScale:(CGFloat)scale
{
UIGraphicsBeginImageContextWithOptions(self.size, YES, scale);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Setting scale to 0.25f will give you a 816 by 612 image from a 8MP camera.
Here's a category UIImage+Scale for those who needs one.
This is an UIImage extension compatible with Swift 3 and Swift 4 which scales image to given size with an aspect ratio
extension UIImage {
func scaledImage(withSize size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
return UIGraphicsGetImageFromCurrentImageContext()!
}
func scaleImageToFitSize(size: CGSize) -> UIImage {
let aspect = self.size.width / self.size.height
if size.width / aspect <= size.height {
return scaledImage(withSize: CGSize(width: size.width, height: size.width / aspect))
} else {
return scaledImage(withSize: CGSize(width: size.height * aspect, height: size.height))
}
}
}
Example usage
let image = UIImage(named: "apple")
let scaledImage = image.scaleImageToFitSize(size: CGSize(width: 45.0, height: 45.0))
When using iOS 15 or newer, you can use the new prepareThumbnail method of UIImage:
sourceImage.prepareThumbnail(of: thumbnailSize) { thumbnail in
// Do something with the resized image
DispatchQueue.main.async {
cell.imageView?.image = thumbnail
}
}
More info here:
https://developer.apple.com/documentation/uikit/uiimage/3750845-preparethumbnail
I found a category for UIImage in Apple's own examples which does the same trick. Here's the link: https://developer.apple.com/library/ios/samplecode/sc2273/Listings/AirDropSample_UIImage_Resize_m.html.
You'll just have to change the call:
UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);
in imageWithImage:scaledToSize:inRect: with:
UIGraphicsBeginImageContextWithOptions(newSize, NO, 2.0);
In order to consider the alpha channel in the image.
For my fellow Xamarians, here is a Xamarin.iOS C# version of #Paul Lynch answer.
private UIImage ResizeImage(UIImage image, CGSize newSize)
{
UIGraphics.BeginImageContextWithOptions(newSize, false, 0.0f);
image.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return newImage;
}
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage
{
let scale = newWidth / image.size.width
let newHeight = image.size.height * scale
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Effective approach without stretching image Swift 4
// Method to resize image
func resize(image: UIImage, toScaleSize:CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(toScaleSize, true, image.scale)
                image.draw(in: CGRect(x: 0, y: 0, width: toScaleSize.width, height: toScaleSize.height))
                let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return scaledImage!
        }
// Call method
let resizedImage = self.resize(image: UIImage(named: "YourImageName")!, toScaleSize: CGSize(width: 290, height: 390))
If you want to make a thumbnail of a UIImage (with proportional resizing or maybe some cropping involved), check out UIImage+Resize category that allows you to use concise, ImageMagick-like syntax:
UIImage* squareImage = [image resizedImageByMagick: #"320x320#"];
[cf Chris] To resize to a desired size:
UIImage *after = [UIImage imageWithCGImage:before.CGImage
scale:CGImageGetHeight(before.CGImage)/DESIREDHEIGHT
orientation:UIImageOrientationUp];
or, equivalently, substitute CGImageGetWidth(...)/DESIREDWIDTH
Rogerio Chaves answer as a swift extension
func scaledTo(size: CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(size, false, 0.0);
self.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
And also bonus
func scaledTo(height: CGFloat) -> UIImage{
let width = height*self.size.width/self.size.height
return scaledTo(size: CGSize(width: width, height: height))
}
Swift 3.0 with failsafe option (returns the original image in case of error):
func resize(image: UIImage, toSize size: CGSize) -> UIImage{
UIGraphicsBeginImageContextWithOptions(size,false,1.0)
image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
if let resizedImage = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
return resizedImage
}
UIGraphicsEndImageContext()
return image
}
(Swift 4 compatible) iOS 10+ and iOS < 10 solution (using UIGraphicsImageRenderer if possible, UIGraphicsGetImageFromCurrentImageContext otherwise)
/// Resizes an image
///
/// - Parameter newSize: New size
/// - Returns: Resized image
func scaled(to newSize: CGSize) -> UIImage {
let rect = CGRect(origin: .zero, size: newSize)
if #available(iOS 10, *) {
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
self.draw(in: rect)
}
} else {
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
#Paul Lynch's answer is great, but it would change the image ratio.
if you don`t want to change the image ratio, and still want the new image fit for new size, try this.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
// calculate a new size which ratio is same to original image
CGFloat ratioW = image.size.width / newSize.width;
CGFloat ratioH = image.size.height / newSize.height;
CGFloat ratio = image.size.width / image.size.height;
CGSize showSize = CGSizeZero;
if (ratioW > 1 && ratioH > 1) {
if (ratioW > ratioH) {
showSize.width = newSize.width;
showSize.height = showSize.width / ratio;
} else {
showSize.height = newSize.height;
showSize.width = showSize.height * ratio;
}
} else if (ratioW > 1) {
showSize.width = showSize.width;
showSize.height = showSize.width / ratio;
} else if (ratioH > 1) {
showSize.height = showSize.height;
showSize.width = showSize.height * ratio;
}
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(showSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, showSize.width, showSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;}
use this extension
extension UIImage {
public func resize(size:CGSize, completionHandler:(resizedImage:UIImage, data:NSData?)->()) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), { () -> Void in
let newSize:CGSize = size
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let imageData = UIImageJPEGRepresentation(newImage, 0.5)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
completionHandler(resizedImage: newImage, data:imageData)
})
})
}
}
Some time your image have scale large than 1 so that resize image will make an image unexpected. This is my solution for this case.
extension UIImage {
func resizeTo(newSize: CGSize) -> UIImage {
// Important thing here
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let image = UIGraphicsImageRenderer(size: newSize, format: format).image { _ in
draw(in: CGRect(origin: .zero, size: newSize))
}
return image.withRenderingMode(renderingMode)
}
}
Swift 2.0 :
let image = UIImage(named: "imageName")
let newSize = CGSize(width: 10, height: 10)
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image?.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let imageResized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Here my somewhat-verbose Swift code
func scaleImage(image:UIImage, toSize:CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(toSize, false, 0.0);
let aspectRatioAwareSize = self.aspectRatioAwareSize(image.size, boxSize: toSize, useLetterBox: false)
let leftMargin = (toSize.width - aspectRatioAwareSize.width) * 0.5
let topMargin = (toSize.height - aspectRatioAwareSize.height) * 0.5
image.drawInRect(CGRectMake(leftMargin, topMargin, aspectRatioAwareSize.width , aspectRatioAwareSize.height))
let retVal = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return retVal
}
func aspectRatioAwareSize(imageSize: CGSize, boxSize: CGSize, useLetterBox: Bool) -> CGSize {
// aspect ratio aware size
// http://stackoverflow.com/a/6565988/8047
let imageWidth = imageSize.width
let imageHeight = imageSize.height
let containerWidth = boxSize.width
let containerHeight = boxSize.height
let imageAspectRatio = imageWidth/imageHeight
let containerAspectRatio = containerWidth/containerHeight
let retVal : CGSize
// use the else at your own risk: it seems to work, but I don't know
// the math
if (useLetterBox) {
retVal = containerAspectRatio > imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
} else {
retVal = containerAspectRatio < imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
}
return retVal
}
Swift 4 answer:
func scaleDown(image: UIImage, withSize: CGSize) -> UIImage {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(withSize, false, scale)
image.draw(in: CGRect(x: 0, y: 0, width: withSize.width, height: withSize.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}

Resources