Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/Svg.Model/Services/SvgService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@
return true;
}

return element.CustomAttributes.TryGetValue($"{SvgNamespaces.XmlNamespace}:base", out value);

Check warning on line 443 in src/Svg.Model/Services/SvgService.cs

View workflow job for this annotation

GitHub Actions / Build MAUI (macos-latest)

Possible null reference assignment.

Check warning on line 443 in src/Svg.Model/Services/SvgService.cs

View workflow job for this annotation

GitHub Actions / Build MAUI (macos-latest)

Possible null reference assignment.

Check warning on line 443 in src/Svg.Model/Services/SvgService.cs

View workflow job for this annotation

GitHub Actions / Pack MAUI (macos-latest)

Possible null reference assignment.
}

internal static Uri GetImageDocumentUri(Uri uri)
Expand Down Expand Up @@ -488,6 +488,11 @@
return GetImageFromDataUri(uriString, svgOwnerElement, assetLoader);
}

if (!uri.IsAbsoluteUri)
{
return default;
}

return GetImageFromWeb(uri, assetLoader);
}
catch (Exception ex)
Expand Down
84 changes: 84 additions & 0 deletions tests/Svg.Model.UnitTests/SvgServiceImageUriTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using Svg;
using Svg.Model.Services;
using Xunit;

namespace Svg.Model.UnitTests;

public class SvgServiceImageUriTests
{
[Fact]
public void GetImageUri_RelativeImageHrefWithoutBaseUri_RemainsRelative()
{
const string svg = """
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="32" height="32">
<image id="missing-image" width="99" height="108" xlink:href="6F03BD87.png" />
</svg>
""";

var document = SvgService.FromSvg(svg);
Assert.NotNull(document);

var image = Assert.IsType<SvgImage>(document!.GetElementById("missing-image"));

var uri = SvgService.GetImageUri(image.Href, image);

Assert.False(uri.IsAbsoluteUri);
Assert.Equal("6F03BD87.png", uri.OriginalString);
}

[Fact]
public void GetImage_RelativeImageHrefWithoutBaseUri_ReturnsNull()
{
const string svg = """
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="32" height="32">
<image id="missing-image" width="99" height="108" xlink:href="6F03BD87.png" />
</svg>
""";

var document = SvgService.FromSvg(svg);
Assert.NotNull(document);

var image = Assert.IsType<SvgImage>(document!.GetElementById("missing-image"));

var loadedImage = SvgService.GetImage(image.Href, image, new TestAssetLoader());

Assert.Null(loadedImage);
}

[Fact]
public void GetImageUri_DocumentOwnerWithoutBaseUri_RemainsRelative()
{
const string svg = """
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" />
""";

var document = SvgService.FromSvg(svg);
Assert.NotNull(document);

var uri = SvgService.GetImageUri("6F03BD87.png", document!);

Assert.False(uri.IsAbsoluteUri);
Assert.Equal("6F03BD87.png", uri.OriginalString);
}

[Fact]
public void GetImageUri_DocumentOwnerUsesDocumentBaseUri()
{
const string svg = """
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" />
""";

var document = SvgService.FromSvg(svg);
Assert.NotNull(document);
document!.BaseUri = new Uri("https://example.test/assets/source.svg");

var uri = SvgService.GetImageUri("6F03BD87.png", document);

Assert.Equal(new Uri("https://example.test/assets/6F03BD87.png"), uri);
}
}
31 changes: 31 additions & 0 deletions tests/Svg.Skia.UnitTests/SKSvgTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,35 @@ public void Load_CssFontFaceWithExternalFontUrl_DoesNotCrash()
Assert.Equal(120, image.Width);
Assert.Equal(40, image.Height);
}

[Fact]
public void Load_RelativeImageHrefWithoutBaseUri_SkipsMissingImage()
{
const string svgMarkup = """
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="32px" height="32px" viewBox="0 0 32 32">
<rect width="32" height="32" fill="#232B34" />
<g opacity="0.1">
<image width="99" height="108" xlink:href="6F03BD87.png"
transform="matrix(1 0 0 1 -33.5 -44.6934)" />
</g>
<circle cx="16" cy="16" r="8" fill="#586871" />
</svg>
""";

var svg = new SKSvg();
using var input = new MemoryStream(Encoding.UTF8.GetBytes(svgMarkup));
using var _ = svg.Load(input);
using var output = new MemoryStream();

Assert.True(svg.Save(output, SkiaSharp.SKColors.Transparent));

output.Position = 0;
using var image = Image.Load<Rgba32>(output);
Assert.Equal(32, image.Width);
Assert.Equal(32, image.Height);
Assert.Equal(new Rgba32(0x23, 0x2B, 0x34), image[0, 0]);
Assert.Equal(new Rgba32(0x58, 0x68, 0x71), image[16, 16]);
}
}
Loading