我正在开发一个应用程序,在这个应用程序中,用户可能会尝试加载非常大的图像。这些图片首先在一个表格视图中以缩略图的形式显示。我原来的代码会在大图片上崩溃,所以我正在重写它,首先将图片直接下载到磁盘上。
有没有已知的方法来调整磁盘上图像的大小,而不完全将其加载到内存中,通过 UIImage
? 我目前正在尝试使用分类来调整尺寸,在 UIImage
详见 此处但我的应用程序在尝试缩略一个非常大的图像时崩溃(例如,。这个 - 警告,巨大的图像)。)
你应该看看ImageIO.framework中的CGImageSource,但它只在iOS 4.0中可用。
快速示例 。
-(UIImage*)resizeImageToMaxSize:(CGFloat)max path:(NSString*)path
{
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)[NSURL fileURLWithPath:path], NULL);
if (!imageSource)
return nil;
CFDictionaryRef options = (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
(id)@(max),
(id)kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageRef imgRef = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options);
UIImage* scaled = [UIImage imageWithCGImage:imgRef];
CGImageRelease(imgRef);
CFRelease(imageSource);
return scaled;
}
根据这个环节。iOS内存深挖我们最好使用 ImageIO
来降低图像的比例。
使用 UIImage
降级图像。
使用 ImageIO
ImageIO可以读取图像的大小和元数据信息,而不会弄脏内存。
ImageIO可以调整图像的大小,但只需要支付调整图像大小的费用。
关于内存中的图像
UIGraphicsBeginImageContextWithOptions
总是使用 SRGB
渲染格式,每像素使用4个字节。load -> decode -> render
3个阶段。UIImage
上浆和调整尺寸的成本很高。对于下面的图片,如果你使用 UIGraphicsBeginImageContextWithOptions
我们只需要590KB就可以加载一张图片,而我们却需要2048 pixels x 1536 pixels x 4 bytes per pixel
解码时=10MB
而 UIGraphicsImageRenderer
在iOS10中引入的iOS12将自动选择最佳的图形格式。这意味着,在iOS12中,你可以通过更换图片来节省75%的内存。UIGraphicsBeginImageContextWithOptions
与 UIGraphicsImageRenderer
如果你不需要SRGB。
这是我的文章,关于 记忆中的iOS图像
func resize(url: NSURL, maxPixelSize: Int) -> CGImage? {
let imgSource = CGImageSourceCreateWithURL(url, nil)
guard let imageSource = imgSource else {
return nil
}
var scaledImage: CGImage?
let options: [NSString: Any] = [
// The maximum width and height in pixels of a thumbnail.
kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
kCGImageSourceCreateThumbnailFromImageAlways: true,
// Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
kCGImageSourceCreateThumbnailWithTransform: true
]
scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
return scaledImage
}
let filePath = Bundle.main.path(forResource:"large_leaves_70mp", ofType: "jpg")
let url = NSURL(fileURLWithPath: filePath ?? "")
let image = resize(url: url, maxPixelSize: 600)
或
// Downsampling large images for display at smaller size
func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
let downsampleOptions =
[kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true,
// Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
let downsampledImage =
CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
return UIImage(cgImage: downsampledImage)
}