Summary
Disabling HDR decoding reduces choppiness in NSImage drawing during fast resizes, especially in small windows.
The issue originates from HDR image data being decoded to SDR on the fly, which is expensive and leads to frame‑rate drops.
Root Cause
- HDR image metadata triggers high‑dynamic‑range decoding in the graphics stack.
NSImage.draw(in:)uses the system’s default decoder, which:- Re‑decodes each frame during resizing.
- Performs expensive color‑space conversions from HDR to SDR.
- Small view bounds force frequent resize callbacks, magnifying the cost.
Why This Happens in Real Systems
- Modern displays and media use HDR; system APIs default to HDR support.
- Resizing actions, drag‑and‑drop, or window resizing generate many
draw(_:)calls. - On macOS, the compositor may not fully optimize for small-draw regions, leading to visible stutter.
Real-World Impact
- High CPU usage during resize events, especially on older GPUs.
- User experience degradation: janky window borders, laggy image scaling.
- Battery drain on portable devices due to increased decoding loads.
Example or Code (if necessary and relevant)
// Disable HDR decoding for a CGImageSource
let nonHDROptions: CFDictionary = [
kCGImageSourceDecodeRequest: kCGImageSourceDecodeToSDR,
kCGImageSourceDecodeRequestOptions: [
kCGComputeHDRStats: false
]
] as CFDictionary
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nonHDROptions) else { return }
self.imageView.image = NSImage(cgImage: cgImage, size: NSSize(width: cgImage.width, height: cgImage.height))
How Senior Engineers Fix It
- Force SDR decoding immediately after loading the image (as shown above).
- Cache the decoded
NSImageand reuse it during resize to avoid repeated decoding. - Use
AVMakeRectfor aspect‑fit calculations, but limit redraws to the minimal area. - Profile continuously with Instruments/Time Profiler to confirm reduced CPU usage.
- Leverage
CALayerbacking for smoother scaling when possible.
Why Juniors Miss It
- They assume
NSImage.draw(in:)will handle HDR transparently. - Lack of awareness of CGImageSource decoding flags.
- Overlook the cost of repetitive decoding in
draw(_:). - Prefer quick “hard‑coded” solutions (e.g., resizing in advance) without profiling.
By understanding the role of HDR decoding and applying explicit SDR conversion, senior engineers can deliver smooth, responsive image rendering even under rapid window resizing.