Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for image sizing via titles in markdown #398

Merged
merged 1 commit into from
Feb 4, 2025
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
43 changes: 41 additions & 2 deletions docs/syntax/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,49 @@ Or, use the `image` directive.
## Inline images

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

Here is the same image used inline ![Elasticsearch](img/observability.png)
Here is the same image used inline ![Elasticsearch](img/observability.png "elasticsearch =50%x50%")


### Inline image titles

Titles are optional making this the minimal syntax required

```markdown
![Elasticsearch](img/observability.png)
```

Including a title can be done by supplying it as an optional argument.

```markdown
![Elasticsearch](img/observability.png "elasticsearch")
```

### Inline image sizing

Inline images are supplied at the end through the title argument.

This is done to maintain maximum compatibility with markdown parsers
and previewers.

```markdown
![alt](img.png "title =WxH")
![alt](img.png "title =W")
```

`W` and `H` can be either an absolute number in pixels or a number followed by `%` to indicate relative sizing.

If `H` is omitted `W` is used as the height as well.

```markdown
![alt](img.png "title =250x330")
![alt](img.png "title =50%x40%")
![alt](img.png "title =50%")
```



### SVG

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System.Collections.Immutable;
using System.IO.Abstractions;
using System.Text.RegularExpressions;
using Elastic.Markdown.Diagnostics;
using Elastic.Markdown.IO;
using Elastic.Markdown.Myst.Comments;
Expand All @@ -12,6 +13,7 @@
using Markdig.Parsers;
using Markdig.Parsers.Inlines;
using Markdig.Renderers;
using Markdig.Renderers.Html;
using Markdig.Syntax.Inlines;

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

internal partial class LinkRegexExtensions
{

[GeneratedRegex(@"\s\=(?<width>\d+%?)(?:x(?<height>\d+%?))?$", RegexOptions.IgnoreCase, "en-US")]
public static partial Regex MatchTitleStylingInstructions();

}

public class DiagnosticLinkInlineParser : LinkInlineParser
{
// See https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for a list of URI schemes
Expand All @@ -41,6 +51,7 @@ public class DiagnosticLinkInlineParser : LinkInlineParser
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
var match = base.Match(processor, ref slice);

if (!match || processor.Inline is not LinkInline link)
return match;

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

ValidateAndProcessLink(processor, link, context);

ParseStylingInstructions(processor, link, context);

return match;
}


private void ParseStylingInstructions(InlineProcessor processor, LinkInline link, ParserContext context)
{
if (string.IsNullOrWhiteSpace(link.Title) || link.Title.IndexOf('=') < 0)
return;

var matches = LinkRegexExtensions.MatchTitleStylingInstructions().Match(link.Title);
if (!matches.Success)
return;

var width = matches.Groups["width"].Value;
if (!width.EndsWith("%"))
width += "px";
var height = matches.Groups["height"].Value;
if (string.IsNullOrEmpty(height))
height = width;
else if (!height.EndsWith("%"))
height += "px";
var title = link.Title[..matches.Index];

link.Title = title;
var attributes = link.GetAttributes();
attributes.AddProperty("width", width);
attributes.AddProperty("height", height);
}

private static bool IsInCommentBlock(LinkInline link) =>
link.Parent?.ParentBlock is CommentBlock;

Expand Down
43 changes: 43 additions & 0 deletions tests/authoring/Inline/InlineImages.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,46 @@ type ``relative path to image`` () =
markdown |> convertsToHtml """
<p><img src="_static/img/observability.png" alt="Elasticsearch" /></p>
"""

type ``supplying a tittle`` () =
static let markdown = Setup.Markdown """
![Elasticsearch](_static/img/observability.png "Hello world")
"""

[<Fact>]
let ``validate HTML: includes title`` () =
markdown |> convertsToHtml """
<p><img src="_static/img/observability.png" alt="Elasticsearch" title="Hello world" /></p>
"""

type ``supplying a tittle with width and height`` () =
static let markdown = Setup.Markdown """
![o](obs.png "Title =250x400")
"""

[<Fact>]
let ``validate HTML: does not include width and height in title`` () =
markdown |> convertsToHtml """
<p><img src="obs.png" width="250px" height="400px" alt="o" title="Title"/></p>
"""

type ``supplying a tittle with width and height in percentage`` () =
static let markdown = Setup.Markdown """
![o](obs.png "Title =50%x40%")
"""

[<Fact>]
let ``validate HTML: does not include width and height in title`` () =
markdown |> convertsToHtml """
<p><img src="obs.png" width="50%" height="40%" alt="o" title="Title"/></p>
"""
type ``supplying a tittle with width only`` () =
static let markdown = Setup.Markdown """
![o](obs.png "Title =30%")
"""

[<Fact>]
let ``validate HTML: sets height to width if not supplied`` () =
markdown |> convertsToHtml """
<p><img src="obs.png" width="30%" height="30%" alt="o" title="Title"/></p>
"""