diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/DownSizeImageAppearProperly.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/DownSizeImageAppearProperly.png index 2337f890992f..1ec973730743 100644 Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/DownSizeImageAppearProperly.png and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/DownSizeImageAppearProperly.png differ diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33239.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue33239.cs new file mode 100644 index 000000000000..4cf8da5d113f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue33239.cs @@ -0,0 +1,106 @@ +#if ANDROID +using Android.Graphics; +using Android.Graphics.Drawables; +using Android.Widget; +#endif + +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 33239, "Unexpected high Image ByteCount when loading an image from resources using ImageSource", PlatformAffected.Android)] +public class Issue33239 : ContentPage +{ + Label _fileImageLabel; + Label _resourceImageLabel; + Image _resourceImage; + Image _fileImage; + + public Issue33239() + { + var instructionLabel = new Label + { + Text = "Tap 'Measure ByteCount' to compare memory usage between stream-loaded (FromResource) and file-loaded (Source=\"royals.png\") images. Both should have similar byte counts after the fix.", + Margin = new Thickness(10) + }; + + // Image loaded via stream/resource path (the broken path before fix) + _resourceImage = new Image + { + Source = ImageSource.FromResource("Controls.TestCases.HostApp.Resources.Images.royals.png", typeof(Issue33239).Assembly), + HeightRequest = 200, + Margin = new Thickness(10), + AutomationId = "ResourceImage" + }; + + // Image loaded via file path (always works correctly) + _fileImage = new Image + { + Source = "royals.png", + HeightRequest = 200, + Margin = new Thickness(10), + AutomationId = "FileImage" + }; + + var measureButton = new Microsoft.Maui.Controls.Button + { + Text = "Measure ByteCount", + AutomationId = "MeasureButton", + Margin = new Thickness(10) + }; + measureButton.Clicked += OnMeasureClicked; + + _fileImageLabel = new Label + { + AutomationId = "FileImageLabel", + Margin = new Thickness(10), + LineBreakMode = LineBreakMode.WordWrap + }; + + _resourceImageLabel = new Label + { + AutomationId = "ResourceImageLabel", + Margin = new Thickness(10), + LineBreakMode = LineBreakMode.WordWrap + }; + + Content = new StackLayout + { + Children = { instructionLabel, _resourceImage, _fileImage, measureButton, _resourceImageLabel, _fileImageLabel } + }; + } + + private void OnMeasureClicked(object sender, EventArgs e) + { +#if ANDROID + int resourceByteCount = GetBitmapByteCount(_resourceImage); + int fileByteCount = GetBitmapByteCount(_fileImage); + + _resourceImageLabel.Text = $"ByteCount:{resourceByteCount}"; + _fileImageLabel.Text = $"ByteCount:{fileByteCount}"; +#endif + } + +#if ANDROID + static int GetBitmapByteCount(Image image) + { + if (image?.Handler?.PlatformView is not ImageView imageView) + return 0; + + if (imageView.Drawable is BitmapDrawable drawable && drawable.Bitmap != null) + return drawable.Bitmap.ByteCount; + + // Fallback: render into a bitmap + if (imageView.Width > 0 && imageView.Height > 0 && Bitmap.Config.Argb8888 != null) + { + using var bitmap = Bitmap.CreateBitmap(imageView.Width, imageView.Height, Bitmap.Config.Argb8888); + if (bitmap != null) + { + var canvas = new Canvas(bitmap); + imageView.Draw(canvas); + return bitmap.ByteCount; + } + } + + return 0; + } +#endif +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33239.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33239.cs new file mode 100644 index 000000000000..f0eb756e000f --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33239.cs @@ -0,0 +1,25 @@ +#if ANDROID +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue33239 : _IssuesUITest +{ + public override string Issue => "Unexpected high Image ByteCount when loading an image from resources using ImageSource"; + + public Issue33239(TestDevice device) : base(device) { } + + [Test] + [Category(UITestCategories.Image)] + public void ImageFromResourceAndFileShouldHaveSimilarByteCount() + { + App.WaitForElement("MeasureButton"); + App.Tap("MeasureButton"); + var file = App.FindElement("FileImageLabel").GetText(); + var resource = App.FindElement("ResourceImageLabel").GetText(); + Assert.That(resource, Is.EqualTo(file)); + } +} +#endif diff --git a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java index 10f724424e45..974b9e51f47e 100644 --- a/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java +++ b/src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java @@ -349,7 +349,8 @@ public static void loadImageFromUri(ImageView imageView, String uri, boolean cac public static void loadImageFromStream(ImageView imageView, InputStream inputStream, ImageLoaderCallback callback) { RequestBuilder builder = Glide .with(imageView) - .load(inputStream); + .load(inputStream) + .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); loadInto(builder, imageView, false, callback, inputStream); } @@ -384,7 +385,8 @@ public static void loadImageFromUri(Context context, String uri, boolean caching public static void loadImageFromStream(Context context, InputStream inputStream, ImageLoaderCallback callback) { RequestBuilder builder = Glide .with(context) - .load(inputStream); + .load(inputStream) + .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); load(builder, context, false, callback, inputStream); }