Skip to content

Commit

Permalink
fix(docx): use proper DPI for svg to fallback png conversions
Browse files Browse the repository at this point in the history
DPI only works when the desired size is known, otherwise rsvg-convert
will use the SVG's viewbox to guess the size in pixels.
That size is often very small, resulting in a very bad quality fallback
PNG.

Signed-off-by: Edwin Török <edwin@etorok.net>
  • Loading branch information
edwintorok committed Dec 26, 2023
1 parent b2388be commit 09a959d
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 9 deletions.
16 changes: 9 additions & 7 deletions src/Text/Pandoc/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import System.IO (nativeNewline, stdout)
import qualified System.IO as IO (Newline (..))
import Text.Pandoc
import Text.Pandoc.Builder (setMeta)
import Text.Pandoc.MediaBag (mediaItems)
import Text.Pandoc.MediaBag (mediaItems')
import Text.Pandoc.Image (svgToPng)
import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts,
IpynbOutput (..), OptInfo(..))
Expand All @@ -73,6 +73,7 @@ import qualified Text.Pandoc.UTF8 as UTF8
#ifndef _WINDOWS
import System.Posix.IO (stdOutput)
import System.Posix.Terminal (queryTerminal)
import Text.Pandoc.ImageSize (desiredSizeInPoints, imageSize)
#endif

convertWithOpts :: ScriptingEngine -> Opt -> IO ()
Expand Down Expand Up @@ -308,7 +309,7 @@ convertWithOpts' scriptingEngine istty datadir opts = do
)

when (format == "docx" && not (optSandbox opts)) $ do
createPngFallbacks (writerDpi writerOptions)
createPngFallbacks writerOptions

output <- case writer of
ByteStringWriter f
Expand Down Expand Up @@ -372,14 +373,15 @@ readAbbreviations mbfilepath =
>>= fmap (Set.fromList . filter (not . T.null) . T.lines) .
toTextM (fromMaybe mempty mbfilepath)

createPngFallbacks :: (PandocMonad m, MonadIO m) => Int -> m ()
createPngFallbacks dpi = do
createPngFallbacks :: (PandocMonad m, MonadIO m) => WriterOptions -> m ()
createPngFallbacks opts = do
-- create fallback pngs for svgs
items <- mediaItems <$> getMediaBag
forM_ items $ \(fp, mt, bs) ->
items <- mediaItems' <$> getMediaBag
forM_ items $ \(fp, mt, bs, attr) ->
case T.takeWhile (/=';') mt of
"image/svg+xml" -> do
res <- svgToPng dpi bs
let dims = either (const Nothing) (Just . desiredSizeInPoints opts attr) (imageSize opts $ BL.toStrict bs)
res <- svgToPng dims (writerDpi opts) bs
case res of
Right bs' -> do
let fp' = fp <> ".png"
Expand Down
9 changes: 7 additions & 2 deletions src/Text/Pandoc/Image.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@ import qualified Control.Exception as E
import Control.Monad.IO.Class (MonadIO(liftIO))
import Text.Pandoc.Class.PandocMonad
import qualified Data.Text as T
import Text.Printf (printf)

-- | Convert svg image to png. rsvg-convert
-- is used and must be available on the path.
svgToPng :: (PandocMonad m, MonadIO m)
=> Int -- ^ DPI
=> Maybe (Double, Double) -- Width and Height in points
-> Int -- ^ DPI
-> L.ByteString -- ^ Input image as bytestring
-> m (Either Text L.ByteString)
svgToPng dpi bs = do
svgToPng dims dpi bs = do
let dpi' = show dpi
let args = ["-f","png","-a","--dpi-x",dpi',"--dpi-y",dpi']
++ maybe [] (\(xpt, ypt) ->
["--width", printf "%.6fpt" xpt, "--height", printf "%.6fpt" ypt])
dims
trace (T.intercalate " " $ map T.pack $ "rsvg-convert" : args)
liftIO $ E.catch
(do (exit, out) <- pipeProcess Nothing "rsvg-convert"
Expand Down

0 comments on commit 09a959d

Please sign in to comment.