mirror of
https://github.com/kovetskiy/mark.git
synced 2026-03-14 06:07:36 +08:00
feat: add support for image dimensions
This commit is contained in:
parent
c32cd79dc8
commit
4d887bde74
@ -78,7 +78,14 @@ You can set a page emoji icon by specifying the icon in the headers.
|
||||
<!-- Image-Align: center -->
|
||||
```
|
||||
|
||||
You can set the alignment for all images in the page. Common values are `left`, `center`, and `right`. This adds the `ac:align` attribute to image tags. Can also be set globally via the `--image-align` CLI option (per-page header takes precedence).
|
||||
You can set the alignment for all images in the page. Common values are `left`, `center`, and `right`. This adds the `ac:align` attribute to image tags and also sets the corresponding `ac:layout` attribute:
|
||||
- `left` → `ac:align="left" ac:layout="align-start"`
|
||||
- `center` → `ac:align="center" ac:layout="center"`
|
||||
- `right` → `ac:align="right" ac:layout="align-end"`
|
||||
|
||||
**Note**: Images with width >= 760px automatically use `ac:align="wide"` with `ac:layout="center"` instead of the configured alignment, as Confluence requires this for wide images.
|
||||
|
||||
Custom values are passed through as-is with only the `ac:align` attribute. Can also be set globally via the `--image-align` CLI option (per-page header takes precedence).
|
||||
|
||||
Mark supports Go templates, which can be included into article by using path
|
||||
to the template relative to current working dir, e.g.:
|
||||
|
||||
@ -4,11 +4,16 @@ import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kovetskiy/mark/confluence"
|
||||
@ -210,12 +215,20 @@ func prepareAttachment(opener vfs.Opener, base, name string) (Attachment, error)
|
||||
return Attachment{}, karma.Format(err, "unable to read file: %q", attachmentPath)
|
||||
}
|
||||
|
||||
return Attachment{
|
||||
attachment := Attachment{
|
||||
Name: name,
|
||||
Filename: strings.ReplaceAll(name, "/", "_"),
|
||||
FileBytes: fileBytes,
|
||||
Replace: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Try to detect image dimensions
|
||||
if config, _, err := image.DecodeConfig(bytes.NewReader(fileBytes)); err == nil {
|
||||
attachment.Width = strconv.Itoa(config.Width)
|
||||
attachment.Height = strconv.Itoa(config.Height)
|
||||
}
|
||||
|
||||
return attachment, nil
|
||||
}
|
||||
|
||||
func CompileAttachmentLinks(markdown []byte, attachments []Attachment) []byte {
|
||||
|
||||
@ -139,10 +139,14 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
r.Attachments.Attach(attachment)
|
||||
|
||||
effectiveAlign := calculateAlign(r.MarkConfig.ImageAlign, attachment.Width)
|
||||
|
||||
err = r.Stdlib.Templates.ExecuteTemplate(
|
||||
writer,
|
||||
"ac:image",
|
||||
struct {
|
||||
Align string
|
||||
Width string
|
||||
Height string
|
||||
Title string
|
||||
@ -150,6 +154,7 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu
|
||||
Attachment string
|
||||
Url string
|
||||
}{
|
||||
effectiveAlign,
|
||||
attachment.Width,
|
||||
attachment.Height,
|
||||
attachment.Name,
|
||||
@ -170,10 +175,14 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
r.Attachments.Attach(attachment)
|
||||
|
||||
effectiveAlign := calculateAlign(r.MarkConfig.ImageAlign, attachment.Width)
|
||||
|
||||
err = r.Stdlib.Templates.ExecuteTemplate(
|
||||
writer,
|
||||
"ac:image",
|
||||
struct {
|
||||
Align string
|
||||
Width string
|
||||
Height string
|
||||
Title string
|
||||
@ -181,6 +190,7 @@ func (r *ConfluenceFencedCodeBlockRenderer) renderFencedCodeBlock(writer util.Bu
|
||||
Attachment string
|
||||
Url string
|
||||
}{
|
||||
effectiveAlign,
|
||||
attachment.Width,
|
||||
attachment.Height,
|
||||
attachment.Name,
|
||||
|
||||
@ -3,6 +3,7 @@ package renderer
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/kovetskiy/mark/attachment"
|
||||
@ -15,6 +16,30 @@ import (
|
||||
"github.com/yuin/goldmark/util"
|
||||
)
|
||||
|
||||
// calculateAlign determines the appropriate ac:align value based on width
|
||||
// Images >= 760px wide use "wide", otherwise use the configured alignment
|
||||
func calculateAlign(configuredAlign string, width string) string {
|
||||
if configuredAlign == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
if width == "" {
|
||||
return configuredAlign
|
||||
}
|
||||
|
||||
// Parse width and check if >= 760
|
||||
widthInt, err := strconv.Atoi(width)
|
||||
if err != nil {
|
||||
return configuredAlign
|
||||
}
|
||||
|
||||
if widthInt >= 760 {
|
||||
return "wide"
|
||||
}
|
||||
|
||||
return configuredAlign
|
||||
}
|
||||
|
||||
type ConfluenceImageRenderer struct {
|
||||
html.Config
|
||||
Stdlib *stdlib.Lib
|
||||
@ -78,6 +103,8 @@ func (r *ConfluenceImageRenderer) renderImage(writer util.BufWriter, source []by
|
||||
|
||||
r.Attachments.Attach(attachments[0])
|
||||
|
||||
effectiveAlign := calculateAlign(r.ImageAlign, attachments[0].Width)
|
||||
|
||||
err = r.Stdlib.Templates.ExecuteTemplate(
|
||||
writer,
|
||||
"ac:image",
|
||||
@ -90,9 +117,9 @@ func (r *ConfluenceImageRenderer) renderImage(writer util.BufWriter, source []by
|
||||
Attachment string
|
||||
Url string
|
||||
}{
|
||||
r.ImageAlign,
|
||||
"",
|
||||
"",
|
||||
effectiveAlign,
|
||||
attachments[0].Width,
|
||||
attachments[0].Height,
|
||||
string(n.Title),
|
||||
string(nodeToHTMLText(n, source)),
|
||||
attachments[0].Filename,
|
||||
|
||||
@ -212,6 +212,7 @@ func templates(api *confluence.API) (*template.Template, error) {
|
||||
`ac:image`: text(
|
||||
`<ac:image`,
|
||||
`{{ if .Align }} ac:align="{{ .Align }}"{{ end }}`,
|
||||
`{{ if eq .Align "left" }} ac:layout="align-start"{{ else if eq .Align "center" }} ac:layout="center"{{ else if eq .Align "right" }} ac:layout="align-end"{{ else if eq .Align "wide" }} ac:layout="center"{{ end }}`,
|
||||
`{{ if .Width }} ac:width="{{ .Width }}"{{ end }}`,
|
||||
`{{ if .Height }} ac:height="{{ .Height }}"{{ end }}`,
|
||||
`{{ if .Title }} ac:title="{{ .Title }}"{{ end }}`,
|
||||
|
||||
2
testdata/links.html
vendored
2
testdata/links.html
vendored
@ -5,7 +5,7 @@
|
||||
<p>Use <ac:link><ri:page ri:content-title="Another Page"/><ac:plain-text-link-body><![CDATA[Another Page]]></ac:plain-text-link-body></ac:link></p>
|
||||
<p>Use <ac:link><ri:page ri:content-title="test_link"/><ac:plain-text-link-body><![CDATA[Another Page]]></ac:plain-text-link-body></ac:link></p>
|
||||
<p>Use <ac:link><ri:page ri:content-title="Page With Space"/><ac:plain-text-link-body><![CDATA[page link with spaces]]></ac:plain-text-link-body></ac:link></p>
|
||||
<p><ac:image ac:alt="My Image"><ri:attachment ri:filename="test.png"/></ac:image></p>
|
||||
<p><ac:image ac:width="1000" ac:height="631" ac:alt="My Image"><ri:attachment ri:filename="test.png"/></ac:image></p>
|
||||
<p><ac:image ac:alt="My External Image"><ri:url ri:value="http://confluence.atlassian.com/images/logo/confluence_48_trans.png?key1=value1&key2=value2"/></ac:image></p>
|
||||
<p><ac:link><ri:page ri:content-title="test_link"/><ac:plain-text-link-body><![CDATA[My test_link]]></ac:plain-text-link-body></ac:link></p>
|
||||
<p><ac:link><ri:page ri:content-title="test_link_link"/><ac:plain-text-link-body><![CDATA[Another [Link]]]></ac:plain-text-link-body></ac:link></p>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user