iOS Swift: How to properly scale down an image? - ios

I'm using AlamofireImage to download and set my UIImage:
backdrop.af_setImageWithURL(downloadURL)
The image is substantially larger than what I will be displaying and so I have an issue with aliasing. How can I resize this image properly?
Results:

You can resize the image with any size once you have a valid UIImage:
func resizedImageWith(image: UIImage, targetSize: CGSize) -> UIImage {
let imageSize = image.size
let newWidth = targetSize.width / image.size.width
let newHeight = targetSize.height / image.size.height
var newSize: CGSize
if(newWidth > newHeight) {
newSize = CGSizeMake(imageSize.width * newHeight, imageSize.height * newHeight)
} else {
newSize = CGSizeMake(imageSize.width * newWidth, imageSize.height * newWidth)
}
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
For any other queries/modifications you have, refer this NShipster

Here is #Santosh's answer in ObjC:
- (UIImage*) scaleImage:(UIImage*)image toSize:(CGSize)newSize {
CGSize imageSize = image.size;
CGFloat newWidth = newSize.width / image.size.width;
CGFloat newHeight = newSize.height / image.size.height;
CGSize newImgSize;
if(newWidth > newHeight) {
newImgSize = CGSizeMake(imageSize.width * newHeight, imageSize.height * newHeight);
} else {
newImgSize = CGSizeMake(imageSize.width * newWidth, imageSize.height * newWidth);
}
CGRect rect = CGRectMake(0, 0, newImgSize.width, newImgSize.height);
UIGraphicsBeginImageContextWithOptions(newImgSize, false, 0.0);
[image drawInRect:rect];;
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

Related

scale image to smaller size in swift3 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am trying to scale a image that is being graphic programmed into the photo gallery. I am trying to scale the image to make it smaller. How would I use the code below to make the image smaller
image1.scale
Use this extension to resize your image:
extension UIImage{
func resizeImageWith(newSize: CGSize) -> UIImage {
let horizontalRatio = newSize.width / size.width
let verticalRatio = newSize.height / size.height
let ratio = max(horizontalRatio, verticalRatio)
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
UIGraphicsBeginImageContextWithOptions(newSize, true, 0)
draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Basically you are calculating the aspect ratio to keep the image intact while resizing it. Then you are getting the current image context and drawing it in the specified rectangle and finally returning it as a new image.
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
}
#IBAction func chooseImage(sender: AnyObject) {
var myPickerController = UIImagePickerController()
myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
myPickerController.delegate = self;
self.presentViewController(myPickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])
{
var image = info[UIImagePickerControllerOriginalImage] as? UIImage
let scaledImage:UIImage = resizeImage(image!, newWidth: 200)
self.dismissViewControllerAnimated(true, completion: nil)
}
Swift 4 version
extension UIImage {
func resize(withWidth newWidth: CGFloat) -> UIImage? {
let scale = newWidth / self.size.width
let newHeight = self.size.height * scale
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
Try this:
First Method:
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
}
Second Method:
import UIKit
func RBSquareImageTo(image: UIImage, size: CGSize) -> UIImage {
return RBResizeImage(RBSquareImage(image), size)
}
func RBSquareImage(image: UIImage) -> UIImage {
var originalWidth = image.size.width
var originalHeight = image.size.height
var edge: CGFloat
if originalWidth > originalHeight {
edge = originalHeight
} else {
edge = originalWidth
}
var posX = (originalWidth - edge) / 2.0
var posY = (originalHeight - edge) / 2.0
var cropSquare = CGRectMake(posX, posY, edge, edge)
var imageRef = CGImageCreateWithImageInRect(image.CGImage, cropSquare);
return UIImage(CGImage: imageRef, scale: UIScreen.mainScreen().scale, orientation: image.imageOrientation)
}
func RBResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Reference:
Here
Here
This may be helpful, this method will do proportional resizing of the image with good quality.
func resizeImage(image: UIImage, withSize: CGSize) -> UIImage {
var actualHeight: CGFloat = image.size.height
var actualWidth: CGFloat = image.size.width
let maxHeight: CGFloat = withSize.width
let maxWidth: CGFloat = withSize.height
var imgRatio: CGFloat = actualWidth/actualHeight
let maxRatio: CGFloat = maxWidth/maxHeight
let compressionQuality = 0.5//50 percent compression
if (actualHeight > maxHeight || actualWidth > maxWidth) {
if(imgRatio < maxRatio) {
//adjust width according to maxHeight
imgRatio = maxHeight / actualHeight
actualWidth = imgRatio * actualWidth
actualHeight = maxHeight
} else if(imgRatio > maxRatio) {
//adjust height according to maxWidth
imgRatio = maxWidth / actualWidth
actualHeight = imgRatio * actualHeight
actualWidth = maxWidth
} else {
actualHeight = maxHeight
actualWidth = maxWidth
}
}
let rect: CGRect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
UIGraphicsBeginImageContext(rect.size)
image.draw(in: rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
let imageData = UIImageJPEGRepresentation(image, CGFloat(compressionQuality))
UIGraphicsEndImageContext()
let resizedImage = UIImage(data: imageData!)
return resizedImage!
}
Call this methods like this,
resizeImage(image: UIImage(named: "ImageName"), withSize: CGSize(width: 300, height: 300))
Thanks:)

Resize Image without losing quality

I'm using the functions below to resize my images width & height but I noticed that it ruins the image quality.
class func imageWithSize(image: UIImage,size: CGSize)->UIImage{
if UIScreen.mainScreen().respondsToSelector("scale"){
UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
}
else
{
UIGraphicsBeginImageContext(size);
}
image.drawInRect(CGRectMake(0, 0, size.width, size.height));
var newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
class func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
{
let scaleFactor = width / height;
let newSize = CGSizeMake(width, height);
return imageWithSize(image, size: newSize);
}
Is there another way to resize images without ruining the quality? Or how can I fix my functions below so it doesn't ruin the image quality after resizing?
Here is my code in swift. For squared images, it works really well and without any loss of quality!
extension UIImage {
func resize(targetSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size:targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}
Here is my Objective-C code. It's work for me.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize isAspectRation:(BOOL)aspect {
if (!image) {
return nil;
}
//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.
CGFloat originRatio = image.size.width / image.size.height;
CGFloat newRatio = newSize.width / newSize.height;
CGSize sz;
if (!aspect) {
sz = newSize;
}else {
if (originRatio < newRatio) {
sz.height = newSize.height;
sz.width = newSize.height * originRatio;
}else {
sz.width = newSize.width;
sz.height = newSize.width / originRatio;
}
}
CGFloat scale = 1.0;
// if([[UIScreen mainScreen]respondsToSelector:#selector(scale)]) {
// CGFloat tmp = [[UIScreen mainScreen]scale];
// if (tmp > 1.5) {
// scale = 2.0;
// }
// }
sz.width /= scale;
sz.height /= scale;
UIGraphicsBeginImageContextWithOptions(sz, NO, scale);
[image drawInRect:CGRectMake(0, 0, sz.width, sz.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I saw your code in Swift. I just convert my Objective-C to Swift without test. Can you try it and let's me know. Thanks!
struct CommonUtils {
static func imageWithImage(image: UIImage, scaleToSize newSize: CGSize, isAspectRation aspect: Bool) -> UIImage{
let originRatio = image.size.width / image.size.height;//CGFloat
let newRatio = newSize.width / newSize.height;
var sz: CGSize = CGSizeZero
if (!aspect) {
sz = newSize
}else {
if (originRatio < newRatio) {
sz.height = newSize.height
sz.width = newSize.height * originRatio
}else {
sz.width = newSize.width
sz.height = newSize.width / originRatio
}
}
let scale: CGFloat = 1.0
sz.width /= scale
sz.height /= scale
UIGraphicsBeginImageContextWithOptions(sz, false, scale)
image.drawInRect(CGRectMake(0, 0, sz.width, sz.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
I just created this useful UIImage extension with swift 5. You can use it to resize your UIImages without losing quality.
I added a couple of methods in order to be able to resize an image to a width or a height keeping the aspect ratio.
extension UIImage {
func resize(targetSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size:targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
func resize(scaledToWidth desiredWidth: CGFloat) -> UIImage {
let oldWidth = size.width
let scaleFactor = desiredWidth / oldWidth
let newHeight = size.height * scaleFactor
let newWidth = oldWidth * scaleFactor
let newSize = CGSize(width: newWidth, height: newHeight)
return resize(targetSize: newSize)
}
func resize(scaledToHeight desiredHeight: CGFloat) -> UIImage {
let scaleFactor = desiredHeight / size.height
let newWidth = size.width * scaleFactor
let newSize = CGSize(width: newWidth, height: desiredHeight)
return resize(targetSize: newSize)
}
}
func image(image:UIImage,imageSize:CGSize)->UIImage
{
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
[image .drawInRect(CGRectMake(0, 3, imageSize.width, imageSize.height))]
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
return newImage;
}

Resizing UIImage Causes UIImage's Data Size Increase

I am trying to resize a UIImage with NYXImageKit and it causes the Image's Data size to increase
P.S.: originalImage's dimension is 1024 * 1024
var originalImage = image;
//originalImage SIZE 108 KB
var resizedImage = image.scaleToFillSize(CGSize(width: 256, height: 256));
//resizedImage BECAME 620 KB
Any ideas?
The code below is from NYXImageKit class
UIImage+Resizing.m
-(UIImage*)scaleToFillSize:(CGSize)newSize
{
size_t destWidth = (size_t)(newSize.width * self.scale);
size_t destHeight = (size_t)(newSize.height * self.scale);
if (self.imageOrientation == UIImageOrientationLeft
|| self.imageOrientation == UIImageOrientationLeftMirrored
|| self.imageOrientation == UIImageOrientationRight
|| self.imageOrientation == UIImageOrientationRightMirrored)
{
size_t temp = destWidth;
destWidth = destHeight;
destHeight = temp;
}
/// Create an ARGB bitmap context
CGContextRef bmContext = NYXCreateARGBBitmapContext(destWidth, destHeight, destWidth * kNyxNumberOfComponentsPerARBGPixel, NYXImageHasAlpha(self.CGImage));
if (!bmContext)
return nil;
/// Image quality
CGContextSetShouldAntialias(bmContext, true);
CGContextSetAllowsAntialiasing(bmContext, true);
CGContextSetInterpolationQuality(bmContext, kCGInterpolationHigh);
/// Draw the image in the bitmap context
UIGraphicsPushContext(bmContext);
CGContextDrawImage(bmContext, CGRectMake(0.0f, 0.0f, destWidth, destHeight), self.CGImage);
UIGraphicsPopContext();
/// Create an image object from the context
CGImageRef scaledImageRef = CGBitmapContextCreateImage(bmContext);
UIImage* scaled = [UIImage imageWithCGImage:scaledImageRef scale:self.scale orientation:self.imageOrientation];
/// Cleanup
CGImageRelease(scaledImageRef);
CGContextRelease(bmContext);
return scaled;
}
Swift Image Resizer
import UIKit
func RBSquareImageTo(image: UIImage, size: CGSize) -> UIImage {
return RBResizeImage(RBSquareImage(image), size)
}
func RBSquareImage(image: UIImage) -> UIImage {
var originalWidth = image.size.width
var originalHeight = image.size.height
var edge: CGFloat
if originalWidth > originalHeight {
edge = originalHeight
} else {
edge = originalWidth
}
var posX = (originalWidth - edge) / 2.0
var posY = (originalHeight - edge) / 2.0
var cropSquare = CGRectMake(posX, posY, edge, edge)
var imageRef = CGImageCreateWithImageInRect(image.CGImage, cropSquare);
return UIImage(CGImage: imageRef, scale: UIScreen.mainScreen().scale, orientation: image.imageOrientation)
}
func RBResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
I hope it helps you,
public func resizeImage(width width: CGFloat, height: CGFloat) -> UIImage {
let newSize: CGRect = CGRectMake(0, 0, width, height)
UIGraphicsBeginImageContext(newSize.size)
self.drawInRect(newSize)
let resizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resizedImage
}

Getting a resized image from an UIImageView

I need to upload image data to my Parse.com backend, but I found out that my pictures are way too big, dimensions wise. NSHipster had an article on image resizing with this code:
import ImageIO
if let imageSource = CGImageSourceCreateWithURL(self.URL, nil) {
let options: CFDictionary = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height) / 2.0,
kCGImageSourceCreateThumbnailFromImageIfAbsent: true
]
let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options).flatMap { UIImage(CGImage: $0) }
}
Unfortunately, this code does not compile in Swift 1.2. In particular there are 2 problems. The CFDictionary could not be initialized, and flatMap method was not recognized.
Here is some functions for resize your image:
import UIKit
func RBSquareImageTo(image: UIImage, size: CGSize) -> UIImage {
return RBResizeImage(RBSquareImage(image), size)
}
func RBSquareImage(image: UIImage) -> UIImage {
var originalWidth = image.size.width
var originalHeight = image.size.height
var edge: CGFloat
if originalWidth > originalHeight {
edge = originalHeight
} else {
edge = originalWidth
}
var posX = (originalWidth - edge) / 2.0
var posY = (originalHeight - edge) / 2.0
var cropSquare = CGRectMake(posX, posY, edge, edge)
var imageRef = CGImageCreateWithImageInRect(image.CGImage, cropSquare);
return UIImage(CGImage: imageRef, scale: UIScreen.mainScreen().scale, orientation: image.imageOrientation)
}
func RBResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
From HERE.
Here is the Objective C code that scale the image given by parameters.
-(UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

Resize UIImage without squashing

I would like to resize a UIImage to be able to upload it to parse.com. I would like to resize it without squashing it. How can I make sure that it is small enough to upload to parse.com (10485760 bytes) but not squash it to a set size.
This is the code I tried below but obviously sets the image size exactly.
Any ideas?
var newSize:CGSize = CGSize(width: 600,height: 600)
let rect = CGRectMake(0,0, newSize.width, newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
// image is a variable of type UIImage
profileImage?.drawInRect(rect)
profileImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Try using this method to scale your image while maintaining the aspect ratio:
func scaleImage(image: UIImage, maxDimension: CGFloat) -> UIImage {
var scaledSize = CGSize(width: maxDimension, height: maxDimension)
var scaleFactor: CGFloat
if image.size.width > image.size.height {
scaleFactor = image.size.height / image.size.width
scaledSize.width = maxDimension
scaledSize.height = scaledSize.width * scaleFactor
} else {
scaleFactor = image.size.width / image.size.height
scaledSize.height = maxDimension
scaledSize.width = scaledSize.height * scaleFactor
}
UIGraphicsBeginImageContext(scaledSize)
image.drawInRect(CGRectMake(0, 0, scaledSize.width, scaledSize.height))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage
}
In this case, you would call it like so:
profileImage = scaleImage(profileImage, newSize: CGSizeMake(600, 600))

Resources