According to this session, [iOS Memory Deep Dive][1], we had better use `ImageIO` to downscale images.
The bad of using `UIImage` downscale images.
- Will decompress original image into memory
- Internal coordinate space transforms are expensive
Use `ImageIO`
- ImageIO can read image sizes and metadata information without dirtying memory.
- ImageIO can resize images at cost of resized image only.
About Image in memory
- Memory use is related to the dimensions of the images, not the file size.
- `UIGraphicsBeginImageContextWithOptions` always uses `SRGB` rendering-format, which use 4 bytes per pixel.
- A image have `load -> decode -> render` 3 phases.
- `UIImage` is expensive for sizing and to resizing
For the following image, if you use `UIGraphicsBeginImageContextWithOptions`
we only need 590KB to load a image, while we need
`2048 pixels x 1536 pixels x 4 bytes per pixel` = 10MB when decoding
[![enter image description here][2]][2]
while `UIGraphicsImageRenderer`, introduced in iOS 10, will automatically pick the best graphic format in iOS12. It means, you may save 75% of memory by replacing `UIGraphicsBeginImageContextWithOptions` with `UIGraphicsImageRenderer` if you don't need SRGB.
This is my article about [iOS images in memory](
[To see links please register here]
)
```swift
func resize(url: NSURL?, maxPixelSize: Int) -> CGImage? {
guard let url = url else {
return nil;
}
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
}
DispatchQueue.global().async {
let image: CGImage? = resize(url: NSURL.init(string: "https://i.stack.imgur.com/rPcHQ.jpg"), maxPixelSize: 600)
DispatchQueue.main.async {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0 ,width: 30, height: 30))
if let cgimage = image {
imageView.image = UIImage(cgImage: cgimage);
}
}
}
```
or
```swift
// 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)
}
```
[1]:
[To see links please register here]
[2]: