diff --git a/src/Markdig.Tests/Markdig.Tests.csproj b/src/Markdig.Tests/Markdig.Tests.csproj
index 9e7fc9688..bbb6f935d 100644
--- a/src/Markdig.Tests/Markdig.Tests.csproj
+++ b/src/Markdig.Tests/Markdig.Tests.csproj
@@ -65,6 +65,7 @@
+
diff --git a/src/Markdig.Tests/TestRelativeUrlReplacement.cs b/src/Markdig.Tests/TestRelativeUrlReplacement.cs
new file mode 100644
index 000000000..edf9b83f3
--- /dev/null
+++ b/src/Markdig.Tests/TestRelativeUrlReplacement.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using Markdig.Parsers;
+using Markdig.Renderers;
+using NUnit.Framework;
+
+namespace Markdig.Tests
+{
+ public class TestRelativeUrlReplacement
+ {
+ [Test]
+ public void ReplacesRelativeLinks()
+ {
+ TestSpec("https://example.com", "Link: [hello](/relative.jpg)", "https://example.com/relative.jpg");
+ TestSpec("https://example.com", "Link: [hello](relative.jpg)", "https://example.com/relative.jpg");
+ TestSpec("https://example.com/", "Link: [hello](/relative.jpg?a=b)", "https://example.com/relative.jpg?a=b");
+ TestSpec("https://example.com/", "Link: [hello](relative.jpg#x)", "https://example.com/relative.jpg#x");
+ TestSpec(null, "Link: [hello](relative.jpg)", "relative.jpg");
+ TestSpec(null, "Link: [hello](/relative.jpg)", "/relative.jpg");
+ TestSpec("https://example.com", "Link: [hello](/relative.jpg)", "https://example.com/relative.jpg");
+ }
+
+ [Test]
+ public void ReplacesRelativeImageSources()
+ {
+ TestSpec("https://example.com", "Image: ![alt text](/image.jpg)", "https://example.com/image.jpg");
+ TestSpec("https://example.com", "Image: ![alt text](image.jpg \"title\")", "https://example.com/image.jpg");
+ TestSpec(null, "Image: ![alt text](/image.jpg)", "/image.jpg");
+ }
+
+ public static void TestSpec(string baseUrl, string markdown, string expectedLink)
+ {
+ var pipeline = new MarkdownPipelineBuilder().Build();
+
+ var writer = new StringWriter();
+ var renderer = new HtmlRenderer(writer);
+ if (baseUrl != null)
+ renderer.BaseUrl = new Uri(baseUrl);
+ pipeline.Setup(renderer);
+
+ var document = MarkdownParser.Parse(markdown, pipeline);
+ renderer.Render(document);
+ writer.Flush();
+
+ Assert.That(writer.ToString(), Contains.Substring("=\"" + expectedLink + "\""));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Markdig/Renderers/HtmlRenderer.cs b/src/Markdig/Renderers/HtmlRenderer.cs
index 68ceab42f..f529a17e2 100644
--- a/src/Markdig/Renderers/HtmlRenderer.cs
+++ b/src/Markdig/Renderers/HtmlRenderer.cs
@@ -75,6 +75,11 @@ public HtmlRenderer(TextWriter writer) : base(writer)
public bool UseNonAsciiNoEscape { get; set; }
+ ///
+ /// Gets a value to use as the base url for all relative links
+ ///
+ public Uri BaseUrl { get; set; }
+
///
/// Writes the content escaped for HTML.
///
@@ -192,6 +197,11 @@ public HtmlRenderer WriteEscapeUrl(string content)
if (content == null)
return this;
+ if (BaseUrl != null && !Uri.TryCreate(content, UriKind.Absolute, out Uri _))
+ {
+ content = new Uri(BaseUrl, content).AbsoluteUri;
+ }
+
int previousPosition = 0;
int length = content.Length;