{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Graphics.PDF.Draw(
Draw
, PDFStream(..)
, withNewContext
, DrawState(..)
, DrawEnvironment(..)
, readDrawST
, writeDrawST
, modifyDrawST
, DrawTuple()
, penPosition
, supplyName
, emptyDrawing
, runDrawing
, setResource
, emptyEnvironment
, PDFXForm
, PDFXObject(..)
, AnyPdfXForm
, pdfDictMember
, PDF(..)
, PDFPage(..)
, PDFPages(..)
, PdfState(..)
, PDFCatalog(..)
, Pages(..)
, PDFDocumentPageMode(..)
, PDFDocumentPageLayout(..)
, PDFViewerPreferences(..)
, PDFDocumentInfo(..)
, PDFTransition(..)
, PDFTransStyle(..)
, PDFTransDirection(..)
, PDFTransDimension(..)
, PDFTransDirection2(..)
, PDFOutline(..)
, OutlineStyle(..)
, PDFOutlineEntry(..)
, Destination(..)
, Outline
, OutlineLoc(..)
, Tree(..)
, OutlineCtx(..)
, AnnotationObject(..)
, Color(..)
, hsvToRgb
, OutlineData
, AnyAnnotation(..)
, AnnotationStyle(..)
, PDFShading(..)
, getRgbColor
, emptyDrawState
, Matrix(..)
, identity
, applyMatrix
, currentMatrix
, multiplyCurrentMatrixWith
, PDFGlobals(..)
) where
import Data.Maybe
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
import qualified Data.Map.Strict as M
import qualified Data.IntMap as IM
import qualified Data.Binary.Builder as BU
import qualified Data.ByteString.Lazy as B
import Control.Monad.ST
import Data.STRef
import Control.Monad.Writer.Class
import Control.Monad.Reader.Class
import Control.Monad.State
import Graphics.PDF.Coordinates
import Graphics.PDF.LowLevel.Types
import Graphics.PDF.LowLevel.Serializer
import Graphics.PDF.Resources
import Graphics.PDF.Data.PDFTree(PDFTree)
import qualified Data.Text as T
import Graphics.PDF.Fonts.Font(PDFFont(..))
data AnnotationStyle = AnnotationStyle !(Maybe Color)
class AnnotationObject a where
addAnnotation :: a -> PDF (PDFReference a)
annotationType :: a -> PDFName
annotationContent :: a -> AnyPdfObject
annotationRect :: a -> [PDFFloat]
annotationToGlobalCoordinates :: a -> Draw a
annotationToGlobalCoordinates = return
data AnyAnnotation = forall a.(PdfObject a,AnnotationObject a) => AnyAnnotation a
instance PdfObject AnyAnnotation where
toPDF (AnyAnnotation a) = toPDF a
instance PdfLengthInfo AnyAnnotation where
instance AnnotationObject AnyAnnotation where
addAnnotation (AnyAnnotation a) = do
PDFReference r <- addAnnotation a
return (PDFReference r)
annotationType (AnyAnnotation a) = annotationType a
annotationContent (AnyAnnotation a) = annotationContent a
annotationRect (AnyAnnotation a) = annotationRect a
data Color = Rgb !Double !Double !Double
| Hsv !Double !Double !Double
deriving(Eq,Ord)
data DrawState = DrawState {
supplyNames :: [String]
, rsrc :: PDFResource
, strokeAlphas :: M.Map StrokeAlpha String
, fillAlphas :: M.Map FillAlpha String
, theFonts :: M.Map PDFFont String
, xobjects :: M.Map (PDFReference AnyPdfXForm) String
, otherRsrcs :: PDFDictionary
, annots :: [AnyAnnotation]
, patterns :: M.Map (PDFReference AnyPdfPattern) String
, colorSpaces :: M.Map PDFColorSpace String
, shadings :: M.Map PDFShading String
, matrix :: [Matrix]
}
data DrawEnvironment = DrawEnvironment {
streamId :: Int
, xobjectBoundD :: IM.IntMap (PDFFloat,PDFFloat)
}
data DrawTuple s
= DrawTuple { drawEnvironment :: DrawEnvironment
, drawStateRef :: STRef s DrawState
, builderRef :: STRef s BU.Builder
, penPosition :: STRef s Point
}
emptyEnvironment :: DrawEnvironment
emptyEnvironment = DrawEnvironment 0 IM.empty
class PDFGlobals m where
bounds :: PDFXObject a => PDFReference a -> m (PDFFloat,PDFFloat)
newtype Draw a = Draw {unDraw :: forall s. DrawTuple s -> ST s a }
instance Applicative Draw where
pure x = Draw $ \_env -> return x
df <*> af = Draw $ \env -> do
f <- unDraw df env
a <- unDraw af env
return $ f a
instance Monad Draw where
m >>= f = Draw $ \env -> do
a <- unDraw m env
unDraw (f a) env
return x = Draw $ \_env -> return x
instance MonadReader DrawEnvironment Draw where
ask = Draw $ \env -> return (drawEnvironment env)
local f m = Draw $ \env -> let drawenv' = f (drawEnvironment env)
env' = env { drawEnvironment = drawenv' }
in unDraw m env'
instance MonadState DrawState Draw where
get = Draw $ \env -> readSTRef (drawStateRef env)
put st = Draw $ \env -> writeSTRef (drawStateRef env) st
instance MonadWriter BU.Builder Draw where
tell bu = Draw $ \env -> modifySTRef (builderRef env) (`mappend` bu)
listen m = Draw $ \env -> do
a <- unDraw m env
w <- readSTRef (builderRef env)
return (a,w)
pass m = Draw $ \env -> do
(a, f) <- unDraw m env
modifySTRef (builderRef env) f
return a
instance Functor Draw where
fmap f = \m -> do { a <- m; return (f a) }
instance MonadPath Draw
readDrawST :: (forall s. DrawTuple s -> STRef s a) -> Draw a
readDrawST f = Draw $ \env -> readSTRef (f env)
writeDrawST :: (forall s. DrawTuple s -> STRef s a) -> a -> Draw ()
writeDrawST f x = Draw $ \env -> writeSTRef (f env) x
modifyDrawST :: (forall s. DrawTuple s -> STRef s a) -> (a -> a) -> Draw ()
modifyDrawST f g = Draw $ \env -> modifySTRef (f env) g
data PDFStream = PDFStream !BU.Builder !Bool !(PDFReference MaybeLength) !PDFDictionary
instance PdfObject PDFStream where
toPDF (PDFStream s c l d) =
mconcat $ [ toPDF dict
, serialize "\nstream"
, newline
, s
, newline
, serialize "endstream"]
where
compressedStream False = []
compressedStream True = if not (pdfDictMember (PDFName "Filter") d) then [(PDFName "Filter",AnyPdfObject $ [AnyPdfObject . PDFName $ "FlateDecode"])] else []
lenDict = PDFDictionary. M.fromList $ [ (PDFName "Length",AnyPdfObject l)] ++ compressedStream c
dict = pdfDictUnion lenDict d
instance PdfLengthInfo PDFStream where
pdfLengthInfo (PDFStream s _ l _) = Just (B.length . BU.toLazyByteString $ s,l)
emptyDrawing :: Draw ()
emptyDrawing = return ()
pdfDictMember :: PDFName -> PDFDictionary -> Bool
pdfDictMember k (PDFDictionary d) = M.member k d
supplyName :: Draw String
supplyName = do
xs <- gets supplyNames
modifyStrict $ \s -> s {supplyNames = tail xs}
return (head xs)
emptyDrawState :: Int -> DrawState
emptyDrawState ref =
let names = (map (("O" ++ (show ref)) ++ ) $ [replicate k ['a'..'z'] | k <- [1..]] >>= sequence) in
DrawState names emptyRsrc M.empty M.empty M.empty M.empty emptyDictionary [] M.empty M.empty M.empty [identity]
runDrawing :: Draw a -> DrawEnvironment -> DrawState -> (a,DrawState,BU.Builder)
runDrawing drawing environment drawState
= runST $ do
dRef <- newSTRef drawState
bRef <- newSTRef mempty
posRef <- newSTRef 0
let tuple = DrawTuple { drawEnvironment = environment
, drawStateRef = dRef
, builderRef = bRef
, penPosition = posRef
}
a <- unDraw drawing tuple
drawSt <- readSTRef (drawStateRef tuple)
builder <- readSTRef (builderRef tuple)
return (a, drawSt, builder)
pushMatrixStack :: Matrix -> Draw ()
pushMatrixStack m = do
modifyStrict $ \s -> s {matrix = m : matrix s}
popMatrixStack :: Draw ()
popMatrixStack = do
modifyStrict $ \s -> s {matrix = tail (matrix s)}
multiplyCurrentMatrixWith :: Matrix -> Draw ()
multiplyCurrentMatrixWith m' = modifyStrict $ \s -> s {matrix = let (m:l) = matrix s in (m' * m ):l}
currentMatrix :: Draw Matrix
currentMatrix = gets matrix >>= return . head
withNewContext :: Draw a -> Draw a
withNewContext m = do
tell . serialize $ "\nq"
pushMatrixStack identity
a <- m
popMatrixStack
tell . serialize $ "\nQ"
return a
setResource :: (Ord a, PdfResourceObject a) => String
-> a
-> M.Map a String
-> Draw (String,M.Map a String)
setResource dict values oldCache = do
case M.lookup values oldCache of
Nothing -> do
newName <- supplyName
modifyStrict $ \s -> s { rsrc = addResource (PDFName dict) (PDFName newName) (toRsrc values) (rsrc s)}
return (newName,M.insert values newName oldCache)
Just n -> return (n,oldCache)
instance PDFGlobals Draw where
bounds (PDFReference r) = getBoundInDraw r
instance PDFGlobals PDF where
bounds (PDFReference r) = getBoundInPDF r
class PDFXObject a where
drawXObject :: PDFReference a -> Draw ()
privateDrawXObject :: PDFReference a -> Draw ()
privateDrawXObject (PDFReference r) = do
xobjectMap <- gets xobjects
(newName,newMap) <- setResource "XObject" (PDFReference r) xobjectMap
modifyStrict $ \s -> s { xobjects = newMap }
tell . mconcat $ [ serialize "\n/"
, serialize newName
, serialize " Do"
]
drawXObject = privateDrawXObject
data AnyPdfXForm = forall a. (PDFXObject a,PdfObject a) => AnyPdfXForm a
instance PdfObject AnyPdfXForm where
toPDF (AnyPdfXForm a) = toPDF a
instance PdfLengthInfo AnyPdfXForm where
instance PDFXObject AnyPdfXForm
data PDFXForm
instance PDFXObject PDFXForm
instance PdfObject PDFXForm where
toPDF _ = noPdfObject
instance PdfLengthInfo PDFXForm where
instance PdfResourceObject (PDFReference PDFXForm) where
toRsrc = AnyPdfObject
instance PdfResourceObject (PDFReference AnyPdfXForm) where
toRsrc = AnyPdfObject
getBoundInDraw :: Int
-> Draw (PDFFloat,PDFFloat)
getBoundInDraw ref = do
theBounds <- asks xobjectBoundD
return $ IM.findWithDefault (0.0,0.0) ref theBounds
getBoundInPDF :: Int
-> PDF (PDFFloat,PDFFloat)
getBoundInPDF ref = do
theBounds <- gets xobjectBound
return $ IM.findWithDefault (0.0,0.0) ref theBounds
data PDFCatalog = PDFCatalog
!(Maybe (PDFReference PDFOutline))
!(PDFReference PDFPages)
!PDFDocumentPageMode
!PDFDocumentPageLayout
!PDFViewerPreferences
data PdfState = PdfState { supplySrc :: !Int
, objects :: !(IM.IntMap AnyPdfObject)
, pages :: !Pages
, streams :: !(IM.IntMap ((Maybe (PDFReference PDFPage)),(DrawState,BU.Builder)))
, catalog :: !(PDFReference PDFCatalog)
, defaultRect :: !PDFRect
, docInfo :: !PDFDocumentInfo
, outline :: Maybe Outline
, currentPage :: Maybe (PDFReference PDFPage)
, xobjectBound :: !(IM.IntMap (PDFFloat,PDFFloat))
, firstOutline :: [Bool]
}
#ifndef __HADDOCK__
data PDFPage = PDFPage
!(Maybe (PDFReference PDFPages))
!(PDFRect)
!(PDFReference PDFStream)
!(Maybe (PDFReference PDFResource))
!(Maybe PDFFloat)
!(Maybe PDFTransition)
![AnyPdfObject]
#else
data PDFPage
#endif
instance Show PDFPage where
show _ = "PDFPage"
newtype Pages = Pages (PDFTree PDFPage)
#ifndef __HADDOCK__
data PDFPages = PDFPages
!Int
!(Maybe (PDFReference PDFPages))
[Either (PDFReference PDFPages) (PDFReference PDFPage)]
#else
data PDFPages
#endif
data PDFTransition = PDFTransition !PDFFloat !PDFTransStyle
deriving(Eq)
data PDFTransDimension = Horizontal | Vertical
deriving(Eq)
instance Show PDFTransDimension where
show Horizontal = "H"
show Vertical = "V"
data PDFTransDirection = Inward | Outward deriving(Eq)
instance Show PDFTransDirection where
show Inward = "I"
show Outward = "O"
data PDFTransDirection2 = LeftToRight
| BottomToTop
| RightToLeft
| TopToBottom
| TopLeftToBottomRight
deriving(Eq)
newtype PDF a = PDF {unPDF :: State PdfState a}
#ifndef __HADDOCK__
deriving (Functor, Applicative, Monad, MonadState PdfState)
#else
instance Functor PDF
instance Monad PDF
instance MonadState PdfState PDF
#endif
data PDFTransStyle = Split PDFTransDimension PDFTransDirection
| Blinds PDFTransDimension
| Box PDFTransDirection
| Wipe PDFTransDirection2
| Dissolve
| Glitter PDFTransDirection2
deriving(Eq)
data PDFDocumentInfo = PDFDocumentInfo {
author :: T.Text
, subject :: T.Text
, pageMode :: PDFDocumentPageMode
, pageLayout :: PDFDocumentPageLayout
, viewerPreferences :: PDFViewerPreferences
, compressed :: Bool
}
data PDFDocumentPageMode = UseNone
| UseOutlines
| UseThumbs
| FullScreen
deriving(Eq,Show)
data PDFDocumentPageLayout = SinglePage
| OneColumn
| TwoColumnLeft
| TwoColumnRight
| TwoPageLeft
| TwoPageRight
deriving(Eq,Show)
data PDFViewerPreferences = PDFViewerPreferences { hideToolbar :: Bool
, hideMenuBar :: Bool
, hideWindowUI :: Bool
, fitWindow :: Bool
, centerWindow :: Bool
, displayDoctitle :: Bool
, nonFullScreenPageMode :: PDFDocumentPageMode
}
data PDFOutline = PDFOutline !(PDFReference PDFOutlineEntry) !(PDFReference PDFOutlineEntry)
instance PdfObject PDFOutline where
toPDF (PDFOutline first lasto) = toPDF $ PDFDictionary. M.fromList $ [
(PDFName "Type",AnyPdfObject . PDFName $ "Outlines")
, (PDFName "First",AnyPdfObject first)
, (PDFName "Last",AnyPdfObject lasto)
]
instance PdfLengthInfo PDFOutline where
data OutlineStyle = NormalOutline
| ItalicOutline
| BoldOutline
deriving(Eq)
data PDFOutlineEntry = PDFOutlineEntry !PDFString
!(PDFReference PDFOutlineEntry)
!(Maybe (PDFReference PDFOutlineEntry))
!(Maybe (PDFReference PDFOutlineEntry))
!(Maybe (PDFReference PDFOutlineEntry))
!(Maybe (PDFReference PDFOutlineEntry))
Int
Destination
Color
OutlineStyle
data Destination = Destination !(PDFReference PDFPage) deriving(Eq,Show)
type OutlineData = (PDFString,Maybe Color, Maybe OutlineStyle,Destination)
type Outline = OutlineLoc OutlineData
data Tree a = Node a [Tree a]
data OutlineCtx a = Top | Child { value :: a
, parent :: OutlineCtx a
, lefts :: [Tree a]
, rights :: [Tree a]
}
data OutlineLoc a = OutlineLoc (Tree a) (OutlineCtx a)
instance PdfObject PDFViewerPreferences where
toPDF (PDFViewerPreferences ht hm hwui fw cw ddt nfspm ) = toPDF $ PDFDictionary. M.fromList $
[ (PDFName "HideToolbar",AnyPdfObject ht)
, (PDFName "HideMenubar",AnyPdfObject hm)
, (PDFName "HideWindowUI",AnyPdfObject hwui)
, (PDFName "FitWindow",AnyPdfObject fw)
, (PDFName "CenterWindow",AnyPdfObject cw)
, (PDFName "DisplayDocTitle",AnyPdfObject ddt)
, (PDFName "NonFullScreenPageMode",AnyPdfObject . PDFName . show $ nfspm)
]
instance PdfLengthInfo PDFViewerPreferences where
instance Show PDFTransStyle where
show (Split _ _) = "Split"
show (Blinds _) = "Blinds"
show (Box _) = "Box"
show (Wipe _) = "Wipe"
show (Dissolve) = "Dissolve"
show (Glitter _) = "Glitter"
instance PdfObject PDFTransition where
toPDF (PDFTransition d t) = toPDF $ PDFDictionary. M.fromList $
[ (PDFName "Type",AnyPdfObject (PDFName "Trans"))
, (PDFName "S",AnyPdfObject (PDFName (show t)))
, (PDFName "D",AnyPdfObject d)
] ++ optionalDm t ++ optionalM t ++ optionalDi t
where
optionalDm (Split a _) = [ (PDFName "Dm",AnyPdfObject (PDFName (show a)))]
optionalDm (Blinds a) = [ (PDFName "Dm",AnyPdfObject (PDFName (show a)))]
optionalDm _ = []
optionalM (Split _ a) = [ (PDFName "M",AnyPdfObject (PDFName (show a)))]
optionalM (Box a) = [ (PDFName "M",AnyPdfObject (PDFName (show a)))]
optionalM _ = []
optionalDi (Wipe a) = [ (PDFName "Di",AnyPdfObject (floatDirection a))]
optionalDi (Glitter a) = [ (PDFName "Di",AnyPdfObject (floatDirection a))]
optionalDi _ = []
instance PdfLengthInfo PDFTransition where
instance PdfObject PDFPages where
toPDF (PDFPages c Nothing l) = toPDF $ PDFDictionary. M.fromList $
[ (PDFName "Type",AnyPdfObject (PDFName "Pages"))
, (PDFName "Kids",AnyPdfObject $ map AnyPdfObject l)
, (PDFName "Count",AnyPdfObject . PDFInteger $ c)
]
toPDF (PDFPages c (Just theParent) l) = toPDF $ PDFDictionary. M.fromList $
[ (PDFName "Type",AnyPdfObject (PDFName "Pages"))
, (PDFName "Parent",AnyPdfObject theParent)
, (PDFName "Kids",AnyPdfObject $ map AnyPdfObject l)
, (PDFName "Count",AnyPdfObject . PDFInteger $ c)
]
instance PdfLengthInfo PDFPages where
instance PdfObject PDFPage where
toPDF (PDFPage (Just theParent) box content theRsrc d t theAnnots) = toPDF $ PDFDictionary. M.fromList $
[ (PDFName "Type",AnyPdfObject (PDFName "Page"))
, (PDFName "Parent",AnyPdfObject theParent)
, (PDFName "MediaBox",AnyPdfObject box)
, (PDFName "Contents",AnyPdfObject content)
, if isJust theRsrc
then
(PDFName "Resources",AnyPdfObject . fromJust $ theRsrc)
else
(PDFName "Resources",AnyPdfObject emptyDictionary)
] ++ (maybe [] (\x -> [(PDFName "Dur",AnyPdfObject x)]) d)
++ (maybe [] (\x -> [(PDFName "Trans",AnyPdfObject x)]) t)
++ ((\x -> if null x then [] else [(PDFName "Annots",AnyPdfObject x)]) theAnnots)
toPDF (PDFPage Nothing _ _ _ _ _ _) = noPdfObject
instance PdfLengthInfo PDFPage where
instance PdfObject PDFCatalog where
toPDF (PDFCatalog outlines lPages pgMode pgLayout viewerPrefs) = toPDF $ PDFDictionary . M.fromList $
[ (PDFName "Type",AnyPdfObject (PDFName "Catalog"))
, (PDFName "Pages",AnyPdfObject lPages)
, (PDFName "PageMode", AnyPdfObject . PDFName . show $ pgMode)
, (PDFName "PageLayout", AnyPdfObject . PDFName . show $ pgLayout)
, (PDFName "ViewerPreferences", AnyPdfObject viewerPrefs)
] ++ (maybe [] (\x -> [(PDFName "Outlines",AnyPdfObject x)]) outlines)
instance PdfLengthInfo PDFCatalog where
instance PdfObject OutlineStyle where
toPDF NormalOutline = toPDF (PDFInteger 0)
toPDF ItalicOutline = toPDF (PDFInteger 1)
toPDF BoldOutline = toPDF (PDFInteger 2)
instance PdfLengthInfo OutlineStyle where
instance PdfObject PDFOutlineEntry where
toPDF (PDFOutlineEntry title theParent prev next first theLast count dest color style) =
toPDF $ PDFDictionary. M.fromList $ [
(PDFName "Title",AnyPdfObject title)
, (PDFName "Parent",AnyPdfObject theParent)
]
++
maybe [] (\x -> [(PDFName "Prev",AnyPdfObject x)]) prev
++
maybe [] (\x -> [(PDFName "Next",AnyPdfObject x)]) next
++
maybe [] (\x -> [(PDFName "First",AnyPdfObject x)]) first
++
maybe [] (\x -> [(PDFName "Last",AnyPdfObject x)]) theLast
++
[ (PDFName "Count",AnyPdfObject (PDFInteger count))
, (PDFName "Dest",AnyPdfObject dest)
, (PDFName "C",AnyPdfObject color)
, (PDFName "F",AnyPdfObject style)
]
instance PdfLengthInfo PDFOutlineEntry where
instance PdfObject Destination where
toPDF (Destination r) = toPDF [ AnyPdfObject r
, AnyPdfObject . PDFName $ "Fit"
]
instance PdfLengthInfo Destination where
instance PdfObject Color where
toPDF (Rgb r g b) = toPDF . map AnyPdfObject $ [r,g,b]
toPDF (Hsv h s v) = let (r,g,b) = hsvToRgb (h,s,v)
in toPDF . map AnyPdfObject $ [r,g,b]
instance PdfLengthInfo Color where
floatDirection :: PDFTransDirection2 -> PDFFloat
floatDirection LeftToRight = 0
floatDirection BottomToTop = 90
floatDirection RightToLeft = 180
floatDirection TopToBottom = 270
floatDirection TopLeftToBottomRight = 315
hsvToRgb :: (Double,Double,Double) -> (Double,Double,Double)
hsvToRgb (h,s,v) =
let hi = fromIntegral (floor (h / 60) `mod` 6 :: Int) :: Double
f = h/60 - hi
p = v * (1-s)
q = v * (1 - f*s)
t = v * (1 - (1-f)*s) in
case hi of
0 -> (v,t,p)
1 -> (q,v,p)
2 -> (p,v,t)
3 -> (p,q,v)
4 -> (t,p,v)
5 -> (v,p,q)
_ -> error "Hue value incorrect"
getRgbColor :: Color -> (PDFFloat,PDFFloat,PDFFloat)
getRgbColor (Rgb r g b) = (r, g, b)
getRgbColor (Hsv h s v) = let (r,g,b) = hsvToRgb (h,s,v) in (r, g, b)
interpole :: Int -> PDFFloat -> PDFFloat -> AnyPdfObject
interpole n x y = AnyPdfObject . PDFDictionary . M.fromList $
[ (PDFName "FunctionType", AnyPdfObject . PDFInteger $ 2)
, (PDFName "Domain", AnyPdfObject . map AnyPdfObject $ ([0,1] :: [PDFFloat]))
, (PDFName "C0", AnyPdfObject . map AnyPdfObject $ [x])
, (PDFName "C1", AnyPdfObject . map AnyPdfObject $ [y])
, (PDFName "N", AnyPdfObject . PDFInteger $ n)
]
data PDFShading = AxialShading PDFFloat PDFFloat PDFFloat PDFFloat Color Color
| RadialShading PDFFloat PDFFloat PDFFloat PDFFloat PDFFloat PDFFloat Color Color
deriving(Eq,Ord)
instance PdfResourceObject PDFShading where
toRsrc (AxialShading x0 y0 x1 y1 ca cb) = AnyPdfObject . PDFDictionary . M.fromList $
[ (PDFName "ShadingType",AnyPdfObject . PDFInteger $ 2)
, (PDFName "Coords",AnyPdfObject . map AnyPdfObject $ [x0,y0,x1,y1])
, (PDFName "ColorSpace",AnyPdfObject . PDFName $ "DeviceRGB")
, (PDFName "Function",AnyPdfObject $ [interpole 1 ra rb,interpole 1 ga gb,interpole 1 ba bb])
]
where
(ra,ga,ba) = getRgbColor ca
(rb,gb,bb) = getRgbColor cb
toRsrc (RadialShading x0 y0 r0 x1 y1 r1 ca cb) = AnyPdfObject . PDFDictionary . M.fromList $
[ (PDFName "ShadingType",AnyPdfObject . PDFInteger $ 3)
, (PDFName "Coords",AnyPdfObject . map AnyPdfObject $ [x0,y0,r0,x1,y1,r1])
, (PDFName "ColorSpace",AnyPdfObject . PDFName $ "DeviceRGB")
, (PDFName "Function",AnyPdfObject $ [interpole 1 ra rb,interpole 1 ga gb,interpole 1 ba bb])
]
where
(ra,ga,ba) = getRgbColor ca
(rb,gb,bb) = getRgbColor cb
applyMatrix :: Matrix -> Draw ()
applyMatrix m@(Matrix a b c d e f) = do
multiplyCurrentMatrixWith m
tell . mconcat $[ serialize '\n'
, toPDF a
, serialize ' '
, toPDF b
, serialize ' '
, toPDF c
, serialize ' '
, toPDF d
, serialize ' '
, toPDF e
, serialize ' '
, toPDF f
, serialize " cm"
]