Skip to content

Commit 2a7416f

Browse files
Copilotrolfbjarne
andauthored
[UIKit] Fix crash in UIScreen.Capture() and UIView.Capture() by replacing deprecated UIGraphicsBeginImageContextWithOptions with UIGraphicsImageRenderer. Fixes #24053. (#24054)
## Problem Customers were experiencing crashes when taking screenshots in iOS apps with the following error: ``` Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: UIGraphicsBeginImageContext() failed to allocate CGBitampContext: size={1080, 810}, scale=2.000000, bitmapInfo=0x2006. Use UIGraphicsImageRenderer to avoid this assert. ``` The crash was occurring in both `UIScreen.Capture()` and `UIView.Capture()` methods, which were using the deprecated `UIGraphicsBeginImageContextWithOptions` API. Apple explicitly recommends using `UIGraphicsImageRenderer` instead to avoid these allocation failures. ## Solution Replaced the deprecated `UIGraphicsBeginImageContextWithOptions` API with the modern `UIGraphicsImageRenderer` API in both affected methods: ### UIScreen.Capture() - Removed legacy iOS version checks and fallback code paths - Simplified from ~40 lines to a clean 9-line implementation - Now uses `UIGraphicsImageRenderer` to capture the KeyWindow ### UIView.Capture(bool afterScreenUpdates) - Replaced try-finally block with using statement for `UIGraphicsImageRenderer` - Maintained the `afterScreenUpdates` parameter functionality - Cleaner, more maintainable code ## Benefits - ✅ Eliminates the CGBitmapContext allocation crash reported by users - ✅ Uses Apple's recommended modern API (available on all supported iOS versions) - ✅ Simplifies code by removing legacy version checks - ✅ More robust and efficient image rendering - ✅ Follows Apple's guidelines from the error message itself ## References - Issue: #24053 - Apple Documentation: [UIGraphicsImageRenderer](https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer) - Suggested by @rolfbjarne Fixes #24053. --------- Co-authored-by: rolfbjarne <[email protected]>
1 parent 056502e commit 2a7416f

File tree

2 files changed

+10
-46
lines changed

2 files changed

+10
-46
lines changed

src/UIKit/UIScreen.cs

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,44 +41,13 @@ public CoreAnimation.CADisplayLink CreateDisplayLink (Action action)
4141
/// </remarks>
4242
public UIImage Capture ()
4343
{
44-
if (SystemVersion.CheckiOS (7, 0)) {
45-
// This is from https://developer.apple.com/library/content/qa/qa1817/_index.html
46-
try {
47-
var view = UIApplication.SharedApplication.KeyWindow;
48-
UIGraphics.BeginImageContextWithOptions (view.Bounds.Size, view.Opaque, 0);
49-
view.DrawViewHierarchy (view.Bounds, true);
50-
return UIGraphics.GetImageFromCurrentImageContext ();
51-
} finally {
52-
UIGraphics.EndImageContext ();
53-
}
54-
}
55-
56-
// This is from: https://developer.apple.com/library/ios/#qa/qa2010/qa1703.html
57-
var selScreen = new Selector ("screen");
58-
var size = Bounds.Size;
59-
60-
UIGraphics.BeginImageContextWithOptions (size, false, 0);
61-
62-
try {
63-
var context = UIGraphics.GetCurrentContext ();
64-
65-
foreach (var window in UIApplication.SharedApplication.Windows) {
66-
if (window.RespondsToSelector (selScreen) && window.Screen != this)
67-
continue;
68-
69-
context.SaveState ();
70-
context.TranslateCTM (window.Center.X, window.Center.Y);
71-
context.ConcatCTM (window.Transform);
72-
context.TranslateCTM (-window.Bounds.Size.Width * window.Layer.AnchorPoint.X, -window.Bounds.Size.Height * window.Layer.AnchorPoint.Y);
73-
74-
window.Layer.RenderInContext (context);
75-
context.RestoreState ();
76-
}
77-
78-
return UIGraphics.GetImageFromCurrentImageContext ();
79-
} finally {
80-
UIGraphics.EndImageContext ();
81-
}
44+
// This is from https://developer.apple.com/library/content/qa/qa1817/_index.html
45+
// Updated to use UIGraphicsImageRenderer to avoid deprecated UIGraphicsBeginImageContextWithOptions
46+
var view = UIApplication.SharedApplication.KeyWindow;
47+
using var renderer = new UIGraphicsImageRenderer (view.Bounds.Size);
48+
return renderer.CreateImage ((context) => {
49+
view.DrawViewHierarchy (view.Bounds, true);
50+
});
8251
}
8352
}
8453
}

src/UIKit/UIView.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,11 @@ public static Task<bool> AnimateAsync (double duration, Action animation)
252252
/// </remarks>
253253
public UIImage Capture (bool afterScreenUpdates = true)
254254
{
255-
UIImage snapshot;
256255
var bounds = Bounds; // try to access objc the smalles amount of times.
257-
try {
258-
UIGraphics.BeginImageContextWithOptions (bounds.Size, Opaque, 0.0f);
256+
using var renderer = new UIGraphicsImageRenderer (bounds.Size);
257+
return renderer.CreateImage ((context) => {
259258
DrawViewHierarchy (bounds, afterScreenUpdates);
260-
snapshot = UIGraphics.GetImageFromCurrentImageContext ();
261-
} finally {
262-
UIGraphics.EndImageContext ();
263-
}
264-
return snapshot;
259+
});
265260
}
266261

267262
#region Inlined from the UITraitChangeObservable protocol

0 commit comments

Comments
 (0)