Skip to content

Commit

Permalink
Adjust the size of rotated/flipped images in docx
Browse files Browse the repository at this point in the history
The desired size of the final image in the docx output wants to be based
on the rotated dimensions, not the original dimensions, so we flip stuff
around a little.
  • Loading branch information
silby committed Nov 20, 2024
1 parent bddba0b commit 868ccd8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 16 deletions.
21 changes: 19 additions & 2 deletions src/Text/Pandoc/ImageSize.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Text.Pandoc.ImageSize ( ImageType(..)
, sizeInPixels
, sizeInPoints
, desiredSizeInPoints
, rotatedDesiredSizeInPoints
, Dimension(..)
, Direction(..)
, Flip(..)
Expand Down Expand Up @@ -194,13 +195,29 @@ sizeInPoints s = (pxXf * 72 / dpiXf, pxYf * 72 / dpiYf)
-- are specified in the attribute (or only dimensions in percentages).
desiredSizeInPoints :: WriterOptions -> Attr -> ImageSize -> (Double, Double)
desiredSizeInPoints opts attr s =
desiredSizeInPoints' opts attr s ratio
where
ratio = fromIntegral (pxX s) / fromIntegral (pxY s)

-- | As desiredSizeInPoints, but swapping the width and height dimensions if
-- the indicated rotation is a quarter-turn or three-quarter-turn.
rotatedDesiredSizeInPoints :: WriterOptions -> Attr -> ImageSize -> Rotate -> (Double, Double)
rotatedDesiredSizeInPoints opts attr s r =
desiredSizeInPoints' opts attr s (ratio r)
where
ratio R0 = fromIntegral (pxX s) / fromIntegral (pxY s)
ratio R180 = fromIntegral (pxX s) / fromIntegral (pxY s)
ratio R90 = fromIntegral (pxY s) / fromIntegral (pxX s)
ratio R270 = fromIntegral (pxY s) / fromIntegral (pxX s)

desiredSizeInPoints' :: WriterOptions -> Attr -> ImageSize -> Double -> (Double, Double)
desiredSizeInPoints' opts attr s ratio =
case (getDim Width, getDim Height) of
(Just w, Just h) -> (w, h)
(Just w, Nothing) -> (w, w / ratio)
(Nothing, Just h) -> (h * ratio, h)
(Nothing, Just h) -> (h * ratio , h)
(Nothing, Nothing) -> sizeInPoints s
where
ratio = fromIntegral (pxX s) / fromIntegral (pxY s)
getDim dir = case dimension dir attr of
Just (Percent _) -> Nothing
Just dim -> Just $ inPoints opts dim
Expand Down
38 changes: 24 additions & 14 deletions src/Text/Pandoc/Writers/Docx/OpenXML.hs
Original file line number Diff line number Diff line change
Expand Up @@ -941,13 +941,24 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
[extLst])
_ -> return ([("r:embed", T.pack ident)], [])
let
(xpt,ypt) = desiredSizeInPoints opts attr
(either (const def) id (imageSize opts img))
transform = imageTransform img
(xpt,ypt) = rotatedDesiredSizeInPoints opts attr
(either (const def) id (imageSize opts img)) (tRotate transform)
-- 12700 emu = 1 pt
pageWidthPt = case dimension Width attr of
Just (Percent a) -> pageWidth * floor (a * 127)
_ -> pageWidth * 12700
(xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700) pageWidthPt
height = case tRotate transform of
R0 -> tshow xemu
R90 -> tshow yemu
R180 -> tshow xemu
R270 -> tshow yemu
width = case tRotate transform of
R0 -> tshow yemu
R90 -> tshow xemu
R180 -> tshow yemu
R270 -> tshow xemu
cNvPicPr = mknode "pic:cNvPicPr" [] $
mknode "a:picLocks" [("noChangeArrowheads","1")
,("noChangeAspect","1")] ()
Expand All @@ -962,20 +973,19 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
, mknode "a:stretch" [] $
mknode "a:fillRect" [] ()
]
transform = imageTransform img
attrflip NoFlip = []
attrflip FlipH = [("flipH", "1")]
attrflip FlipV = [("flipV", "1")]
xfrmFlip NoFlip = []
xfrmFlip FlipH = [("flipH", "1")]
xfrmFlip FlipV = [("flipV", "1")]
-- 60,000ths of a degree
rotate R0 = []
rotate R90 = [("rot", "5400000")]
rotate R180 = [("rot", "10800000")]
rotate R270 = [("rot", "16200000")]
xfrmRot R0 = []
xfrmRot R90 = [("rot", "5400000")]
xfrmRot R180 = [("rot", "10800000")]
xfrmRot R270 = [("rot", "16200000")]

xfrm = mknode "a:xfrm" ((attrflip (tFlip transform)) <> (rotate (tRotate transform)))
xfrm = mknode "a:xfrm" ((xfrmFlip (tFlip transform)) <> (xfrmRot (tRotate transform)))
[ mknode "a:off" [("x","0"),("y","0")] ()
, mknode "a:ext" [("cx",tshow xemu)
,("cy",tshow yemu)] () ]
, mknode "a:ext" [("cx",height)
,("cy",width)] () ]
prstGeom = mknode "a:prstGeom" [("prst","rect")] $
mknode "a:avLst" [] ()
ln = mknode "a:ln" [("w","9525")]
Expand All @@ -996,7 +1006,7 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do
imgElt = mknode "w:r" [] $
mknode "w:drawing" [] $
mknode "wp:inline" []
[ mknode "wp:extent" [("cx",tshow xemu),("cy",tshow yemu)] ()
[ mknode "wp:extent" [("cx",height),("cy",width)] ()
, mknode "wp:effectExtent"
[("b","0"),("l","0"),("r","0"),("t","0")] ()
, mknode "wp:docPr"
Expand Down

0 comments on commit 868ccd8

Please sign in to comment.