git.iko.soy/typeable/pandoc
on master help sign in
Merge pull request #3464 from mb21/determine-svg-size
e51b32aMauro Bieg
src/Text/Pandoc/ImageSize.hs+49−18
@@ -39,6 +39,7 @@ module Text.Pandoc.ImageSize ( ImageType(..)
39 , Direction(..)
39 , Direction(..)
40 , dimension
40 , dimension
41 , inInch
41 , inInch
42+ , inPixel
42 , inPoints
43 , inPoints
43 , numUnit
44 , numUnit
44 , showInInch
45 , showInInch
@@ -58,6 +59,8 @@ import Data.Default (Default)
58import Numeric (showFFloat)
59import Numeric (showFFloat)
59import Text.Pandoc.Definition
60import Text.Pandoc.Definition
60import Text.Pandoc.Options
61import Text.Pandoc.Options
62+import qualified Text.Pandoc.UTF8 as UTF8
63+import qualified Text.XML.Light as Xml
61import qualified Data.Map as M
64import qualified Data.Map as M
62import Control.Monad.Except
65import Control.Monad.Except
63import Data.Maybe (fromMaybe)
66import Data.Maybe (fromMaybe)
@@ -65,7 +68,7 @@ import Data.Maybe (fromMaybe)
65-- quick and dirty functions to get image sizes
68-- quick and dirty functions to get image sizes
66-- algorithms borrowed from wwwis.pl
69-- algorithms borrowed from wwwis.pl
67
70
68−data ImageType = Png | Gif | Jpeg | Pdf | Eps deriving Show
71+data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps deriving Show
69data Direction = Width | Height
72data Direction = Width | Height
70instance Show Direction where
73instance Show Direction where
71 show Width = "width"
74 show Width = "width"
@@ -100,17 +103,25 @@ imageType img = case B.take 4 img of
100 "\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
103 "\xff\xd8\xff\xe0" -> return Jpeg -- JFIF
101 "\xff\xd8\xff\xe1" -> return Jpeg -- Exif
104 "\xff\xd8\xff\xe1" -> return Jpeg -- Exif
102 "%PDF" -> return Pdf
105 "%PDF" -> return Pdf
106+ "<svg" -> return Svg
107+ "<?xm"
108+ | "<svg " == (B.take 5 $ last $ B.groupBy openingTag $ B.drop 7 img)
109+ -> return Svg
103 "%!PS"
110 "%!PS"
104 | (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
111 | (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
105 -> return Eps
112 -> return Eps
106 _ -> mzero
113 _ -> mzero
114+ where
115+ -- B.groupBy openingTag matches first "<svg" or "<html" but not "<!--"
116+ openingTag x y = x == '<' && y /= '!'
107
117
108−imageSize :: ByteString -> Either String ImageSize
118+imageSize :: WriterOptions -> ByteString -> Either String ImageSize
109−imageSize img =
119+imageSize opts img =
110 case imageType img of
120 case imageType img of
111 Just Png -> mbToEither "could not determine PNG size" $ pngSize img
121 Just Png -> mbToEither "could not determine PNG size" $ pngSize img
112 Just Gif -> mbToEither "could not determine GIF size" $ gifSize img
122 Just Gif -> mbToEither "could not determine GIF size" $ gifSize img
113 Just Jpeg -> jpegSize img
123 Just Jpeg -> jpegSize img
124+ Just Svg -> mbToEither "could not determine SVG size" $ svgSize opts img
114 Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
125 Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
115 Just Pdf -> Left "could not determine PDF size" -- TODO
126 Just Pdf -> Left "could not determine PDF size" -- TODO
116 Nothing -> Left "could not determine image type"
127 Nothing -> Left "could not determine image type"
@@ -161,6 +172,16 @@ inInch opts dim =
161 (Inch a) -> a
172 (Inch a) -> a
162 (Percent _) -> 0
173 (Percent _) -> 0
163
174
175+inPixel :: WriterOptions -> Dimension -> Integer
176+inPixel opts dim =
177+ case dim of
178+ (Pixel a) -> a
179+ (Centimeter a) -> floor $ dpi * a * 0.3937007874 :: Integer
180+ (Inch a) -> floor $ dpi * a :: Integer
181+ _ -> 0
182+ where
183+ dpi = fromIntegral $ writerDpi opts
184+
164-- | Convert a Dimension to a String denoting its equivalent in inches, for example "2.00000".
185-- | Convert a Dimension to a String denoting its equivalent in inches, for example "2.00000".
165-- Note: Dimensions in percentages are converted to the empty string.
186-- Note: Dimensions in percentages are converted to the empty string.
166showInInch :: WriterOptions -> Dimension -> String
187showInInch :: WriterOptions -> Dimension -> String
@@ -170,14 +191,8 @@ showInInch opts dim = showFl $ inInch opts dim
170-- | Convert a Dimension to a String denoting its equivalent in pixels, for example "600".
191-- | Convert a Dimension to a String denoting its equivalent in pixels, for example "600".
171-- Note: Dimensions in percentages are converted to the empty string.
192-- Note: Dimensions in percentages are converted to the empty string.
172showInPixel :: WriterOptions -> Dimension -> String
193showInPixel :: WriterOptions -> Dimension -> String
173−showInPixel opts dim =
194+showInPixel _ (Percent _) = ""
174− case dim of
195+showInPixel opts dim = show $ inPixel opts dim
175− (Pixel a) -> show a
176− (Centimeter a) -> show (floor $ dpi * a * 0.3937007874 :: Int)
177− (Inch a) -> show (floor $ dpi * a :: Int)
178− (Percent _) -> ""
179− where
180− dpi = fromIntegral $ writerDpi opts
181
196
182-- | Maybe split a string into a leading number and trailing unit, e.g. "3cm" to Just (3.0, "cm")
197-- | Maybe split a string into a leading number and trailing unit, e.g. "3cm" to Just (3.0, "cm")
183numUnit :: String -> Maybe (Double, String)
198numUnit :: String -> Maybe (Double, String)
@@ -195,13 +210,11 @@ dimension dir (_, _, kvs) =
195 Width -> extractDim "width"
210 Width -> extractDim "width"
196 Height -> extractDim "height"
211 Height -> extractDim "height"
197 where
212 where
198− extractDim key =
213+ extractDim key = lookup key kvs >>= lengthToDim
199− case lookup key kvs of
214+
200− Just str ->
215+lengthToDim :: String -> Maybe Dimension
201− case numUnit str of
216+lengthToDim s = numUnit s >>= uncurry toDim
202− Just (num, unit) -> toDim num unit
217+ where
203− Nothing -> Nothing
204− Nothing -> Nothing
205 toDim a "cm" = Just $ Centimeter a
218 toDim a "cm" = Just $ Centimeter a
206 toDim a "mm" = Just $ Centimeter (a / 10)
219 toDim a "mm" = Just $ Centimeter (a / 10)
207 toDim a "in" = Just $ Inch a
220 toDim a "in" = Just $ Inch a
@@ -209,6 +222,8 @@ dimension dir (_, _, kvs) =
209 toDim a "%" = Just $ Percent a
222 toDim a "%" = Just $ Percent a
210 toDim a "px" = Just $ Pixel (floor a::Integer)
223 toDim a "px" = Just $ Pixel (floor a::Integer)
211 toDim a "" = Just $ Pixel (floor a::Integer)
224 toDim a "" = Just $ Pixel (floor a::Integer)
225+ toDim a "pt" = Just $ Inch (a / 72)
226+ toDim a "pc" = Just $ Inch (a / 6)
212 toDim _ _ = Nothing
227 toDim _ _ = Nothing
213
228
214epsSize :: ByteString -> Maybe ImageSize
229epsSize :: ByteString -> Maybe ImageSize
@@ -271,6 +286,22 @@ gifSize img = do
271 }
286 }
272 _ -> Nothing -- "GIF parse error"
287 _ -> Nothing -- "GIF parse error"
273
288
289+svgSize :: WriterOptions -> ByteString -> Maybe ImageSize
290+svgSize opts img = do
291+ doc <- Xml.parseXMLDoc $ UTF8.toString img
292+ let dpi = fromIntegral $ writerDpi opts
293+ let dirToInt dir = do
294+ dim <- Xml.findAttrBy (== Xml.QName dir Nothing Nothing) doc >>= lengthToDim
295+ return $ inPixel opts dim
296+ w <- dirToInt "width"
297+ h <- dirToInt "height"
298+ return ImageSize {
299+ pxX = w
300+ , pxY = h
301+ , dpiX = dpi
302+ , dpiY = dpi
303+ }
304+
274jpegSize :: ByteString -> Either String ImageSize
305jpegSize :: ByteString -> Either String ImageSize
275jpegSize img =
306jpegSize img =
276 let (hdr, rest) = B.splitAt 4 img
307 let (hdr, rest) = B.splitAt 4 img
src/Text/Pandoc/Writers/Docx.hs+2−1
@@ -1184,7 +1184,7 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do
1184 Right (img, mt) -> do
1184 Right (img, mt) -> do
1185 ident <- ("rId"++) `fmap` ((lift . lift) getUniqueId)
1185 ident <- ("rId"++) `fmap` ((lift . lift) getUniqueId)
1186 let (xpt,ypt) = desiredSizeInPoints opts attr
1186 let (xpt,ypt) = desiredSizeInPoints opts attr
1187− (either (const def) id (imageSize img))
1187+ (either (const def) id (imageSize opts img))
1188 -- 12700 emu = 1 pt
1188 -- 12700 emu = 1 pt
1189 let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700) (pageWidth * 12700)
1189 let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700) (pageWidth * 12700)
1190 let cNvPicPr = mknode "pic:cNvPicPr" [] $
1190 let cNvPicPr = mknode "pic:cNvPicPr" [] $
@@ -1228,6 +1228,7 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do
1228 Just Gif -> ".gif"
1228 Just Gif -> ".gif"
1229 Just Pdf -> ".pdf"
1229 Just Pdf -> ".pdf"
1230 Just Eps -> ".eps"
1230 Just Eps -> ".eps"
1231+ Just Svg -> ".svg"
1231 Nothing -> ""
1232 Nothing -> ""
1232 if null imgext
1233 if null imgext
1233 then -- without an extension there is no rule for content type
1234 then -- without an extension there is no rule for content type
src/Text/Pandoc/Writers/ICML.hs+1−1
@@ -546,7 +546,7 @@ imageICML opts style attr (src, _) = do
546 report $ CouldNotFetchResource src ""
546 report $ CouldNotFetchResource src ""
547 return def
547 return def
548 Right (img, _) -> do
548 Right (img, _) -> do
549− case imageSize img of
549+ case imageSize opts img of
550 Right size -> return size
550 Right size -> return size
551 Left msg -> do
551 Left msg -> do
552 report $ CouldNotDetermineImageSize src msg
552 report $ CouldNotDetermineImageSize src msg
src/Text/Pandoc/Writers/ODT.hs+1−1
@@ -153,7 +153,7 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = do
153 report $ CouldNotFetchResource src ""
153 report $ CouldNotFetchResource src ""
154 return $ Emph lab
154 return $ Emph lab
155 Right (img, mbMimeType) -> do
155 Right (img, mbMimeType) -> do
156− (ptX, ptY) <- case imageSize img of
156+ (ptX, ptY) <- case imageSize opts img of
157 Right s -> return $ sizeInPoints s
157 Right s -> return $ sizeInPoints s
158 Left msg -> do
158 Left msg -> do
159 report $ CouldNotDetermineImageSize src msg
159 report $ CouldNotDetermineImageSize src msg
src/Text/Pandoc/Writers/RTF.hs+1−1
@@ -63,7 +63,7 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = do
63 "image/jpeg" -> return "\\jpegblip"
63 "image/jpeg" -> return "\\jpegblip"
64 "image/png" -> return "\\pngblip"
64 "image/png" -> return "\\pngblip"
65 _ -> throwError $ PandocSomeError "Unknown file type"
65 _ -> throwError $ PandocSomeError "Unknown file type"
66− sizeSpec <- case imageSize imgdata of
66+ sizeSpec <- case imageSize opts imgdata of
67 Left msg -> do
67 Left msg -> do
68 report $ CouldNotDetermineImageSize src msg
68 report $ CouldNotDetermineImageSize src msg
69 return ""
69 return ""