pdf-toolbox-content 0.0.3.1 → 0.0.3.2
raw patch · 4 files changed
+73/−37 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- changelog.md +4/−0
- lib/Pdf/Toolbox/Content/Processor.hs +5/−0
- lib/Pdf/Toolbox/Content/UnicodeCMap.hs +62/−35
- pdf-toolbox-content.cabal +2/−2
changelog.md view
@@ -1,3 +1,7 @@+0.0.3.2++* support array ranges in unicode cmap (#15)+* support Op\_apostrophe content operator (#16) 0.0.3.1
lib/Pdf/Toolbox/Content/Processor.hs view
@@ -269,6 +269,11 @@ } processOp (Op_Tw, args) _ = left $ UnexpectedError $ "Op_Tw: wrong number of agruments:" ++ show args +processOp (Op_apostrophe, [o]) p = do+ p' <- processOp (Op_T_star, []) p+ processOp (Op_Tj, [o]) p'+processOp (Op_apostrophe, args) _ = left $ UnexpectedError $ "Op_apostrophe: wrong number of agruments:" ++ show args+ processOp _ p = return p ensureInTextObject :: Monad m => Bool -> Processor -> PdfE m ()
lib/Pdf/Toolbox/Content/UnicodeCMap.hs view
@@ -11,6 +11,8 @@ ) where +import Data.Monoid+import Data.Functor import Data.Char import Data.Map (Map) import qualified Data.Map as Map@@ -39,9 +41,9 @@ parseUnicodeCMap :: ByteString -> Either String UnicodeCMap parseUnicodeCMap cmap = case (codeRanges, chars, ranges) of- (Right cr, Right cs, Right rs) -> Right $ UnicodeCMap {+ (Right cr, Right cs, Right (rs, crs)) -> Right $ UnicodeCMap { unicodeCMapCodeRanges = cr,- unicodeCMapChars = cs,+ unicodeCMapChars = cs <> crs, unicodeCMapRanges = rs } (Left err, _, _) -> Left $ "CMap code ranges: " ++ err@@ -67,7 +69,9 @@ inRange glyph (start, end) = glyph >= start && glyph <= end toCode :: ByteString -> Int-toCode bs = fst $ BS.foldr (\b (sm, i) -> (sm + fromIntegral b * i, i * 255)) (0, 1) bs+toCode bs = fst $ BS.foldr (\b (sm, i) ->+ (sm + fromIntegral b * i, i * 255)) (0, 1) bs+ -- | Convert glyph to text -- -- Note: one glyph can represent more then one char, e.g. for ligatures@@ -77,7 +81,8 @@ Just txt -> Just txt Nothing -> case filter inRange (unicodeCMapRanges cmap) of- [(start, _, char)] -> Just (Text.singleton $ toEnum $ (fromEnum char) + (glyph - start))+ [(start, _, char)] -> Just (Text.singleton $ toEnum+ $ (fromEnum char) + (glyph - start)) _ -> Nothing where inRange (start, end, _) = glyph >= start && glyph <= end@@ -92,59 +97,77 @@ chars <- replicateM n $ do P.skipSpace- _ <- P.char '<'- i <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'+ i <- parseHex P.skipSpace- _ <- P.char '<'- j <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'+ j <- parseHex return (toCode i, Text.decodeUtf16BE j) return $ Map.fromList chars -rangesParser :: Parser [(Int, Int, Char)]+-- | It returns regular ranges and char map+--+-- Array ranges are converted to char map+rangesParser :: Parser ([(Int, Int, Char)], Map Int Text) rangesParser = do- n <- P.option 0 $ skipTillParser $ do+ n <- P.option (0 :: Int) $ skipTillParser $ do n <- P.decimal P.skipSpace- _ <- P.string "beginbfrange"+ void $ P.string "beginbfrange" return n - replicateM n $ do- P.skipSpace- _ <- P.char '<'- i <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'- P.skipSpace- _ <- P.char '<'- j <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'- P.skipSpace- _ <- P.char '<'- k <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'- return (toCode i, toCode j, Text.head $ Text.decodeUtf16BE k)+ let go 0 rs cs = return (rs, cs)+ go count rs cs = do+ P.skipSpace+ i <- toCode <$> parseHex+ P.skipSpace+ j <- toCode <$> parseHex+ P.skipSpace+ k <- P.eitherP parseHex parseHexArray+ case k of+ Left h -> do+ c <- case Text.uncons $ Text.decodeUtf16BE h of+ Nothing -> fail "Can't decode range"+ Just (v, _) -> return v+ go (pred count) ((i, j, c) : rs) cs+ Right hs -> do+ let cs' = zip [i..j] . map Text.decodeUtf16BE $ hs+ go (pred count) rs (cs <> Map.fromList cs') + go n mempty mempty+ codeRangesParser :: Parser [(ByteString, ByteString)] codeRangesParser = do n <- skipTillParser $ do n <- P.decimal P.skipSpace- _ <- P.string "begincodespacerange"+ void $ P.string "begincodespacerange" return n replicateM n $ do P.skipSpace- _ <- P.char '<'- i <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'+ i <- parseHex P.skipSpace- _ <- P.char '<'- j <- P.takeTill (== '>') >>= fromHex- _ <- P.char '>'+ j <- parseHex return (i, j) +parseHex :: Parser ByteString+parseHex = do+ void $ P.char '<'+ res <- P.takeTill (== '>') >>= fromHex+ void $ P.char '>'+ return res++parseHexArray :: Parser [ByteString]+parseHexArray = do+ void $ P.char '['+ res <- P.many' $ do+ P.skipSpace+ parseHex+ P.skipSpace+ void $ P.char ']'+ return res++-- XXX: wtf?! fromHex :: Monad m => ByteString -> m ByteString fromHex hex = do let (str, rest) = Base16.decode $ bsToLower hex@@ -152,7 +175,11 @@ fail $ "Can't decode hex" ++ show rest return str where- bsToLower = BS.map $ fromIntegral . fromEnum . toLower . toEnum . fromIntegral+ bsToLower = BS.map $ fromIntegral+ . fromEnum+ . toLower+ . toEnum+ . fromIntegral skipTillParser :: Parser a -> Parser a skipTillParser p = P.choice [
pdf-toolbox-content.cabal view
@@ -1,11 +1,11 @@ name: pdf-toolbox-content-version: 0.0.3.1+version: 0.0.3.2 synopsis: A collection of tools for processing PDF files license: BSD3 license-file: LICENSE author: Yuras Shumovich maintainer: Yuras Shumovich <shumovichy@gmail.com>-copyright: Copyright (c) Yuras Shumovich 2013-2014+copyright: Copyright (c) Yuras Shumovich 2013-2015 category: PDF build-type: Simple cabal-version: >=1.8