使用iPhone SDK调整/优化图像大小的最简单方法是什么?

我的应用程序正在从网络下载一组图像文件,并将其保存到本地iPhone磁盘。 其中一些图像的尺寸非常大(例如,宽度大于500像素)。 由于iPhone甚至没有足够大的显示器来显示原始尺寸的图像,因此我打算将图像的尺寸调整得小一点以节省空间/性能。

此外,这些图像中的一些是JPEG,并不像通常的60%质量设置那样保存。

如何使用iPhone SDK调整图片大小,以及如何更改JPEG图像的质量设置?

提供了几个建议作为这个问题的答案。 我已经建议在这篇文章中描述的技术,与相关的代码:

+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; { UIGraphicsBeginImageContext( newSize ); [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

就图像的存储而言,与iPhone一起使用的最快的图像格式是PNG,因为它对该格式进行了优化。 但是,如果要将这些图像存储为JPEG,则可以使用UIImage并执行以下操作:

 NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6); 

这将创建一个包含60%质量设置的JPEG图像的原始字节的NSData实例。 该NSData实例的内容然后可以写入磁盘或缓存在内存中。

调整图像大小的最简单最直接的方法就是这样

 float actualHeight = image.size.height; float actualWidth = image.size.width; float imgRatio = actualWidth/actualHeight; float maxRatio = 320.0/480.0; if(imgRatio!=maxRatio){ if(imgRatio < maxRatio){ imgRatio = 480.0 / actualHeight; actualWidth = imgRatio * actualWidth; actualHeight = 480.0; } else{ imgRatio = 320.0 / actualWidth; actualHeight = imgRatio * actualHeight; actualWidth = 320.0; } } CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight); UIGraphicsBeginImageContext(rect.size); [image drawInRect:rect]; UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

上述方法适用于小图像,但是当您尝试调整一个非常大的图像时,会很快耗尽内存并使应用程序崩溃。 更好的方法是使用CGImageSourceCreateThumbnailAtIndex调整图像的大小,而不是先完全解码。

如果您有要调整图像的路径,可以使用以下命令:

 - (void)resizeImageAtPath:(NSString *)imagePath { // Create the image source (from path) CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL); // To create image source from UIImage, use this // NSData* pngData = UIImagePNGRepresentation(image); // CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL); // Create thumbnail options CFDictionaryRef options = (__bridge CFDictionaryRef) @{ (id) kCGImageSourceCreateThumbnailWithTransform : @YES, (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES, (id) kCGImageSourceThumbnailMaxPixelSize : @(640) }; // Generate the thumbnail CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); CFRelease(src); // Write the thumbnail at path CGImageWriteToFile(thumbnail, imagePath); } 

更多细节在这里 。

最好的方式来缩放图像,而不失去纵横比(即没有延长的责任)是使用这种方法:

 //to scale images without changing aspect ratio + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize { float width = newSize.width; float height = newSize.height; UIGraphicsBeginImageContext(newSize); CGRect rect = CGRectMake(0, 0, width, height); float widthRatio = image.size.width / width; float heightRatio = image.size.height / height; float divisor = widthRatio > heightRatio ? widthRatio : heightRatio; width = image.size.width / divisor; height = image.size.height / divisor; rect.size.width = width; rect.size.height = height; //indent in case of width or height difference float offset = (width - height) / 2; if (offset > 0) { rect.origin.y = offset; } else { rect.origin.x = -offset; } [image drawInRect: rect]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return smallImage; } 

将此方法添加到Utility类中,以便可以在整个项目中使用它,并像这样访问它:

 xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size]; 

此方法在保持高宽比的同时保持缩放比例。 如果缩小图像的宽度比高度更宽(反之亦然),则还会在图像中添加缩进。

如果你有控制服务器,我强烈建议用ImageMagik调整图像服务器端的大小。 下载大图像并在手机上调整大小会浪费许多宝贵的资源 – 带宽,电池和内存。 所有这些在手机上都很少。

我在Swift中开发了一个图像缩放的最终解决方案。

您可以使用它来调整图像的大小来填充,方向填充或方面适合指定的大小。

您可以将图像对齐到四个边和四个角中的任何一个。

而且,如果原图像和目标尺寸的纵横比不相等,也可以修剪额外的空间。

 enum UIImageAlignment { case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight } enum UIImageScaleMode { case Fill, AspectFill, AspectFit(UIImageAlignment) } extension UIImage { func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage { let preWidthScale = width.map { $0 / size.width } let preHeightScale = height.map { $0 / size.height } var widthScale = preWidthScale ?? preHeightScale ?? 1 var heightScale = preHeightScale ?? widthScale switch scaleMode { case .AspectFit(_): let scale = min(widthScale, heightScale) widthScale = scale heightScale = scale case .AspectFill: let scale = max(widthScale, heightScale) widthScale = scale heightScale = scale default: break } let newWidth = size.width * widthScale let newHeight = size.height * heightScale let canvasWidth = trim ? newWidth : (width ?? newWidth) let canvasHeight = trim ? newHeight : (height ?? newHeight) UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0) var originX: CGFloat = 0 var originY: CGFloat = 0 switch scaleMode { case .AspectFit(let alignment): switch alignment { case .Center: originX = (canvasWidth - newWidth) / 2 originY = (canvasHeight - newHeight) / 2 case .Top: originX = (canvasWidth - newWidth) / 2 case .Left: originY = (canvasHeight - newHeight) / 2 case .Bottom: originX = (canvasWidth - newWidth) / 2 originY = canvasHeight - newHeight case .Right: originX = canvasWidth - newWidth originY = (canvasHeight - newHeight) / 2 case .TopLeft: break case .TopRight: originX = canvasWidth - newWidth case .BottomLeft: originY = canvasHeight - newHeight case .BottomRight: originX = canvasWidth - newWidth originY = canvasHeight - newHeight } default: break } self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight)) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } } 

下面有一些应用这个解决方案的例子。

灰色的矩形是目标网站图像将被调整大小。 浅蓝色矩形中的蓝色圆圈就是图片(我使用了圆圈,因为很容易看到它在缩放时没有保留方面)。 如果您通过trim: true ,则浅橙色标记将被修剪的区域trim: true

缩放之前和之后的宽高比

看点1(之前) 看点1(后)

方面的另一个例子是:

看点2(之前) 看点2(后)

方面符合顶部对齐:

看点3(之前) 看点3(后)

方面填充

方面填充(之前) 看点填充(之后)

填充

填满(之前) 填充(之后)

我在示例中使用了upscaling,因为它更简单,但解决方案也适用于缩小比例的问题。

对于JPEG压缩,你应该使用这个:

 let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality if let data = UIImageJPEGRepresentation(image, compressionQuality) { // ... } 

你可以用Xcode操场查看我的要点 。

您可以使用此代码按需要的大小缩放图像。

 + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize { CGSize actSize = image.size; float scale = actSize.width/actSize.height; if (scale < 1) { newSize.height = newSize.width/scale; } else { newSize.width = newSize.height*scale; } UIGraphicsBeginImageContext(newSize); [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

对于Swift 3,下面的代码缩放图像保持高宽比。 您可以在Apple的文档中阅读更多关于ImageContext 的内容 :

 extension UIImage { class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage { let scale = newHeight / image.size.height let newWidth = image.size.width * scale UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight)) image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight)) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage! } } 

要使用它,请调用resizeImage()方法:

 UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight) 

在这里增加了一些答案,但是我已经找到了一个通过文件大小而不是尺寸来调整大小的解决方案。

这将既减少图像的尺寸和质量,直到达到您给定的大小。

 func compressTo(toSizeInMB size: Double) -> UIImage? { let bytes = size * 1024 * 1024 let sizeInBytes = Int(bytes) var needCompress:Bool = true var imgData:Data? var compressingValue:CGFloat = 1.0 while (needCompress) { if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) { if data.count < sizeInBytes || compressingValue < 0.1 { needCompress = false imgData = data } else { compressingValue -= 0.1 } } } if let data = imgData { print("Finished with compression value of: \(compressingValue)") return UIImage(data: data) } return nil } private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? { let size = CGSize(width: self.size.width*factor, height: self.size.height*factor) UIGraphicsBeginImageContext(size) draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() { UIGraphicsEndImageContext() return newImage; } return nil } 

通过尺寸回答缩放信用

如果有人还在寻找更好的选择

 -(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize { UIImage *sourceImage = image; UIImage *newImage = nil; CGSize imageSize = sourceImage.size; CGFloat width = imageSize.width; CGFloat height = imageSize.height; CGFloat targetWidth = targetSize.width; CGFloat targetHeight = targetSize.height; CGFloat scaleFactor = 0.0; CGFloat scaledWidth = targetWidth; CGFloat scaledHeight = targetHeight; CGPoint thumbnailPoint = CGPointMake(0.0,0.0); if (CGSizeEqualToSize(imageSize, targetSize) == NO) { CGFloat widthFactor = targetWidth / width; CGFloat heightFactor = targetHeight / height; if (widthFactor < heightFactor) scaleFactor = widthFactor; else scaleFactor = heightFactor; scaledWidth = width * scaleFactor; scaledHeight = height * scaleFactor; // center the image if (widthFactor < heightFactor) { thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; } else if (widthFactor > heightFactor) { thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; } } // this is actually the interesting part: UIGraphicsBeginImageContext(targetSize); CGRect thumbnailRect = CGRectZero; thumbnailRect.origin = thumbnailPoint; thumbnailRect.size.width = scaledWidth; thumbnailRect.size.height = scaledHeight; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } 

在视网膜显示器上可能会出现的一个问题是图像的比例是由ImageCapture设置的。 上面的调整大小功能不会改变这一点。 在这些情况下,调整大小将不正确。

在下面的代码中,比例设置为1(不缩放),并且返回的图像具有您所期望的大小。 这是在UIGraphicsBeginImageContextWithOptions调用中完成的。

 -(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize { UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0); [theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

我结束了使用Brads技术在UIImage+Extensions创建一个scaleToFitWidth方法,如果这对任何人scaleToFitWidth用…

 -(UIImage *)scaleToFitWidth:(CGFloat)width { CGFloat ratio = width / self.size.width; CGFloat height = self.size.height * ratio; NSLog(@"W:%f H:%f",width,height); UIGraphicsBeginImageContext(CGSizeMake(width, height)); [self drawInRect:CGRectMake(0.0f,0.0f,width,height)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

然后在任何你喜欢的地方

#import "UIImage+Extensions.h"

UIImage *newImage = [image scaleToFitWidth:100.0f];

另外值得注意的是,如果你想渲染UIView中的图像,可以把它移到UIView+Extensions类中

我只想为Cocoa Swift程序员回答这个问题。 这个函数返回新的尺寸的NSImage。 你可以像这样使用这个功能。

  let sizeChangedImage = changeImageSize(image, ratio: 2) // changes image size func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage { // getting the current image size let w = image.size.width let h = image.size.height // calculating new size let w_new = w / ratio let h_new = h / ratio // creating size constant let newSize = CGSizeMake(w_new ,h_new) //creating rect let rect = NSMakeRect(0, 0, w_new, h_new) // creating a image context with new size let newImage = NSImage.init(size:newSize) newImage.lockFocus() // drawing image with new size in context image.drawInRect(rect) newImage.unlockFocus() return newImage } 

试试这个,它适合我,

  CGRect rect =CGRectMake (0, 0,1200,900); UIGraphicsBeginImageContext( rect.size ); [image drawInRect:rect]; UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData *imageData = UIImagePNGRepresentation(picture1); UIImage *img=[UIImage imageWithData:imageData]; [imageArray addObject:img]; 
 - (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(); CGContextSetInterpolationQuality(context, kCGInterpolationHigh); CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height); CGContextConcatCTM(context, flipVertical); CGContextDrawImage(context, newRect, imageRef); CGImageRef newImageRef = CGBitmapContextCreateImage(context); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; CGImageRelease(newImageRef); UIGraphicsEndImageContext(); return newImage; } 

要调整图像的大小,我使用这个函数代替DrawInRect可以得到更好的(图形)结果:

 - (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth { float lScale = pWidth / pImage.size.width; CGImageRef cgImage = pImage.CGImage; UIImage *lResult = [UIImage imageWithCGImage:cgImage scale:lScale orientation:UIImageOrientationRight]; return lResult; } 

宽高比自动照顾