[Android] Fix excessive memory usage for stream and resource-based image loading#33590
Conversation
|
Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
This PR fixes excessive memory usage when loading images from streams or resources on Android by preventing Glide from upscaling images to display dimensions. The fix adds override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to stream-based image loading paths in PlatformInterop.java, ensuring images maintain their original dimensions rather than being scaled to match the display size.
Changes:
- Added size override to
loadImageFromStreammethods to prevent Glide upscaling - Created UI test to verify image byte count remains reasonable for stream-based loading
- Created test page demonstrating the issue with embedded resource image loading
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java | Added .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to both loadImageFromStream methods to prevent image upscaling |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33239.cs | Added Android-specific UI test verifying image byte count after loading from resource |
| src/Controls/tests/TestCases.HostApp/Issues/Issue33239.cs | Added test page with embedded resource image and button to measure bitmap memory usage |
| App.WaitForElement("MeasureButton"); | ||
| App.Tap("MeasureButton"); | ||
| var resultText = App.FindElement("ResultLabel").GetText(); | ||
| Assert.That(resultText, Is.EqualTo("Image ByteCount: 786432")); |
There was a problem hiding this comment.
The hard-coded byte count value (786432) in this assertion is brittle and may cause test failures across different devices or Android versions. The actual byte count can vary based on bitmap configuration, pixel density, or image decoding behavior. Consider using a range check or verifying that the byte count is within a reasonable threshold of the expected original image dimensions instead of an exact match.
| Assert.That(resultText, Is.EqualTo("Image ByteCount: 786432")); | |
| var prefix = "Image ByteCount: "; | |
| Assert.That(resultText, Does.StartWith(prefix), "Result text did not start with the expected prefix."); | |
| var byteCountText = resultText.Substring(prefix.Length).Trim(); | |
| if (!int.TryParse(byteCountText, out var byteCount)) | |
| { | |
| Assert.Fail($"Unable to parse byte count from result text: '{resultText}'"); | |
| } | |
| const int expectedByteCount = 786432; | |
| var tolerance = (int)(expectedByteCount * 0.2); // allow 20% variance | |
| Assert.That( | |
| byteCount, | |
| Is.InRange(expectedByteCount - tolerance, expectedByteCount + tolerance), | |
| $"Expected image byte count to be within ±{tolerance} of {expectedByteCount}, but was {byteCount}."); |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
1394f31 to
097697d
Compare
097697d to
4a23114
Compare
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — Modified the test cases ·
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #33590 | Add .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to both loadImageFromStream methods in PlatformInterop.java |
⏳ PENDING (Gate) | PlatformInterop.java (+4/-2) |
Original PR |
🚦 Gate — Test Verification
📝 Review Session — Modified the test cases · eb7bec7
Result: ✅ PASSED
Platform: android
Mode: Full Verification (RequireFullVerification)
TestFilter: Issue33239
- Tests FAIL without fix ✅ (bug detected correctly)
- Tests PASS with fix ✅ (fix works correctly)
Fix Files Detected:
src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java
🔧 Fix — Analysis & Comparison
📝 Review Session — Modified the test cases · eb7bec7
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-sonnet-4.5) | .centerInside() transformation on both loadImageFromStream methods |
✅ PASS | PlatformInterop.java (+2/-2) |
Prevents upscaling via transformation layer |
| 2 | try-fix (claude-opus-4.6) | .downsample(DownsampleStrategy.NONE) on both loadImageFromStream methods |
✅ PASS | PlatformInterop.java (+3/-2) |
Disables decode-level upsampling entirely |
| 3 | try-fix (gpt-5.2) | .downsample(DownsampleStrategy.AT_MOST) on both loadImageFromStream methods |
✅ PASS | PlatformInterop.java (+3/-2) |
Prevents upscaling; allows downscaling |
| 4 | try-fix (gpt-5.2-codex) | Read stream to byte[], decode bounds, override with explicit width/height | ✅ PASS | PlatformInterop.java (~60 lines) |
Bypasses view size measurement; very invasive |
| 5 | try-fix (gemini-3-pro-preview) | .downsample(DownsampleStrategy.CENTER_INSIDE) on both loadImageFromStream methods |
✅ PASS | PlatformInterop.java (+3/-2) |
Prevents upscaling; allows downscaling; semantically clear |
| 6 | try-fix (gpt-5.2) | Downsampler.FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS=false |
❌ FAIL | PlatformInterop.java (+4/-2) |
Deep Glide internal; doesn't affect this decode path |
| PR | PR #33590 | .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) on both loadImageFromStream methods |
✅ PASS (Gate) | PlatformInterop.java (+4/-2) |
Original PR fix; consistent with loadImageFromFont pattern in same file |
Cross-Pollination Summary (Round 2)
| Model | Response |
|---|---|
| claude-sonnet-4.5 | Suggested thumbnail/format/cache ideas but concluded NO NEW IDEAS worth pursuing |
| claude-opus-4.6 | NO NEW IDEAS — confirmed the Glide API surface is exhausted |
| gpt-5.2 | NEW IDEA: DISABLE_BITMAP_POOL — tangential (controls memory reuse, not decode size) |
| gpt-5.2-codex | NEW IDEA: .disallowHardwareConfig() — unrelated to decode-phase upscaling |
| gemini-3-pro-preview | NO NEW IDEAS |
Exhausted: Yes — remaining suggestions are tangential to decode-phase upscaling and won't yield better results.
Selected Fix: PR's fix — .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
Reason: The PR's fix uses the same pattern as loadImageFromFont already uses in PlatformInterop.java, maintaining internal consistency. It is semantically explicit ("load at original dimensions") and directly addresses the root cause. While DownsampleStrategy.CENTER_INSIDE or AT_MOST (Attempts 3 and 5) could be argued as more memory-efficient for large images (they allow beneficial downscaling), the PR's approach is the correct semantic for a stream/resource load where the developer controls display size via the Image control's Aspect/HeightRequest/WidthRequest properties. The agent could NOT beat the PR's fix.
📋 Report — Final Recommendation
📝 Review Session — Modified the test cases · eb7bec7
✅ Final Recommendation: APPROVE
Summary
PR #33590 fixes a genuine Android memory bug where ImageSource.FromResource() and ImageSource.FromStream() caused ~25MB Bitmap.ByteCount vs ~1MB for XAML images. The root cause (Glide upscaling stream-based images to display dimensions) is correct, the fix (.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)) is verified to work by Gate, and the test was updated to use a robust comparison approach (comparing resource vs. file image byte counts directly, rather than a hardcoded value).
The prior review (at commit 4a23114) requested changes due to a hardcoded byte count in the test. The author has addressed this — the current test uses Assert.That(resource, Is.EqualTo(file)), which is device-independent. Gate passed with this updated test.
The agent explored 5 alternative fix approaches and could not find a better solution than the PR's fix.
Root Cause
Glide's default behavior when loading from InputStream is to resize the decoded bitmap to match the ImageView's (or display) dimensions. loadImageFromFont in the same file already had .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to prevent this. The two loadImageFromStream overloads were missing this override, causing stream-based images (used by ImageSource.FromResource() and ImageSource.FromStream()) to be upscaled to display resolution (~25MB) rather than preserved at original dimensions (~786KB).
Fix Quality
Approach: Add .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to both loadImageFromStream overloads in PlatformInterop.java.
Assessment: ✅ Correct, minimal (4 lines), and consistent with the existing loadImageFromFont pattern in the same file. The agent tried 5 alternative approaches (all passed tests) but none were simpler or more semantically clear than the PR's approach.
Alternative approaches explored (all passed tests):
.centerInside()transformation — prevents upscaling via transformation layer.downsample(DownsampleStrategy.NONE)— disables decode-level upsampling.downsample(DownsampleStrategy.AT_MOST)— prevents upscaling, allows downscaling- Read stream to byte[], decode bounds, override explicitly — works but invasive (~60 lines)
.downsample(DownsampleStrategy.CENTER_INSIDE)— semantically clear, allows downscalingDownsampler.FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS=false— ❌ FAILED
PR Finalize Review
Title: ✅ Accurate — [Android] Fix excessive memory usage for stream and resource-based image loading
Description: ✅ Good — contains NOTE block, issue details, root cause, description of change, platforms checkbox. Only minor enhancement: add "What NOT to Do" section.
Suggested description addition:
### What NOT to Do (for future agents)
- ❌ **Don't use `.dontTransform()`** — Only stops post-decode transformations; the upscaling happens during the decode phase and is not affected
- ❌ **Don't use `Downsampler.FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS=false`** — Deep Glide internal; doesn't affect stream-based image decode upscaling pathCode Review Findings
🟡 Medium Issues
1. Test can pass silently if both images fail to load
The test assertion Assert.That(resource, Is.EqualTo(file)) would pass if both labels contain "ByteCount:0" (e.g., if the images fail to load before the button is tapped). The GetBitmapByteCount fallback is also concerning — if the ImageView hasn't rendered yet when the button is tapped, it returns 0 for both, causing a false positive.
Recommendation: Add a guard that the byte count is non-zero:
Assert.That(resource, Is.Not.EqualTo("ByteCount:0"), "Resource image byte count should be non-zero");
Assert.That(resource, Is.EqualTo(file));2. DownSizeImageAppearProperly.png snapshot changed (unexplained)
The DownSizeImageAppearProperly snapshot was modified by this PR, but the description doesn't explain why. Loading images at SIZE_ORIGINAL instead of display dimensions may change visual appearance if Glide was previously doing beneficial downscaling for this test. The snapshot change should be reviewed to confirm the new appearance is correct.
🟢 Minor Issues
3. Test only covers FromResource path, not FromStream
The test uses ImageSource.FromResource(). Both code paths converge on loadImageFromStream, so one test is sufficient, but a comment would help future contributors understand this:
// ImageSource.FromResource routes through loadImageFromStream in PlatformInterop.java,
// so this test covers both FromResource and FromStream scenarios.✅ Looks Good
- Core fix is correct and minimal: 2×2-line change in
PlatformInterop.java, consistent withloadImageFromFontpattern - Test approach is robust: Comparing resource vs. file byte counts is device-independent
- AutomationIds are present and matched: HostApp and test correctly reference same IDs
- NOTE block present in PR description
- Platform labels accurate (Android only)
Platforms
- Android (tested by Gate + try-fix)
- iOS — not affected (fix is Android-only Java code)
- Windows — not affected
- macOS — not affected
📋 Expand PR Finalization Review
Title: ✅ Good
Current: [Android] Fix excessive memory usage for stream and resource-based image loading
Description: ✅ Good
Description needs updates. See details below.
✨ Suggested PR Description
[!NOTE]
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Root Cause
Glide's default behavior for stream-based image loading is to upscale the decoded bitmap to the display dimensions of the target ImageView. This caused ImageSource.FromResource() and ImageSource.FromStream() to produce bitmaps with byte counts proportional to the screen resolution rather than the original image dimensions. File-based loading (loadImageFromFile) and font-based loading (loadImageFromFont) were not affected — loadImageFromFont already used Target.SIZE_ORIGINAL to preserve original dimensions.
Description of Change
Added .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to both loadImageFromStream overloads in PlatformInterop.java:
loadImageFromStream(ImageView imageView, InputStream inputStream, ImageLoaderCallback callback)loadImageFromStream(Context context, InputStream inputStream, ImageLoaderCallback callback)
This prevents Glide from upscaling the bitmap to the display size, ensuring stream/resource-loaded images consume memory proportional to their actual dimensions — consistent with the existing behavior for file-based image loading.
Note: Target.SIZE_ORIGINAL also prevents Glide from downsampling very large images. This is the correct behavior for MAUI (matching how file images are loaded), but very large embedded resources will use proportionally more memory.
Key Technical Details
Methods changed (PlatformInterop.java):
loadImageFromStream(ImageView, InputStream, ImageLoaderCallback)— previously lacked size override, now usesTarget.SIZE_ORIGINALloadImageFromStream(Context, InputStream, ImageLoaderCallback)— previously lacked size override, now usesTarget.SIZE_ORIGINAL
Unchanged (already correct):
loadImageFromFont— already usedTarget.SIZE_ORIGINALfor both ImageView and Context variantsloadImageFromFile— file loading was not affected by the upscaling issue
Issues Fixed
Fixes #33239
Platforms Tested
- Android
- Windows
- iOS
- Mac
Output Screenshot
| Before | After |
|---|---|
![]() |
![]() |
Code Review: ⚠️ Issues Found
Code Review — PR #33590
PR: [Android] Fix excessive memory usage for stream and resource-based image loading
Files reviewed: 4
🔴 Critical Issues
None.
🟡 Moderate Concerns
1. #if ANDROID Inside HostApp Method Bodies
File: src/Controls/tests/TestCases.HostApp/Issues/Issue33239.cs
Problem: The UI test guidelines say platform-specific logic should be moved to extension methods rather than using inline #if directives inside method bodies. The HostApp file uses #if ANDROID both inside OnMeasureClicked and to guard the GetBitmapByteCount helper method.
// Current — discouraged pattern
private void OnMeasureClicked(object sender, EventArgs e)
{
#if ANDROID
int resourceByteCount = GetBitmapByteCount(_resourceImage);
// ...
#endif
}
#if ANDROID
static int GetBitmapByteCount(Image image) { ... }
#endifRecommendation: Move the Android-specific logic to a platform extension method (e.g., in a Issue33239.android.cs partial file), or at minimum consolidate the #if ANDROID guard to the class/file level rather than inside method bodies.
Severity: Moderate (guideline violation, doesn't affect functionality)
2. Target.SIZE_ORIGINAL Disables All Size Optimization
File: src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java
Problem: Using Target.SIZE_ORIGINAL with Glide prevents both upscaling AND downscaling. This is correct for normal image sizes and matches the pre-existing behavior for loadImageFromFont. However, for very large images loaded via stream/resource (e.g., a multi-megapixel embedded resource), the full-resolution bitmap will be decoded into memory without any size-based downsampling.
// New behavior — loads at original dimensions always (no size cap)
RequestBuilder<Drawable> builder = Glide
.with(imageView)
.load(inputStream)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);Context: The old behavior (upscaling to display dimensions) was arguably worse — a small image was wastefully upscaled. The new behavior is correct for the common case. This concern is primarily about documenting the edge case.
Recommendation: This is acceptable as-is and matches the existing loadImageFromFont pattern. No code change needed, but consider adding a comment noting that SIZE_ORIGINAL intentionally preserves original dimensions for both small and large images.
Severity: Moderate (potential OOM for very large embedded images, but this matches existing loadImageFromFont behavior and is better than the previous upscaling)
🟢 Looks Good
Fix is Correct and Minimal
The core fix — adding .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) to both loadImageFromStream overloads — is exactly the right approach. This matches how loadImageFromFont was already handled and directly addresses the root cause (Glide upscaling stream inputs to display dimensions).
Both Overloads Fixed
Both the ImageView-based and Context-based variants of loadImageFromStream are updated, ensuring consistent behavior regardless of which loading path is used.
Test Approach Is Sound
The Issue33239.cs test compares byte count of a resource-loaded image vs. a file-loaded image using Assert.That(resource, Is.EqualTo(file)). This is a meaningful test since both images are loaded from the same royals.png source — after the fix, both paths should produce the same byte count. This avoids the fragility of asserting an absolute byte count value.
Note on Outdated Review Comment: There is an existing review comment from
copilot-pull-request-reviewersuggesting a range-based assertion around a hard-coded value of786432. This comment is marked as outdated and refers to an earlier version of the test. The current test implementation does not use a hard-coded byte count and does not need this suggestion applied.
Test Class-Level #if ANDROID Guard Is Acceptable
The NUnit test file wraps the entire class in #if ANDROID at the class level (not inside a test method), which is an acceptable pattern for platform-specific tests where the test simply cannot run on other platforms.
|
The AI summary suggested test did not work. so I updated the test case and verified that it now works as expected. |
…age loading (#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes #33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
…age loading (#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes #33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
…age loading (#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes #33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
…age loading (#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes #33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
…age loading (dotnet#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes dotnet#33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
… - 1 (#34334) This PR addresses the UI test image failures that occurred in the inflight/candidate branch #34294 and includes updates to improve rendering and test stability across platforms. ### Controls Handler Registration * Simplified the logic for registering handlers for controls like `Label`, `Editor`, `Picker`, `RadioButton`, and `TimePicker` in `AppHostBuilderExtensions.cs`. The new approach registers all fallback handlers together, reducing duplicated code and improving maintainability. ### * In the NavigationRootManager class, the line _rootView.SetTitleBar(null, null); was added in this PR #34032 by a contributor due to an AI minor suggestion, but this line causes an issue when swapping pages, so the TitlebarWorksWhenSwitchingPage test fails. Setting SetTitleBar to null is already implemented in the WindowHandler class in the [DisconnectHandler](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/Window/WindowHandler.Windows.cs#L55) method, so I have removed this line _rootView.SetTitleBar(null, null); from the PR [34032](#34032). ### Image Resave: * Resaved images: DownSizeImageAppearProperly, Material3CheckBoxFeatureTests, Material3CheckBox_DefaultAppearance, DownSizeImageAppearProperly, VerifyLinearGradientBrushWithStrokeAndOpacity, VerifyRadialGradientBrushWithOpacity, VerifyRadialGradientBrushWithShadowAndOpacity, VerifyLinearGradientBrushWithOpacity, VerifyLinearGradientBrushWithShadowAndOpacity, DarkTheme_VerifyVisualState. These PR fixes address the issues: #33173, #31567, #33590, #34036 * Added the base images for iOS 26, Mac, and Windows. ### Test Stability and Platform-Specific Handling * Added a platform-specific ignore for a Shell flyout test on iOS 26 due to a known bug, improving test reliability and clarity about platform limitations. * Updated a CollectionView scroll test to wait for specific elements on Windows, ensuring the test works correctly across platforms. ### DatePicker Handler Tests * Introduced a helper method `EnsureDialogCreated` in `DatePickerHandlerTests.Android.cs` to reliably create the native dialog before reading min/max values, addressing issues caused by lazy dialog creation after a recent PR. This helper is now used in relevant tests to improve robustness. [[1]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R26) [[2]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R54) [[3]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R131-R146) * Clarified the DatePicker test logic in `DatePickerTests.cs` to ensure the `DateSelected` event fires correctly regardless of dialog state, improving test reliability on Android. ### Test Case Organization * Removed the obsolete `VerifyFlyoutPage_IsEnabled` test and renumbered the remaining FlyoutPage tests in `FlyoutPageFeatureTests.cs` to maintain sequential order and consistency. [[1]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L176-R177) [[2]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L204-R191) [[3]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L222-R209) [[4]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L240-R227) [[5]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L254-R241) [[6]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L268-R255) [[7]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L284-R271) [[8]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L299-R286) [[9]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L310-R297) [[10]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L327-R314) [[11]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L340-R327) [[12]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L357-R344) [[13]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L376-R363) [[14]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L387-R374) [[15]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L400-R387)
…age loading (#33590) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams. ### Root Cause Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size. ### Description of Change Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage. Validated the behavior in the following platforms - [x] Android - [ ] Windows - [ ] iOS - [ ] Mac ### Issues Fixed Fixes #33239 ### Output ScreenShot | Before | After | |---------|--------| | <img width="352" height="759" alt="33239-BeforeFix" src="https://github.com/user-attachments/assets/a1ed4f05-e39a-4d1f-a974-2dc589bf7d78" /> | <img width="352" height="759" alt="33239-AfterFix" src="https://github.com/user-attachments/assets/64b067bc-da36-4690-a077-8022ac621223" /> |
… - 1 (#34334) This PR addresses the UI test image failures that occurred in the inflight/candidate branch #34294 and includes updates to improve rendering and test stability across platforms. ### Controls Handler Registration * Simplified the logic for registering handlers for controls like `Label`, `Editor`, `Picker`, `RadioButton`, and `TimePicker` in `AppHostBuilderExtensions.cs`. The new approach registers all fallback handlers together, reducing duplicated code and improving maintainability. ### * In the NavigationRootManager class, the line _rootView.SetTitleBar(null, null); was added in this PR #34032 by a contributor due to an AI minor suggestion, but this line causes an issue when swapping pages, so the TitlebarWorksWhenSwitchingPage test fails. Setting SetTitleBar to null is already implemented in the WindowHandler class in the [DisconnectHandler](https://github.com/dotnet/maui/blob/main/src/Core/src/Handlers/Window/WindowHandler.Windows.cs#L55) method, so I have removed this line _rootView.SetTitleBar(null, null); from the PR [34032](#34032). ### Image Resave: * Resaved images: DownSizeImageAppearProperly, Material3CheckBoxFeatureTests, Material3CheckBox_DefaultAppearance, DownSizeImageAppearProperly, VerifyLinearGradientBrushWithStrokeAndOpacity, VerifyRadialGradientBrushWithOpacity, VerifyRadialGradientBrushWithShadowAndOpacity, VerifyLinearGradientBrushWithOpacity, VerifyLinearGradientBrushWithShadowAndOpacity, DarkTheme_VerifyVisualState. These PR fixes address the issues: #33173, #31567, #33590, #34036 * Added the base images for iOS 26, Mac, and Windows. ### Test Stability and Platform-Specific Handling * Added a platform-specific ignore for a Shell flyout test on iOS 26 due to a known bug, improving test reliability and clarity about platform limitations. * Updated a CollectionView scroll test to wait for specific elements on Windows, ensuring the test works correctly across platforms. ### DatePicker Handler Tests * Introduced a helper method `EnsureDialogCreated` in `DatePickerHandlerTests.Android.cs` to reliably create the native dialog before reading min/max values, addressing issues caused by lazy dialog creation after a recent PR. This helper is now used in relevant tests to improve robustness. [[1]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R26) [[2]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R54) [[3]](diffhunk://#diff-de28fdea458f311cfcc7e767c7e9e2a4c7c36e4d065ae2ebf2a25b420f183c29R131-R146) * Clarified the DatePicker test logic in `DatePickerTests.cs` to ensure the `DateSelected` event fires correctly regardless of dialog state, improving test reliability on Android. ### Test Case Organization * Removed the obsolete `VerifyFlyoutPage_IsEnabled` test and renumbered the remaining FlyoutPage tests in `FlyoutPageFeatureTests.cs` to maintain sequential order and consistency. [[1]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L176-R177) [[2]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L204-R191) [[3]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L222-R209) [[4]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L240-R227) [[5]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L254-R241) [[6]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L268-R255) [[7]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L284-R271) [[8]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L299-R286) [[9]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L310-R297) [[10]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L327-R314) [[11]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L340-R327) [[12]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L357-R344) [[13]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L376-R363) [[14]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L387-R374) [[15]](diffhunk://#diff-a20c8165e92130c8ebbda3af607c3dd309cf1c1b6c85942abd6ed81132510fb3L400-R387)
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 46 commits with various improvements, bug fixes, and enhancements. ## Button - [Android] Implemented material3 support for Button by @Dhivya-SF4094 in #33173 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Button](#33172) </details> ## CollectionView - [Android] Fix RemainingItemsThresholdReachedCommand not firing when CollectionView has Header and Footer both defined by @SuthiYuvaraj in #29618 <details> <summary>🔧 Fixes</summary> - [Android : RemainingItemsThresholdReachedCommand not firing when CollectionVew has Header and Footer both defined](#29588) </details> - [iOS/MacCatalyst] Fix CollectionView ScrollTo for horizontal layouts by @Shalini-Ashokan in #33853 <details> <summary>🔧 Fixes</summary> - [[iOS/MacCatalyst] CollectionView ScrollTo does not work with horizontal Layout](#33852) </details> - [iOS & Mac] Fixed IndicatorView Size doesnt update dynamically by @SubhikshaSf4851 in #31129 <details> <summary>🔧 Fixes</summary> - [[iOS, Catalyst] IndicatorView.IndicatorSize does not update dynamically at runtime](#31064) </details> - [Android] Fix for CollectionView Scrolled event is triggered on the initial app load. by @BagavathiPerumal in #33558 <details> <summary>🔧 Fixes</summary> - [[Android] CollectionView Scrolled event is triggered on the initial app load.](#33333) </details> - [iOS, Android] Fix for CollectionView IsEnabled=false allows touch interactions by @praveenkumarkarunanithi in #31403 <details> <summary>🔧 Fixes</summary> - [More issues with CollectionView IsEnabled, InputTransparent, Opacity via Styles and code behind](#19771) </details> - [iOS] Fix VerticalOffset Update When Modifying CollectionView.ItemsSource While Scrolled by @devanathan-vaithiyanathan in #34153 <details> <summary>🔧 Fixes</summary> - [[iOS]VerticalOffset Not Reset to Zero After Clearing ItemSource in CollectionView](#26798) </details> ## DateTimePicker - [Android] Fix DatePicker MinimumDate/MaximumDate not updating dynamically by @HarishwaranVijayakumar in #33687 <details> <summary>🔧 Fixes</summary> - [[regression/8.0.3] [Android] DatePicker control minimum date issue](#19256) - [[Android] DatePicker does not update MinimumDate / MaximumDate in the Popup when set in the viewmodel after first opening](#33583) </details> ## Drawing - Android drawable perf by @albyrock87 in #31567 ## Editor - [Android] Implemented material3 support for Editor by @SyedAbdulAzeemSF4852 in #33478 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Editor](#33476) </details> ## Entry - [iOS, Mac] Fix for CursorPosition not updating when typing into Entry control by @SyedAbdulAzeemSF4852 in #30505 <details> <summary>🔧 Fixes</summary> - [Entry control CursorPosition does not update on TextChanged event [iOS Maui 8.0.7] ](#20911) - [CursorPosition not calculated correctly on behaviors events for iOS devices](#32483) </details> ## Flyoutpage - [Android, Windows] Fix for FlyoutPage toolbar button not updating on orientation change by @praveenkumarkarunanithi in #31962 <details> <summary>🔧 Fixes</summary> - [Flyout page in Android does not show flyout button (burger) consistently](#24468) </details> - Fix for First Item in CollectionView Overlaps in FlyoutPage.Flyout on iOS by @praveenkumarkarunanithi in #29265 <details> <summary>🔧 Fixes</summary> - [[iOS] CollectionView not rendering first item correctly in FlyoutPage.Flyout](#29170) </details> ## Image - [Android] Fix excessive memory usage for stream and resource-based image loading by @Shalini-Ashokan in #33590 <details> <summary>🔧 Fixes</summary> - [[Android] Unexpected high Bitmap.ByteCount when loading image via ImageSource.FromResource() or ImageSource.FromStream() in .NET MAUI](#33239) </details> - [Android] Fix for Resize method returns an image that has already been disposed by @SyedAbdulAzeemSF4852 in #29964 <details> <summary>🔧 Fixes</summary> - [In GraphicsView, the Resize method returns an image that has already been disposed](#29961) - [IIMage.Resize bugged behaviour](#31103) </details> ## Label - Fixed Label Span font property inheritance when applied via Style by @SubhikshaSf4851 in #34110 <details> <summary>🔧 Fixes</summary> - [`Span` does not inherit text styling from `Label` if that styling is applied using `Style` ](#21326) </details> - [Android] Implemented material3 support for Label by @SyedAbdulAzeemSF4852 in #33599 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Label](#33598) </details> ## Map - [Android] Fix Circle Stroke color is incorrectly updated as Fill color. by @NirmalKumarYuvaraj in #33643 <details> <summary>🔧 Fixes</summary> - [[Android] Circle Stroke color is incorrectly updated as Fill color.](#33642) </details> ## Mediapicker - [iOS] Fix: invoke MediaPicker completion handler after DismissViewController by @yuriikyry4enko in #34250 <details> <summary>🔧 Fixes</summary> - [[iOS] Media Picker UIImagePickerController closing issue](#21996) </details> ## Navigation - Fix ContentPage memory leak on Android when using NavigationPage modally (fixes #33918) by @brunck in #34117 <details> <summary>🔧 Fixes</summary> - [[Android] Modal TabbedPage whose tabs are NavigationPage(ContentPage) is retained after PopModalAsync()](#33918) </details> ## Picker - [Android] Implement material3 support for TimePicker by @HarishwaranVijayakumar in #33646 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for TimePicker](#33645) </details> - [Android] Implemented Material3 support for Picker by @SyedAbdulAzeemSF4852 in #33668 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Picker](#33665) </details> ## RadioButton - [Android] Implemented material3 support for RadioButton by @SyedAbdulAzeemSF4852 in #33468 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for RadioButton](#33467) </details> ## Setup - Clarify MA003 error message by @jeremy-visionaid in #34067 <details> <summary>🔧 Fixes</summary> - [MA003 false positive with 9.0.21](#26599) </details> ## Shell - [Android] Fix TabBar FlowDirection not updating dynamically by @SubhikshaSf4851 in #33091 <details> <summary>🔧 Fixes</summary> - [[Android, iOS] FlowDirection RTL is not updated dynamically on Shell TabBar](#32993) </details> - [Android] Fix page not disposed on Shell replace navigation by @Vignesh-SF3580 in #33426 <details> <summary>🔧 Fixes</summary> - [[Android] [Shell] replace navigation leaks current page](#25134) </details> - [Android] Fixed Shell flyout does not disable scrolling when FlyoutVerticalScrollMode is set to Disabled by @NanthiniMahalingam in #32734 <details> <summary>🔧 Fixes</summary> - [[Android] Shell.FlyoutVerticalScrollMode="Disabled" does not disable scrolling](#32477) </details> ## Single Project - Fix: Throw a clear error when an SVG lacks dimensions instead of a NullReferenceException by @Shalini-Ashokan in #33194 <details> <summary>🔧 Fixes</summary> - [MAUI Fails To Convert Valid SVG Files Into PNG Files (Object reference not set to an instance of an object)](#32460) </details> ## SwipeView - [iOS] Fix SwipeView stays open on iOS after updating content by @devanathan-vaithiyanathan in #31248 <details> <summary>🔧 Fixes</summary> - [[iOS] - Swipeview with collectionview issue](#19541) </details> ## TabbedPage - [Windows] Fixed IsEnabled Property not works on Tabs by @NirmalKumarYuvaraj in #26728 <details> <summary>🔧 Fixes</summary> - [ShellContent IsEnabledProperty does not work](#5161) - [[Windows] Shell Tab IsEnabled Not Working](#32996) </details> - [Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes by @Vignesh-SF3580 in #33359 <details> <summary>🔧 Fixes</summary> - [[Android] NavigationBar overlaps with StatusBar when mixing HasNavigationBar=true/false in TabbedPage on Android 15 (API 35)](#33340) </details> ## Templates - Fix for unable to open task using keyboard navigation on windows platform by @SuthiYuvaraj in #33647 <details> <summary>🔧 Fixes</summary> - [Unable to open task using keyboard: A11y_.NET maui_User can get all the insights of Dashboard_Keyboard](#30787) </details> ## TitleView - Fix for NavigationPage.TitleView does not expand with host window in iPadOS 26+ by @SuthiYuvaraj in #33088 ## Toolbar - [iOS] Fix toolbar items ignoring BarTextColor on iOS/MacCatalyst 26+ by @Shalini-Ashokan in #34036 <details> <summary>🔧 Fixes</summary> - [[iOS 26] ToolbarItem color with custom BarTextColor not working](#33970) </details> - [Android] Fix for ToolbarItem retaining the icon from the previous page on Android when using NavigationPage. by @BagavathiPerumal in #32311 <details> <summary>🔧 Fixes</summary> - [Toolbaritem keeps the icon of the previous page on Android, using NavigationPage (not shell)](#31727) </details> ## WebView - [Android] Fix WebView in a grid expands beyond it's cell by @devanathan-vaithiyanathan in #32145 <details> <summary>🔧 Fixes</summary> - [Android - WebView in a grid expands beyond it's cell](#32030) </details> ## Xaml - ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @HarishwaranVijayakumar in #30880 <details> <summary>🔧 Fixes</summary> - [Binding context in ContentPresenter](#23797) </details> <details> <summary>🔧 Infrastructure (1)</summary> - [Revert] ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @Ahamed-Ali in #34332 </details> <details> <summary>🧪 Testing (6)</summary> - [Testing] Feature Matrix UITest Cases for Shell Flyout Page by @NafeelaNazhir in #32525 - [Testing] Feature Matrix UITest Cases for Brushes by @LogishaSelvarajSF4525 in #31833 - [Testing] Feature Matrix UITest Cases for BindableLayout by @LogishaSelvarajSF4525 in #33108 - [Android] Add UI tests for Material 3 CheckBox by @HarishwaranVijayakumar in #34126 <details> <summary>🔧 Fixes</summary> - [[Android] Add UI tests for Material 3 CheckBox](#34125) </details> - [Testing] Feature Matrix UITest Cases for Shell Tabbed Page by @NafeelaNazhir in #33159 - [Testing] Fixed Test case failure in PR 34294 - [03/2/2026] Candidate - 1 by @TamilarasanSF4853 in #34334 </details> <details> <summary>📦 Other (2)</summary> - Bumps Syncfusion.Maui.Toolkit dependency to version 1.0.9 by @PaulAndersonS in #34178 - Fix crash when closing Windows based app when using TitleBar by @MFinkBK in #34032 <details> <summary>🔧 Fixes</summary> - [Unhandled exception "Value does not fall within the expected range" when closing Windows app](#32194) </details> </details> **Full Changelog**: main...inflight/candidate


Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
Stream-based and resource-based image loading consumed excessive memory on Android versus XAML image loading. Images were loaded at display dimensions instead of original dimensions, affecting all apps using embedded resources or streams.
Root Cause
Glide upscaled stream-based images to display dimensions without size constraints. XAML had proper size handling, but stream loading lacked overrides, causing memory to scale with screen size not image size.
Description of Change
Added size override in PlatformInterop.java to preserve original image dimensions. This prevents upscaling to display dimensions, making all loading methods produce consistent memory usage.
Validated the behavior in the following platforms
Issues Fixed
Fixes #33239
Output ScreenShot