@@ -42,6 +42,7 @@ module Text.Pandoc.Readers.Odt.ContentReader
42import Control.Arrow
42import Control.Arrow
43import Control.Applicative hiding ( liftA, liftA2, liftA3 )
43import Control.Applicative hiding ( liftA, liftA2, liftA3 )
45+import qualified Data.ByteString.Lazy as B
45import qualified Data.Map as M
46import qualified Data.Map as M
46import Data.List ( find )
47import Data.List ( find )
47import Data.Maybe
48import Data.Maybe
@@ -50,6 +51,7 @@ import qualified Text.XML.Light as XML
51import Text.Pandoc.Definition
52import Text.Pandoc.Definition
52import Text.Pandoc.Builder
53import Text.Pandoc.Builder
54+import Text.Pandoc.MediaBag (insertMedia, MediaBag)
53import Text.Pandoc.Shared
55import Text.Pandoc.Shared
55import Text.Pandoc.Readers.Odt.Base
57import Text.Pandoc.Readers.Odt.Base
@@ -68,6 +70,7 @@ import qualified Data.Set as Set
68--------------------------------------------------------------------------------
70--------------------------------------------------------------------------------
70type Anchor = String
72type Anchor = String
73+type Media = [(FilePath, B.ByteString)]
72data ReaderState
75data ReaderState
73 = ReaderState { -- | A collection of styles read somewhere else.
76 = ReaderState { -- | A collection of styles read somewhere else.
@@ -87,14 +90,17 @@ data ReaderState
87 -- | A map from internal anchor names to "pretty" ones.
90 -- | A map from internal anchor names to "pretty" ones.
88 -- The mapping is a purely cosmetic one.
91 -- The mapping is a purely cosmetic one.
89 , bookmarkAnchors :: M.Map Anchor Anchor
92 , bookmarkAnchors :: M.Map Anchor Anchor
90−
93+ -- | A map of files / binary data from the archive
95+ -- | Hold binary resources used in the document
96+ , odtMediaBag :: MediaBag
91-- , sequences
97-- , sequences
92-- , trackedChangeIDs
98-- , trackedChangeIDs
94 deriving ( Show )
100 deriving ( Show )
96−readerState :: Styles -> ReaderState
102+readerState :: Styles -> Media -> ReaderState
97−readerState styles = ReaderState styles [] 0 Nothing M.empty
103+readerState styles media = ReaderState styles [] 0 Nothing M.empty media mempty
100pushStyle' :: Style -> ReaderState -> ReaderState
106pushStyle' :: Style -> ReaderState -> ReaderState
@@ -134,6 +140,16 @@ putPrettyAnchor ugly pretty state@ReaderState{..}
134usedAnchors :: ReaderState -> [Anchor]
140usedAnchors :: ReaderState -> [Anchor]
135usedAnchors ReaderState{..} = M.elems bookmarkAnchors
141usedAnchors ReaderState{..} = M.elems bookmarkAnchors
143+getMediaBag :: ReaderState -> MediaBag
144+getMediaBag ReaderState{..} = odtMediaBag
146+getMediaEnv :: ReaderState -> Media
147+getMediaEnv ReaderState{..} = envMedia
149+insertMedia' :: (FilePath, B.ByteString) -> ReaderState -> ReaderState
150+insertMedia' (fp, bs) state@ReaderState{..}
151+ = state { odtMediaBag = insertMedia fp Nothing bs odtMediaBag }
137--------------------------------------------------------------------------------
153--------------------------------------------------------------------------------
138-- Reader type and associated tools
154-- Reader type and associated tools
139--------------------------------------------------------------------------------
155--------------------------------------------------------------------------------
@@ -190,6 +206,22 @@ popStyle = keepingTheValue (
190getCurrentListLevel :: OdtReaderSafe _x ListLevel
206getCurrentListLevel :: OdtReaderSafe _x ListLevel
191getCurrentListLevel = getExtraState >>^ currentListLevel
207getCurrentListLevel = getExtraState >>^ currentListLevel
210+updateMediaWithResource :: OdtReaderSafe (FilePath, B.ByteString) (FilePath, B.ByteString)
211+updateMediaWithResource = keepingTheValue (
212+ (keepingTheValue getExtraState
219+lookupResource :: OdtReaderSafe String (FilePath, B.ByteString)
220+lookupResource = proc target -> do
221+ state <- getExtraState -< ()
222+ case lookup target (getMediaEnv state) of
223+ Just bs -> returnV (target, bs) -<< ()
224+ Nothing -> returnV ("", B.empty) -< ()
194type AnchorPrefix = String
226type AnchorPrefix = String
@@ -511,6 +543,10 @@ read_plain_text = fst ^&&& read_plain_text' >>% recover
511 extractText (XML.Text cData) = succeedWith (XML.cdData cData)
543 extractText (XML.Text cData) = succeedWith (XML.cdData cData)
512 extractText _ = failEmpty
544 extractText _ = failEmpty
546+read_text_seq :: InlineMatcher
547+read_text_seq = matchingElement NsText "sequence"
548+ $ matchChildContent [] read_plain_text
515-- specifically. I honor that, although the current implementation of '(<>)'
551-- specifically. I honor that, although the current implementation of '(<>)'
516-- for 'Inlines' in "Text.Pandoc.Builder" will collaps them agein.
552-- for 'Inlines' in "Text.Pandoc.Builder" will collaps them agein.
@@ -559,6 +595,8 @@ read_paragraph = matchingElement NsText "p"
559 , read_reference_start
595 , read_reference_start
560 , read_bookmark_ref
596 , read_bookmark_ref
561 , read_reference_ref
597 , read_reference_ref
598+ , read_maybe_nested_img_frame
562 ] read_plain_text
600 ] read_plain_text
@@ -583,6 +621,7 @@ read_header = matchingElement NsText "h"
583 , read_reference_start
621 , read_reference_start
584 , read_bookmark_ref
622 , read_bookmark_ref
585 , read_reference_ref
623 , read_reference_ref
624+ , read_maybe_nested_img_frame
586 ] read_plain_text
625 ] read_plain_text
587 ) -< blocks
626 ) -< blocks
588 anchor <- getHeaderAnchor -< children
627 anchor <- getHeaderAnchor -< children
@@ -687,6 +726,64 @@ read_table_cell = matchingElement NsTable "table-cell"
687 $ matchChildContent' [ read_paragraph
726 $ matchChildContent' [ read_paragraph
729+----------------------
731+----------------------
734+read_maybe_nested_img_frame :: InlineMatcher
735+read_maybe_nested_img_frame = matchingElement NsDraw "frame"
737+ img <- (findChild' NsDraw "image") -< ()
739+ Just _ -> read_frame -< blocks
740+ Nothing -> matchChildContent' [ read_frame_text_box ] -< blocks
742+read_frame :: OdtReaderSafe Inlines Inlines
745+ w <- ( findAttr' NsSVG "width" ) -< ()
746+ h <- ( findAttr' NsSVG "height" ) -< ()
747+ titleNodes <- ( matchChildContent' [ read_frame_title ] ) -< blocks
748+ src <- matchChildContent' [ read_image_src ] -< blocks
749+ resource <- lookupResource -< src
750+ _ <- updateMediaWithResource -< resource
751+ alt <- (matchChildContent [] read_plain_text) -< blocks
752+ arr (uncurry4 imageWith ) -<
753+ (image_attributes w h, src, inlineListToIdentifier (toList titleNodes), alt)
755+image_attributes :: Maybe String -> Maybe String -> Attr
756+image_attributes x y =
757+ ( "", [], (dim "width" x) ++ (dim "height" y))
759+ dim _ (Just "") = []
760+ dim name (Just v) = [(name, v)]
763+read_image_src :: (Namespace, ElementName, OdtReader Anchor Anchor)
764+read_image_src = matchingElement NsDraw "image"
766+ imgSrc <- findAttr NsXLink "href" -< ()
768+ Right src -> returnV src -<< ()
769+ Left _ -> returnV "" -< ()
771+read_frame_title :: InlineMatcher
772+read_frame_title = matchingElement NsSVG "title"
773+ $ (matchChildContent [] read_plain_text)
775+read_frame_text_box :: InlineMatcher
776+read_frame_text_box = matchingElement NsDraw "text-box"
778+ paragraphs <- (matchChildContent' [ read_paragraph ]) -< blocks
779+ arr read_img_with_caption -< toList paragraphs
781+read_img_with_caption :: [Block] -> Inlines
782+read_img_with_caption ((Para ((Image attr _ target) : txt)) : _) =
783+ singleton (Image attr txt target) -- override caption with the text that follows
784+read_img_with_caption _ =
690----------------------
787----------------------
691-- Internal links
788-- Internal links
692----------------------
789----------------------
@@ -783,8 +880,11 @@ read_text = matchChildContent' [ read_header
786−read_body :: OdtReader _x Pandoc
883+read_body :: OdtReader _x (Pandoc, MediaBag)
787read_body = executeIn NsOffice "body"
884read_body = executeIn NsOffice "body"
788 $ executeIn NsOffice "text"
885 $ executeIn NsOffice "text"
789− $ liftAsSuccess read_text
886+ $ liftAsSuccess
790−
887+ $ proc inlines -> do
888+ txt <- read_text -< inlines
889+ state <- getExtraState -< ()
890+ returnA -< (txt, getMediaBag state)