Skip to content

Commit 250d161

Browse files
authored
Add support for image sizing via titles in markdown (#398)
Introduced a feature to parse width and height from image titles using a regex pattern. Updated the markdown parser, tests, and docs to support and demonstrate inline image resizing with syntax like `=WxH` or `=W`. If height is omitted, it defaults to the width value.
1 parent 80a60fa commit 250d161

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

docs/syntax/images.md

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,49 @@ Or, use the `image` directive.
3939
## Inline images
4040

4141
```markdown
42-
Here is the same image used inline ![Elasticsearch](img/observability.png)
42+
Here is the same image used inline ![Elasticsearch](img/observability.png "elasticsearch =50%x50%")
4343
```
4444

45-
Here is the same image used inline ![Elasticsearch](img/observability.png)
45+
Here is the same image used inline ![Elasticsearch](img/observability.png "elasticsearch =50%x50%")
46+
47+
48+
### Inline image titles
49+
50+
Titles are optional making this the minimal syntax required
51+
52+
```markdown
53+
![Elasticsearch](img/observability.png)
54+
```
55+
56+
Including a title can be done by supplying it as an optional argument.
57+
58+
```markdown
59+
![Elasticsearch](img/observability.png "elasticsearch")
60+
```
61+
62+
### Inline image sizing
63+
64+
Inline images are supplied at the end through the title argument.
65+
66+
This is done to maintain maximum compatibility with markdown parsers
67+
and previewers.
68+
69+
```markdown
70+
![alt](img.png "title =WxH")
71+
![alt](img.png "title =W")
72+
```
73+
74+
`W` and `H` can be either an absolute number in pixels or a number followed by `%` to indicate relative sizing.
75+
76+
If `H` is omitted `W` is used as the height as well.
77+
78+
```markdown
79+
![alt](img.png "title =250x330")
80+
![alt](img.png "title =50%x40%")
81+
![alt](img.png "title =50%")
82+
```
83+
84+
4685

4786
### SVG
4887

src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Collections.Immutable;
66
using System.IO.Abstractions;
7+
using System.Text.RegularExpressions;
78
using Elastic.Markdown.Diagnostics;
89
using Elastic.Markdown.IO;
910
using Elastic.Markdown.Myst.Comments;
@@ -12,6 +13,7 @@
1213
using Markdig.Parsers;
1314
using Markdig.Parsers.Inlines;
1415
using Markdig.Renderers;
16+
using Markdig.Renderers.Html;
1517
using Markdig.Syntax.Inlines;
1618

1719
namespace Elastic.Markdown.Myst.InlineParsers;
@@ -33,6 +35,14 @@ public void Setup(MarkdownPipelineBuilder pipeline) =>
3335
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { }
3436
}
3537

38+
internal partial class LinkRegexExtensions
39+
{
40+
41+
[GeneratedRegex(@"\s\=(?<width>\d+%?)(?:x(?<height>\d+%?))?$", RegexOptions.IgnoreCase, "en-US")]
42+
public static partial Regex MatchTitleStylingInstructions();
43+
44+
}
45+
3646
public class DiagnosticLinkInlineParser : LinkInlineParser
3747
{
3848
// See https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for a list of URI schemes
@@ -41,6 +51,7 @@ public class DiagnosticLinkInlineParser : LinkInlineParser
4151
public override bool Match(InlineProcessor processor, ref StringSlice slice)
4252
{
4353
var match = base.Match(processor, ref slice);
54+
4455
if (!match || processor.Inline is not LinkInline link)
4556
return match;
4657

@@ -49,9 +60,38 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice)
4960
return match;
5061

5162
ValidateAndProcessLink(processor, link, context);
63+
64+
ParseStylingInstructions(processor, link, context);
65+
5266
return match;
5367
}
5468

69+
70+
private void ParseStylingInstructions(InlineProcessor processor, LinkInline link, ParserContext context)
71+
{
72+
if (string.IsNullOrWhiteSpace(link.Title) || link.Title.IndexOf('=') < 0)
73+
return;
74+
75+
var matches = LinkRegexExtensions.MatchTitleStylingInstructions().Match(link.Title);
76+
if (!matches.Success)
77+
return;
78+
79+
var width = matches.Groups["width"].Value;
80+
if (!width.EndsWith("%"))
81+
width += "px";
82+
var height = matches.Groups["height"].Value;
83+
if (string.IsNullOrEmpty(height))
84+
height = width;
85+
else if (!height.EndsWith("%"))
86+
height += "px";
87+
var title = link.Title[..matches.Index];
88+
89+
link.Title = title;
90+
var attributes = link.GetAttributes();
91+
attributes.AddProperty("width", width);
92+
attributes.AddProperty("height", height);
93+
}
94+
5595
private static bool IsInCommentBlock(LinkInline link) =>
5696
link.Parent?.ParentBlock is CommentBlock;
5797

tests/authoring/Inline/InlineImages.fs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,46 @@ type ``relative path to image`` () =
2828
markdown |> convertsToHtml """
2929
<p><img src="_static/img/observability.png" alt="Elasticsearch" /></p>
3030
"""
31+
32+
type ``supplying a tittle`` () =
33+
static let markdown = Setup.Markdown """
34+
![Elasticsearch](_static/img/observability.png "Hello world")
35+
"""
36+
37+
[<Fact>]
38+
let ``validate HTML: includes title`` () =
39+
markdown |> convertsToHtml """
40+
<p><img src="_static/img/observability.png" alt="Elasticsearch" title="Hello world" /></p>
41+
"""
42+
43+
type ``supplying a tittle with width and height`` () =
44+
static let markdown = Setup.Markdown """
45+
![o](obs.png "Title =250x400")
46+
"""
47+
48+
[<Fact>]
49+
let ``validate HTML: does not include width and height in title`` () =
50+
markdown |> convertsToHtml """
51+
<p><img src="obs.png" width="250px" height="400px" alt="o" title="Title"/></p>
52+
"""
53+
54+
type ``supplying a tittle with width and height in percentage`` () =
55+
static let markdown = Setup.Markdown """
56+
![o](obs.png "Title =50%x40%")
57+
"""
58+
59+
[<Fact>]
60+
let ``validate HTML: does not include width and height in title`` () =
61+
markdown |> convertsToHtml """
62+
<p><img src="obs.png" width="50%" height="40%" alt="o" title="Title"/></p>
63+
"""
64+
type ``supplying a tittle with width only`` () =
65+
static let markdown = Setup.Markdown """
66+
![o](obs.png "Title =30%")
67+
"""
68+
69+
[<Fact>]
70+
let ``validate HTML: sets height to width if not supplied`` () =
71+
markdown |> convertsToHtml """
72+
<p><img src="obs.png" width="30%" height="30%" alt="o" title="Title"/></p>
73+
"""

0 commit comments

Comments
 (0)