Как уменьшить UIImage и сделать его хрустящим / острым одновременно вместо размытого?
Мне нужно уменьшить изображение, но резким способом. В Photoshop, например, есть опции уменьшения размера изображения " Bicubic Smoother "(размытый) и"Bicubic Sharper".
является ли этот алгоритм масштабирования изображений открытым исходным кодом или документированным где-то или SDK предлагает методы для этого?
7 ответов:
просто используя
imageWithCGImage
недостаточно. Он будет масштабироваться, но результат будет размытым и неоптимальным, будь то масштабирование вверх или вниз.Если вы хотите получить правильный псевдоним и избавиться от" jaggies " вам нужно что-то вроде этого:http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/.
мой рабочий тестовый код выглядит примерно так, что это решение Тревора с одной небольшой настройкой для работы с моим прозрачным 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; }
для тех, кто использует Swift вот принятый ответ в 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 }
Если кто-то ищет Swift-версию, вот Swift-версия принятого ответа @Dan Rosenstark:
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 }
Если вы сохраняете исходное соотношение сторон изображения при масштабировании, вы всегда будете иметь четкое изображение независимо от того, насколько вы уменьшаете масштаб.
вы можете использовать следующий метод для масштабирования:
+ (UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
Для 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 }
@YAR ваше решение работает правильно.
есть только одна вещь, которая не соответствует моим требованиям: вся картина изменяется. Я написал метод, который сделал это как
photos app on iphone
. Это вычисляет " длинную сторону "и отсекает" наложение", что приводит к получению гораздо лучших результатов в отношении качества изображения.- (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 ; }
Это расширение должно масштабировать изображение, сохраняя исходное соотношение сторон. Остальная часть изображения обрезается. (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 } }