The memory usage of the image depends on its dimension (2034*1600) not its file size (600kb)

Memory usage of an image can be calculated as follows,

Memory = width in pixels height in pixels 4 byte per pixel

So our memory will be,

Memory = 2034 1600 4 = 13.02 MB

Why do images occupy such memory space?

In iOS, 3 phases are involved to render an image in app. The phases are Load, Decode & Render

Load:

Loads the compressed .jpg, .png file into the memory

Decode:

Decodes/uncompress the image into GPU readable format, which in turn occupies more memory than its files size

Render:

Renders the image into the app

Image Formats:

The following are the image formats,

  • SRGB Format (4 byte/pixel)
  • Wide Format (8 byte/pixel)
  • Luminance & alpha 8 format (2 byte/pixel)
  • Alpha 8 format (1 byte/pixel)

To choose the right format for the app,

  • Don’t use UIGraphicsBeginImageContextWithOptions, it occupies 4 bytes per pixel by default
  • Use UIGraphicsImageRenderer, automatically picks best graphics format in iOS 12

Eg: To Draw circle using UIGraphicsImageRenderer – allocates only 1 byte per pixel

let bounds = CGRect(x: 0, y: 0, width:300, height: 100)
let renderer = UIGraphicsImageRenderer(size: bounds.size) 

let image = renderer.image { context in 
// Drawing Code 
UIColor.black.setFill() 

let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: UIRectCorner.allCorners, cornerRadii: CGSize(width: 20, height: 20)) 

path.addClip() 
UIRectFill(bounds) 
} 

// Make circle render blue, but stay at 1 byte-per-pixel image 
let imageView = UIImageView(image: image) 
imageView.tintColor = .blue 

Image Resizing:

UIImage is non-efficient in resizing images. It will compress original image to memory and its internal coordinate space transforms are expensive

ImageIO is efficient in resizing images. It can read image size & metadata information without dirtying the memory.

//Resizing image using ImageIO - Efficient
       
let file = "path/image.jpg"

let url = NSURL(fileURLWithPath: file)
        
let imageSource = CGImageSourceCreateWithURL(url, nil)

let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)

let options :[NSString:Any] = [
            kCGImageSourceThumbnailMaxPixelSize:100,
kCGImageSourceCreateThumbnailFromImageAlways:true ]
        
let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options)

Images should be loaded only if the app presents the image. Unload the images when the app is off-screen using App lifecycle such as UIApplicationWillEnterForeground and UIApplicationDidEnterBackground notifications.

Also unload images using UIViewController lifecycle methods such as viewWillAppear and viewDidDisappear.

blog

copyright©2021Saravana all rights reserved