Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1e731e1
Initial plan
Copilot Jul 15, 2025
d65d50c
Fix Graphics IImage test resource loading for net10.0 compatibility
Copilot Jul 15, 2025
0ee42ee
Fix Android threading issues by pre-loading images asynchronously
Copilot Jul 15, 2025
f54bc86
Fix stream handling by copying to MemoryStream before PlatformImage.F…
Copilot Jul 15, 2025
76c6b99
Enhanced image loading with better error handling and PlatformImageLo…
Copilot Jul 15, 2025
a71e4ff
Fix PlatformImage.FromStream null handling for .NET 10.0 compatibilit…
Copilot Jul 16, 2025
b85e2dc
Add comprehensive exception handling around PlatformImage.FromStream …
Copilot Jul 16, 2025
b6f2bbe
Simplify approach: Fix .NET 10.0 stream positioning issues with minim…
Copilot Jul 16, 2025
b046791
Fix .NET 10.0 Android marshal method compatibility for Graphics IImag…
Copilot Jul 16, 2025
c1d0dc7
Add AndroidEnableMarshalMethods=false to fix .NET 10.0 Graphics test …
Copilot Jul 16, 2025
870907d
Restore AndroidEnableMarshalMethods setting after confirming it's not…
Copilot Jul 16, 2025
244b8eb
Add HybridWebView JavaScript support for cross-platform web messaging
Copilot Jul 17, 2025
3e9d337
Investigate marshal methods compatibility: Use BitmapFactory.DecodeSt…
Copilot Jul 17, 2025
340e09e
Use BitmapFactory.DecodeByteArray for better .NET 10.0 marshal method…
Copilot Jul 17, 2025
980dcf8
Optimize PlatformImage.FromStream for better memory efficiency and er…
Copilot Jul 18, 2025
db29e72
Add null stream validation to PlatformImage.FromStream across all pla…
Copilot Jul 18, 2025
de39299
Update PlatformImage.FromStream to return null instead of throwing ex…
Copilot Jul 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
<DefineConstants>$(DefineConstants);NATIVE_AOT</DefineConstants>
</PropertyGroup>

<!-- Test marshal methods compatibility with BitmapFactory.DecodeStreamAsync approach -->
<!-- This tests if using async BitmapFactory methods works better with .NET 10.0 marshal methods -->
<!-- Reference: https://github.com/dotnet/core/blob/main/release-notes/10.0/preview/preview1/dotnetmaui.md#enable-marshal-methods-by-default -->
<PropertyGroup Condition="$(TargetFramework.Contains('-android'))">
<AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods>
</PropertyGroup>

<ItemGroup Condition=" '$(UseMaui)' != 'true' ">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>
Expand Down Expand Up @@ -66,7 +73,7 @@
<MauiFont Include="Resources\Fonts\**" />
<MauiFont Remove="Resources\Fonts\Dokdo-Regular.ttf" />
<EmbeddedResource Include="Resources\Fonts\Dokdo-Regular.ttf" />
<EmbeddedResource Include="Resources\Images\royals.png" />
<MauiAsset Include="Resources\Images\royals.png" />
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

Expand Down
25 changes: 21 additions & 4 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue16767_Downsize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,29 @@ public class Issue16767_DownsizeDrawable : IDrawable
{
public void Draw(ICanvas canvas, RectF dirtyRect)
{
IImage image;
var assembly = GetType().GetTypeInfo().Assembly;
using (var stream = assembly.GetManifestResourceStream("Controls.TestCases.HostApp.Resources.Images.royals.png"))
IImage image = null;

try
{
image = PlatformImage.FromStream(stream);
// Use FileSystem.OpenAppPackageFileAsync for MauiAsset approach
var task = FileSystem.OpenAppPackageFileAsync("royals.png");
task.Wait();
using (var stream = task.Result)
{
// Copy to MemoryStream to ensure stream is properly buffered for marshal methods
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
image = PlatformImage.FromStream(memoryStream);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to load image: {ex.Message}");
}

if (image is not null)
{
float spacing = 20;
Expand Down
24 changes: 20 additions & 4 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue16767_Resize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,27 @@ internal void SetResizeMode(ResizeMode resizeMode)

public void Draw(ICanvas canvas, RectF dirtyRect)
{
IImage image;
var assembly = GetType().GetTypeInfo().Assembly;
using (var stream = assembly.GetManifestResourceStream("Controls.TestCases.HostApp.Resources.Images.royals.png"))
IImage image = null;

try
{
image = PlatformImage.FromStream(stream);
// Use FileSystem.OpenAppPackageFileAsync for MauiAsset approach
var task = FileSystem.OpenAppPackageFileAsync("royals.png");
task.Wait();
using (var stream = task.Result)
{
// Copy to MemoryStream to ensure stream is properly buffered for marshal methods
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
image = PlatformImage.FromStream(memoryStream);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to load image: {ex.Message}");
}

if (image is not null)
Expand Down
18 changes: 15 additions & 3 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue21886.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,21 @@ Button CreateButton(string text, EventHandler handler)

async Task<IImage> LoadImageAsync()
{
var assembly = GetType().GetTypeInfo().Assembly;
using var stream = assembly.GetManifestResourceStream("Controls.TestCases.HostApp.Resources.Images.royals.png");
return await Task.FromResult(PlatformImage.FromStream(stream));
try
{
// Use FileSystem.OpenAppPackageFileAsync for MauiAsset approach
using var stream = await FileSystem.OpenAppPackageFileAsync("royals.png");
// Copy to MemoryStream to ensure stream is properly buffered for marshal methods
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
return PlatformImage.FromStream(memoryStream);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to load image: {ex.Message}");
return null;
}
}

async void OnResize(object sender, EventArgs e)
Expand Down
18 changes: 15 additions & 3 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue30006.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,21 @@ Button CreateButton(string text, EventHandler handler)

async Task<IImage> LoadImageAsync()
{
var assembly = GetType().GetTypeInfo().Assembly;
using var stream = assembly.GetManifestResourceStream("Controls.TestCases.HostApp.Resources.Images.royals.png");
return await Task.FromResult(PlatformImage.FromStream(stream));
try
{
// Use FileSystem.OpenAppPackageFileAsync for MauiAsset approach
using var stream = await FileSystem.OpenAppPackageFileAsync("royals.png");
// Copy to MemoryStream to ensure stream is properly buffered for marshal methods
using var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
return PlatformImage.FromStream(memoryStream);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to load image: {ex.Message}");
return null;
}
}

async void OnDownSize(object sender, EventArgs e)
Expand Down
24 changes: 22 additions & 2 deletions src/Graphics/src/Graphics/Platforms/Android/PlatformImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,28 @@ public IImage ToPlatformImage()

public static IImage FromStream(Stream stream, ImageFormat formatHint = ImageFormat.Png)
{
var bitmap = BitmapFactory.DecodeStream(stream);
return new PlatformImage(bitmap);
Bitmap bitmap;

if (stream is null)
{
return null;
}
//For memory efficiency, use a single MemoryStream and access its buffer directly
using (var memoryStream = new MemoryStream())
{
if (stream.CanSeek)
{
stream.Position = 0;
}
stream.CopyTo(memoryStream);

// Get the buffer and actual length
byte[] buffer = memoryStream.GetBuffer();
int length = (int)memoryStream.Length;
bitmap = BitmapFactory.DecodeByteArray(buffer, 0, length);
}

return bitmap != null ? new PlatformImage(bitmap) : null;
}
}
}
3 changes: 0 additions & 3 deletions src/Graphics/src/Graphics/Platforms/Mac/PlatformImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,6 @@ public IImage ToPlatformImage()

public static IImage FromStream(Stream stream, ImageFormat formatHint = ImageFormat.Png)
{
if (stream == null)
return null;

var previous = NSApplication.CheckForIllegalCrossThreadCalls;
NSApplication.CheckForIllegalCrossThreadCalls = false;
var data = NSData.FromStream(stream);
Expand Down