How to reduce the scale of UIImage and make it crispy / sharp at the same time, and not blurry?

I need to scale the image, but sharply. In Photoshop, for example, there are options for reducing the size of the image "Bicubic Smoother" (blurry) and "Bicubic Sharper".

Is this image scaling algorithm open source or documented anywhere or does it offer SDK methods for doing this?

+66
ios uikit image core-graphics scaling
May 26 '11 at 15:44
source share
7 answers

Just using imageWithCGImage not enough. It will scale, but the result will be blurry and suboptimal, whether scaling up or down.

If you want to get the right to aliases and get rid of "jaggies", you need something like this: http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right- way / .

My working test code looks something like this: Trevor solution with one small tweak to work with my transparent PNGs:

 - (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize { CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); CGImageRef imageRef = image.CGImage; UIGraphicsBeginImageContextWithOptions(newSize, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); // Set the quality level to use when rescaling CGContextSetInterpolationQuality(context, kCGInterpolationHigh); CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height); CGContextConcatCTM(context, flipVertical); // Draw into the context; this scales the image CGContextDrawImage(context, newRect, imageRef); // Get the resized image from the context and a UIImage CGImageRef newImageRef = CGBitmapContextCreateImage(context); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; CGImageRelease(newImageRef); UIGraphicsEndImageContext(); return newImage; } 
+121
Oct 15 2018-11-11T00:
source share

For those using Swift, this is the accepted answer in Swift:

 func resizeImage(image: UIImage, newSize: CGSize) -> (UIImage) { let newRect = CGRectIntegral(CGRectMake(0,0, newSize.width, newSize.height)) let imageRef = image.CGImage UIGraphicsBeginImageContextWithOptions(newSize, false, 0) let context = UIGraphicsGetCurrentContext() // Set the quality level to use when rescaling CGContextSetInterpolationQuality(context, kCGInterpolationHigh) let flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height) CGContextConcatCTM(context, flipVertical) // Draw into the context; this scales the image CGContextDrawImage(context, newRect, imageRef) let newImageRef = CGBitmapContextCreateImage(context) as CGImage let newImage = UIImage(CGImage: newImageRef) // Get the resized image from the context and a UIImage UIGraphicsEndImageContext() return newImage } 
+17
Aug 21 '14 at 15:39
source share

If someone is looking for a Swift version, here is the Swift version from @Yar's accepted answer:

 func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage { let scale = newHeight / image.size.height let newWidth = image.size.width * scale UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight)) image.drawInRect(CGRectMake(0, 0, newWidth, newHeight)) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } 
+14
Jul 27 '15 at 11:54
source share

If you keep the original aspect ratio of the image when scaling, you will always find yourself with a sharp image, no matter how much you zoom out.

The following method can be used for scaling:

 + (UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation 
+11
May 26 '11 at 15:56
source share

For Swift 3

 func resizeImage(image: UIImage, newSize: CGSize) -> (UIImage) { let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral UIGraphicsBeginImageContextWithOptions(newSize, false, 0) let context = UIGraphicsGetCurrentContext() // Set the quality level to use when rescaling context!.interpolationQuality = CGInterpolationQuality.default let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height) context!.concatenate(flipVertical) // Draw into the context; this scales the image context?.draw(image.cgImage!, in: CGRect(x: 0.0,y: 0.0, width: newRect.width, height: newRect.height)) let newImageRef = context!.makeImage()! as CGImage let newImage = UIImage(cgImage: newImageRef) // Get the resized image from the context and a UIImage UIGraphicsEndImageContext() return newImage } 
+10
Jan 09 '17 at 9:28
source share

@YAR your solution is working correctly.

There is only one that does not meet my requirements: the whole image is changed. I wrote a method that did this as photos app on iphone . This computes the โ€œlonger sideโ€ and cuts off the โ€œoverlayโ€, which results in much better results regarding image quality.

 - (UIImage *)resizeImageProportionallyIntoNewSize:(CGSize)newSize; { CGFloat scaleWidth = 1.0f; CGFloat scaleHeight = 1.0f; if (CGSizeEqualToSize(self.size, newSize) == NO) { //calculate "the longer side" if(self.size.width > self.size.height) { scaleWidth = self.size.width / self.size.height; } else { scaleHeight = self.size.height / self.size.width; } } //prepare source and target image UIImage *sourceImage = self; UIImage *newImage = nil; // Now we create a context in newSize and draw the image out of the bounds of the context to get // A proportionally scaled image by cutting of the image overlay UIGraphicsBeginImageContext(newSize); //Center image point so that on each egde is a little cutoff CGRect thumbnailRect = CGRectZero; thumbnailRect.size.width = newSize.width * scaleWidth; thumbnailRect.size.height = newSize.height * scaleHeight; thumbnailRect.origin.x = (int) (newSize.width - thumbnailRect.size.width) * 0.5; thumbnailRect.origin.y = (int) (newSize.height - thumbnailRect.size.height) * 0.5; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } 
+2
Dec 21 '12 at 12:13
source share

This extension should scale the image while maintaining the original aspect ratio. The rest of the image is cropped. (Swift 3)

 extension UIImage { func thumbnail(ofSize proposedSize: CGSize) -> UIImage? { let scale = min(size.width/proposedSize.width, size.height/proposedSize.height) let newSize = CGSize(width: size.width/scale, height: size.height/scale) let newOrigin = CGPoint(x: (proposedSize.width - newSize.width)/2, y: (proposedSize.height - newSize.height)/2) let thumbRect = CGRect(origin: newOrigin, size: newSize).integral UIGraphicsBeginImageContextWithOptions(proposedSize, false, 0) draw(in: thumbRect) let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return result } 

}

0
May 22 '17 at 12:28
source share



All Articles