我的应用程序是从网络下载一组图像文件,并将它们保存到本地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);
这将创建一个NSData实例,其中包含60%质量设置的JPEG图像的原始字节.然后可以将该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
.
缩放之前和之后的宽高比适合:
方面拟合的另一个例子:
Aspect适合顶部对齐:
方面填充:
填充:
我在我的示例中使用了upscaling,因为它更易于演示,但解决方案也适用于降尺度.
对于JPEG压缩,您应该使用:
let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality if let data = UIImageJPEGRepresentation(image, compressionQuality) { // ... }
你可以通过Xcode游乐场查看我的要点.