From a67223c44219c5a6b2154a06dffedecdd26e925e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 20 Oct 2023 12:18:46 -0700 Subject: [PATCH] Typst writer: add `#box` around image to make it inline. (#9149) An `#image` by itself in typst is a block-level element. To force images to be inline (as they are in pandoc), we need to add a box with an explicit width. When a width is not given in image attributes, we compute one from the image itself, when possible. Closes #9104, supersedes #9105. --- src/Text/Pandoc/Writers/Typst.hs | 33 +++++++++++++++++++++++++++----- test/writer.typst | 4 ++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs index f8cc651de025..d66897fba0d8 100644 --- a/src/Text/Pandoc/Writers/Typst.hs +++ b/src/Text/Pandoc/Writers/Typst.hs @@ -17,7 +17,8 @@ module Text.Pandoc.Writers.Typst ( writeTypst ) where import Text.Pandoc.Definition -import Text.Pandoc.Class.PandocMonad ( PandocMonad ) +import Text.Pandoc.Class ( PandocMonad, fetchItem ) +import Text.Pandoc.ImageSize (imageSize, sizeInPoints) import Text.Pandoc.Options ( WriterOptions(..), WrapOption(..), isEnabled ) import Data.Text (Text) import Data.List (intercalate, intersperse) @@ -30,6 +31,7 @@ import Text.Pandoc.Writers.Math (convertMath) import qualified Text.TeXMath as TM import Text.DocLayout import Text.DocTemplates (renderTemplate) +import Control.Monad.Except (catchError) import Text.Pandoc.Extensions (Extension(..)) import Text.Collate.Lang (Lang(..), parseLang) @@ -280,10 +282,31 @@ inlineToTypst inline = then mempty else nowrap $ brackets contents Image (_,_,kvs) _inlines (src,_tit) -> do - let width' = maybe mempty ((", width: " <>) . literal) $ lookup "width" kvs - let height' = maybe mempty ((", height: " <>) . literal) $ - lookup "height" kvs - return $ "#image(" <> doubleQuoted src <> width' <> height' <> ")" + opts <- gets stOptions + let mbHeight = lookup "height" kvs + let mdWidth = lookup "width" kvs + let coreImage = "image" <> + parens (doubleQuoted src <> + maybe mempty (\w -> ", width: " <> literal w) mdWidth <> + maybe mempty (\h -> ", height: " <> literal h) mbHeight) + -- see #9104; we need a box or the image is treated as block-level: + case (mdWidth, mbHeight) of + (Nothing, Nothing) -> do + realWidth <- catchError + (do (bs, _mt) <- fetchItem src + case imageSize opts bs of + Right x -> pure $ Just $ T.pack $ + show (fst (sizeInPoints x)) <> "pt" + Left _ -> pure Nothing) + (\_ -> pure Nothing) + case realWidth of + Just w -> return $ "#box" <> + parens ("width: " <> literal w <> ", " <> coreImage) + Nothing -> return $ "#" <> coreImage + (Just w, _) -> return $ "#box" <> + parens ("width: " <> literal w <> ", " <> coreImage) + (_, Just h) -> return $ "#box" <> + parens ("height: " <> literal h <> ", " <> coreImage) Note blocks -> do contents <- blocksToTypst blocks return $ "#footnote" <> brackets (chomp contents) diff --git a/test/writer.typst b/test/writer.typst index aa5400e570ba..edcc87cc8cca 100644 --- a/test/writer.typst +++ b/test/writer.typst @@ -779,13 +779,13 @@ or here: From "Voyage dans la Lune" by Georges Melies \(1902): -#figure([#image("lalune.jpg")], +#figure([#box(width: 150.0pt, image("lalune.jpg"))], caption: [ lalune ] ) -Here is a movie #image("movie.jpg") icon. +Here is a movie #box(width: 20.0pt, image("movie.jpg")) icon. #horizontalrule