git.iko.soy/typeable/pandoc
on master help sign in
Merge pull request #1468 from jkr/mediabag

Mediabag

commitb12d2ea20a8b914ed2d6ee111eee5a25ad989597 authorJohn MacFarlane <jgm@berkeley.edu> dateWed 30 Jul 2014, 10:55 (12 years ago) parent02c79eaf733b50
7 files changed+49−43
pandoc.hs+2−1 src/Text/Pandoc.hs+3−3 src/Text/Pandoc/Readers/Docx.hs+25−32 src/Text/Pandoc/Readers/Docx/Parse.hs+5−5 src/Text/Pandoc/Shared.hs+11 tests/Tests/Readers/Docx.hs+2−1 tests/docx.image_no_embed.native+1−1
pandoc.hs+2−1
@@ -1201,7 +1201,8 @@ main = do
12011201 readSources sources >>=
12021202 handleIncludes' . convertTabs . intercalate "\n" >>=
12031203 r readerOpts
1204− ByteStringReader r -> readFiles sources >>= r readerOpts
1204+ ByteStringReader r -> readFiles sources >>= r readerOpts >>=
1205+ (return . fst)
12051206
12061207
12071208 let doc0 = M.foldWithKey setMeta doc metadata
src/Text/Pandoc.hs+3−3
@@ -160,7 +160,7 @@ import Text.Pandoc.Writers.Haddock
160160import Text.Pandoc.Writers.Custom
161161import Text.Pandoc.Templates
162162import Text.Pandoc.Options
163−import Text.Pandoc.Shared (safeRead, warn)
163+import Text.Pandoc.Shared (safeRead, warn, MediaBag)
164164import Data.Aeson
165165import qualified Data.ByteString.Lazy as BL
166166import Data.List (intercalate)
@@ -204,12 +204,12 @@ markdown o s = do
204204 return doc
205205
206206data Reader = StringReader (ReaderOptions -> String -> IO Pandoc)
207− | ByteStringReader (ReaderOptions -> BL.ByteString -> IO Pandoc)
207+ | ByteStringReader (ReaderOptions -> BL.ByteString -> IO (Pandoc, MediaBag))
208208
209209mkStringReader :: (ReaderOptions -> String -> Pandoc) -> Reader
210210mkStringReader r = StringReader (\o s -> return $ r o s)
211211
212−mkBSReader :: (ReaderOptions -> BL.ByteString -> Pandoc) -> Reader
212+mkBSReader :: (ReaderOptions -> BL.ByteString -> (Pandoc, MediaBag)) -> Reader
213213mkBSReader r = ByteStringReader (\o s -> return $ r o s)
214214
215215-- | Association list of formats and readers.
src/Text/Pandoc/Readers/Docx.hs+25−32
@@ -78,8 +78,6 @@ import Codec.Archive.Zip
7878import Text.Pandoc.Definition
7979import Text.Pandoc.Options
8080import Text.Pandoc.Builder (text, toList)
81−import Text.Pandoc.MIME (getMimeType)
82−import Text.Pandoc.UTF8 (toString)
8381import Text.Pandoc.Walk
8482import Text.Pandoc.Readers.Docx.Parse
8583import Text.Pandoc.Readers.Docx.Lists
@@ -88,9 +86,7 @@ import Text.Pandoc.Readers.Docx.TexChar
8886import Text.Pandoc.Shared
8987import Data.Maybe (mapMaybe, fromMaybe)
9088import Data.List (delete, isPrefixOf, (\\), intercalate, intersect)
91−import qualified Data.ByteString as BS
9289import qualified Data.ByteString.Lazy as B
93−import Data.ByteString.Base64 (encode)
9490import qualified Data.Map as M
9591import Control.Monad.Reader
9692import Control.Monad.State
@@ -98,17 +94,24 @@ import Text.Printf (printf)
9894
9995readDocx :: ReaderOptions
10096 -> B.ByteString
101− -> Pandoc
97+ -> (Pandoc, MediaBag)
10298readDocx opts bytes =
10399 case archiveToDocx (toArchive bytes) of
104− Right docx -> Pandoc meta blks where
105− (meta, blks) = (docxToMetaAndBlocks opts docx)
100+ Right docx -> (Pandoc meta blks, mediaBag) where
101+ (meta, blks, mediaBag) = (docxToOutput opts docx)
106102 Left _ -> error $ "couldn't parse docx file"
107103
108104data DState = DState { docxAnchorMap :: M.Map String String
105+ , docxMediaBag :: MediaBag
109106 , docxInHeaderBlock :: Bool
110107 , docxInTexSubscript :: Bool }
111108
109+defaultDState :: DState
110+defaultDState = DState { docxAnchorMap = M.empty
111+ , docxMediaBag = M.empty
112+ , docxInHeaderBlock = False
113+ , docxInTexSubscript = False}
114+
112115data DEnv = DEnv { docxOptions :: ReaderOptions
113116 , docxDocument :: Docx}
114117
@@ -319,13 +322,6 @@ runToInlines (Footnote bps) =
319322runToInlines (Endnote bps) =
320323 concatMapM bodyPartToBlocks bps >>= (\blks -> return [Note blks])
321324
322−makeDataUrl :: String -> B.ByteString -> Maybe String
323−makeDataUrl fp bs =
324− case getMimeType fp of
325− Just mime -> Just $ "data:" ++ mime ++ ";base64," ++
326− toString (encode $ BS.concat $ B.toChunks bs)
327− Nothing -> Nothing
328−
329325parPartToInlines :: ParPart -> DocxContext [Inline]
330326parPartToInlines (PlainRun r) = runToInlines r
331327parPartToInlines (Insertion _ author date runs) = do
@@ -372,11 +368,9 @@ parPartToInlines (BookMark _ anchor) =
372368 modify $ \s -> s { docxAnchorMap = M.insert anchor newAnchor anchorMap}
373369 return [Span (newAnchor, ["anchor"], []) []]
374370parPartToInlines (Drawing fp bs) = do
375− return $ case True of -- TODO: add self-contained images
376− True -> [Image [] (fp, "")]
377− False -> case makeDataUrl fp bs of
378− Just d -> [Image [] (d, "")]
379− Nothing -> [Image [] ("", "")]
371+ mediaBag <- gets docxMediaBag
372+ modify $ \s -> s { docxMediaBag = M.insert fp bs mediaBag}
373+ return [Image [] (fp, "")]
380374parPartToInlines (InternalHyperLink anchor runs) = do
381375 ils <- concatMapM runToInlines runs
382376 return [Link ils ('#' : anchor, "")]
@@ -675,26 +669,25 @@ rewriteLink l@(Link ils ('#':target, title)) = do
675669 Nothing -> l
676670rewriteLink il = return il
677671
678−bodyToMetaAndBlocks :: Body -> DocxContext (Meta, [Block])
679−bodyToMetaAndBlocks (Body bps) = do
672+bodyToOutput :: Body -> DocxContext (Meta, [Block], MediaBag)
673+bodyToOutput (Body bps) = do
680674 let (metabps, blkbps) = sepBodyParts bps
681675 meta <- bodyPartsToMeta metabps
682676 blks <- concatMapM bodyPartToBlocks blkbps >>=
683677 walkM rewriteLink
684− return $
685− (meta,
686− blocksToDefinitions $
687− blocksToBullets $ blks)
688−
689−docxToMetaAndBlocks :: ReaderOptions -> Docx -> (Meta, [Block])
690−docxToMetaAndBlocks opts d@(Docx (Document _ body)) =
691− let dState = DState { docxAnchorMap = M.empty
692− , docxInHeaderBlock = False
693− , docxInTexSubscript = False}
678+ mediaBag <- gets docxMediaBag
679+ return $ (meta,
680+ blocksToDefinitions $ blocksToBullets $ blks,
681+ mediaBag)
682+
683+docxToOutput :: ReaderOptions -> Docx -> (Meta, [Block], MediaBag)
684+docxToOutput opts d@(Docx (Document _ body)) =
685+ let dState = defaultDState
694686 dEnv = DEnv { docxOptions = opts
695687 , docxDocument = d}
696688 in
697− evalDocxContext (bodyToMetaAndBlocks body) dEnv dState
689+ evalDocxContext (bodyToOutput body) dEnv dState
690+
698691
699692ilToCode :: Inline -> String
700693ilToCode (Str s) = s
src/Text/Pandoc/Readers/Docx/Parse.hs+5−5
@@ -779,11 +779,11 @@ expandDrawingId :: String -> D ParPart
779779expandDrawingId s = do
780780 target <- asks (lookupRelationship s . envRelationships)
781781 case target of
782− Just t -> do let filepath = combine "word" t
783− bytes <- asks (lookup filepath . envMedia)
784− case bytes of
785− Just bs -> return $ Drawing filepath bs
786− Nothing -> throwError DocxError
782+ Just filepath -> do
783+ bytes <- asks (lookup (combine "word" filepath) . envMedia)
784+ case bytes of
785+ Just bs -> return $ Drawing filepath bs
786+ Nothing -> throwError DocxError
787787 Nothing -> throwError DocxError
788788
789789elemToParPart :: NameSpaces -> Element -> D ParPart
src/Text/Pandoc/Shared.hs+11
@@ -48,6 +48,8 @@ module Text.Pandoc.Shared (
4848 toRomanNumeral,
4949 escapeURI,
5050 tabFilter,
51+ -- * Media Handling
52+ MediaBag,
5153 -- * Date/time
5254 normalizeDate,
5355 -- * Pandoc block and inline list processing
@@ -114,6 +116,7 @@ import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
114116 renderOptions)
115117import qualified Data.ByteString as BS
116118import qualified Data.ByteString.Char8 as B8
119+import qualified Data.ByteString.Lazy as BL
117120import Text.Pandoc.Compat.Monoid
118121import Data.ByteString.Base64 (decodeLenient)
119122import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
@@ -280,6 +283,14 @@ tabFilter tabStop =
280283 x : go (spsToNextStop - 1) xs
281284 in go tabStop
282285
286+---
287+--- Media handling
288+---
289+
290+-- | A map of media paths to their binary representations.
291+
292+type MediaBag = M.Map String BL.ByteString
293+
283294--
284295-- Date/time
285296--
tests/Tests/Readers/Docx.hs+2−1
@@ -37,7 +37,8 @@ compareOutput :: ReaderOptions
3737compareOutput opts docxFile nativeFile = do
3838 df <- B.readFile docxFile
3939 nf <- Prelude.readFile nativeFile
40− return $ (noNorm (readDocx opts df), noNorm (readNative nf))
40+ let (p, _) = readDocx opts df
41+ return $ (noNorm p, noNorm (readNative nf))
4142
4243testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO Test
4344testCompareWithOptsIO opts name docxFile nativeFile = do
tests/docx.image_no_embed.native+1−1
@@ -1,2 +1,2 @@
11[Header 2 ("an-image",[],[]) [Str "An",Space,Str "image"]
2−,Para [Image [] ("word/media/image1.jpeg","")]]
2+,Para [Image [] ("media/image1.jpeg","")]]