diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs index 42ca465340a6..2bf394b12e7d 100644 --- a/src/Text/Pandoc/Writers/Typst.hs +++ b/src/Text/Pandoc/Writers/Typst.hs @@ -33,7 +33,7 @@ import Control.Monad.State ( StateT, evalStateT, gets, modify ) import Text.Pandoc.Writers.Shared ( lookupMetaInlines, lookupMetaString, metaToContext, defField, resetField, setupTranslations ) -import Text.Pandoc.Shared (isTightList, orderedListMarkers, tshow) +import Text.Pandoc.Shared (isTightList, orderedListMarkers, stringify, tshow) import Text.Pandoc.Highlighting (highlight, formatTypstBlock, formatTypstInline, styleToTypst) import Text.Pandoc.Translations (Term(Abstract), translateTerm) @@ -365,10 +365,16 @@ blockToTypst block = opts <- gets stOptions contents <- case blocks of -- don't need #box around block-level image - [Para [Image attr _ (src, _)]] - -> pure $ mkImage opts False src attr - [Plain [Image attr _ (src, _)]] - -> pure $ mkImage opts False src attr + [Para [Image attr imgInlines (src, _)]] + -> let mbAlt = if null imgInlines + then Nothing + else Just (stringify imgInlines) + in pure $ mkImage opts False src attr mbAlt + [Plain [Image attr imgInlines (src, _)]] + -> let mbAlt = if null imgInlines + then Nothing + else Just (stringify imgInlines) + in pure $ mkImage opts False src attr mbAlt _ -> brackets <$> blocksToTypst blocks let lab = toLabel FreestandingLabel ident return $ "#figure(" <> nest 2 ((contents <> ",") @@ -529,34 +535,45 @@ inlineToTypst inline = (if inlines == [Str src] then mempty else nowrap $ brackets contents) - Image attr _inlines (src,_tit) -> do - opts <- gets stOptions - pure $ mkImage opts True src attr + Image attr imgInlines (src,_tit) -> do + opts <- gets stOptions + let mbAlt = if null imgInlines + then Nothing + else Just (stringify imgInlines) + pure $ mkImage opts True src attr mbAlt Note blocks -> do contents <- blocksToTypst blocks return $ "#footnote" <> brackets (chomp contents) -- see #9104; need box or image is treated as block-level -mkImage :: WriterOptions -> Bool -> Text -> Attr -> Doc Text -mkImage opts useBox src attr +mkImage :: WriterOptions -> Bool -> Text -> Attr -> Maybe Text -> Doc Text +mkImage opts useBox src (ident, cls, kvs) mbAlt | useBox = "#box" <> parens coreImage | otherwise = coreImage where src' = T.pack $ unEscapeString $ T.unpack src -- #9389 showDim (Pixel a) = literal (showInInch opts (Pixel a) <> "in") showDim dim = text (show dim) + -- Priority: explicit alt attribute > inlines from markdown + -- Empty alt="" is preserved (indicates decorative image) + altText = case lookup "alt" kvs of + Just alt -> Just alt + Nothing -> mbAlt + altAttr = case altText of + Just alt | not (T.null alt) -> ", alt: " <> doubleQuoted alt + _ -> mempty dimAttrs = - (case dimension Height attr of + (case dimension Height (ident, cls, kvs) of Nothing -> mempty Just dim -> ", height: " <> showDim dim) <> - (case dimension Width attr of + (case dimension Width (ident, cls, kvs) of Nothing -> mempty Just dim -> ", width: " <> showDim dim) isData = "data:" `T.isPrefixOf` src' dataSvg = " src' <> "\" />" coreImage - | isData = "image.decode" <> parens(doubleQuoted dataSvg <> dimAttrs) - | otherwise = "image" <> parens (doubleQuoted src' <> dimAttrs) + | isData = "image.decode" <> parens(doubleQuoted dataSvg <> altAttr <> dimAttrs) + | otherwise = "image" <> parens (doubleQuoted src' <> altAttr <> dimAttrs) textstyle :: PandocMonad m => Doc Text -> [Inline] -> TW m (Doc Text) textstyle s inlines = do diff --git a/test/command/9236.md b/test/command/9236.md index f8eca5fb553b..c903c845ac1a 100644 --- a/test/command/9236.md +++ b/test/command/9236.md @@ -9,25 +9,26 @@ And inline: ![minimal](command/minimal.svg){height=2in} and ![minimal](command/minimal.svg). ^D -#figure(image("command/minimal.svg", width: 3in), +#figure(image("command/minimal.svg", alt: "minimal", width: 3in), caption: [ minimal ] ) -#figure(image("command/minimal.svg", height: 2in, width: 3in), +#figure(image("command/minimal.svg", alt: "minimal", height: 2in, width: 3in), caption: [ minimal ] ) -#figure(image("command/minimal.svg"), +#figure(image("command/minimal.svg", alt: "minimal"), caption: [ minimal ] ) -And inline: #box(image("command/minimal.svg", height: 2in)) and -#box(image("command/minimal.svg")). +And inline: +#box(image("command/minimal.svg", alt: "minimal", height: 2in)) and +#box(image("command/minimal.svg", alt: "minimal")). ``` diff --git a/test/command/typst-image-alt.md b/test/command/typst-image-alt.md new file mode 100644 index 000000000000..12284182c89c --- /dev/null +++ b/test/command/typst-image-alt.md @@ -0,0 +1,78 @@ +``` +% pandoc -f markdown-implicit_figures -t typst +![Alt text from inlines](image.png) +^D +#box(image("image.png", alt: "Alt text from inlines")) +``` + +``` +% pandoc -f markdown-implicit_figures -t typst +![](image.png){alt="Explicit alt attribute"} +^D +#box(image("image.png", alt: "Explicit alt attribute")) +``` + +``` +% pandoc -f markdown-implicit_figures -t typst +![Inlines ignored](image.png){alt="Explicit wins"} +^D +#box(image("image.png", alt: "Explicit wins")) +``` + +``` +% pandoc -f markdown-implicit_figures -t typst +![](image.png) +^D +#box(image("image.png")) +``` + +``` +% pandoc -f markdown-implicit_figures -t typst +![Inlines ignored for decorative](image.png){alt=""} +^D +#box(image("image.png")) +``` + +``` +% pandoc -t typst +![Caption text](image.png){alt="Alt text describing the image"} + +^D +#figure(image("image.png", alt: "Alt text describing the image"), + caption: [ + Caption text + ] +) +``` + +``` +% pandoc -t typst +![Caption only](image.png) + +^D +#figure(image("image.png", alt: "Caption only"), + caption: [ + Caption only + ] +) +``` + +``` +% pandoc -f markdown -t typst +![Caption](test.png){alt="A \"quoted\" phrase and C:\\path\\file"} +^D +#figure(image("test.png", alt: "A \"quoted\" phrase and C:\\path\\file"), + caption: [ + Caption + ] +) + +``` + +``` +% pandoc -f html -t typst +A small red dot +^D +#box(image.decode("", alt: "A small red dot")) + +``` diff --git a/test/writer.typst b/test/writer.typst index 7ce5d05f1520..873628977e26 100644 --- a/test/writer.typst +++ b/test/writer.typst @@ -837,13 +837,13 @@ or here: From "Voyage dans la Lune" by Georges Melies (1902): -#figure(image("lalune.jpg"), +#figure(image("lalune.jpg", alt: "lalune"), caption: [ lalune ] ) -Here is a movie #box(image("movie.jpg")) icon. +Here is a movie #box(image("movie.jpg", alt: "movie")) icon. #horizontalrule