packages feed

diagrams-pdf 0.2.0 → 0.3

raw patch · 6 files changed

+870/−137 lines, 6 filesbinary-addedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Diagrams.Backend.Pdf: BottomLeftCorner :: TextOrigin
+ Diagrams.Backend.Pdf: BottomRightCorner :: TextOrigin
+ Diagrams.Backend.Pdf: BottomSide :: TextOrigin
+ Diagrams.Backend.Pdf: Center :: TextOrigin
+ Diagrams.Backend.Pdf: LabelStyle :: FontName -> LabelSize -> Justification -> TextOrigin -> (Colour Double) -> LabelStyle
+ Diagrams.Backend.Pdf: LeftSide :: TextOrigin
+ Diagrams.Backend.Pdf: RightSide :: TextOrigin
+ Diagrams.Backend.Pdf: TopLeftCorner :: TextOrigin
+ Diagrams.Backend.Pdf: TopRightCorner :: TextOrigin
+ Diagrams.Backend.Pdf: TopSide :: TextOrigin
+ Diagrams.Backend.Pdf: data LabelStyle
+ Diagrams.Backend.Pdf: data TextOrigin
+ Diagrams.Backend.Pdf: instance Renderable PdfImage Pdf
+ Diagrams.Backend.Pdf: instance Renderable PdfTextBox Pdf
+ Diagrams.Backend.Pdf: instance Renderable PdfURL Pdf
+ Diagrams.Backend.Pdf: instance Transformable TransSh
+ Diagrams.Backend.Pdf: pdfAxialShading :: HasStyle a => P2 -> P2 -> Colour Double -> Colour Double -> a -> a
+ Diagrams.Backend.Pdf: pdfImage :: (Monad m, PDFGlobals m) => PDFReference PDFJpeg -> m (Diagram Pdf R2)
+ Diagrams.Backend.Pdf: pdfLabelWithSize :: (Renderable PdfTextBox Pdf, Renderable (Path R2) Pdf) => LabelStyle -> String -> Double -> Double -> Diagram Pdf R2
+ Diagrams.Backend.Pdf: pdfLabelWithSuggestedSize :: (Renderable PdfTextBox Pdf, Renderable (Path R2) Pdf) => LabelStyle -> String -> Double -> Double -> (Diagram Pdf R2, Diagram Pdf R2)
+ Diagrams.Backend.Pdf: pdfRadialShading :: HasStyle a => P2 -> Double -> P2 -> Double -> Colour Double -> Colour Double -> a -> a
+ Diagrams.Backend.Pdf: pdfTextWithSize :: (ParagraphStyle ps s, Style s, Renderable PdfTextBox Pdf, Renderable (Path R2) Pdf) => TextOrigin -> Double -> Double -> ps -> s -> TM ps s () -> Diagram Pdf R2
+ Diagrams.Backend.Pdf: pdfTextWithSuggestedSize :: (ParagraphStyle ps s, Style s, Renderable PdfTextBox Pdf, Renderable (Path R2) Pdf) => TextOrigin -> Double -> Double -> ps -> s -> TM ps s () -> (Diagram Pdf R2, Diagram Pdf R2)
+ Diagrams.Backend.Pdf: pdfURL :: String -> Double -> Double -> Diagram Pdf R2
+ Diagrams.Backend.Pdf: type LabelSize = Int

Files

diagrams-pdf.cabal view
@@ -1,5 +1,5 @@ name:                diagrams-pdf-version:             0.2.0+version:             0.3 synopsis:            PDF backend for diagrams drawing EDSL homepage:            http://www.alpheccar.org license:             BSD3@@ -32,14 +32,17 @@                      .                      Additional documentation can be found in the                      README file distributed with the source tarball+extra-source-files: test/test.hs, test/Makefile, test/logo.jpg+ Source-repository head   type:     git   location: http://github.com/alpheccar/diagrams-pdf + library   Exposed-modules:     Diagrams.Backend.Pdf                        Diagrams.Backend.Pdf.CmdLine     -  -- other-modules:       +  other-modules:       Diagrams.Backend.Pdf.Specific   build-depends:       base >= 4.6 && < 4.8,                        mtl >= 2.1 && < 2.2 ,                        monoid-extras >= 0.3 && < 0.4,
src/Diagrams/Backend/Pdf.hs view
@@ -8,7 +8,8 @@ {-# LANGUAGE TypeSynonymInstances      #-} {-# LANGUAGE ViewPatterns              #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.Backend.Pdf@@ -29,13 +30,36 @@ -- -- This IO action will write the specified file. --+-- / Specific HPDF primitives /+-- +-- For details about the use of the HPDF specific primitives, the file+-- test.hs in this package can be used. You'll have to unpack the archive+-- for this package. ----------------------------------------------------------------------------- module Diagrams.Backend.Pdf -  ( -- * Backend token+  ( -- * PDF Backend +    -- ** Backend token     Pdf(..)+    -- ** Backend options   , Options(..)   , sizeFromSpec+  -- * HPDF Specific primitives +  -- ** Text+  , LabelStyle(..)+  , TextOrigin(..)+  , LabelSize+  , pdfLabelWithSuggestedSize+  , pdfTextWithSuggestedSize+  , pdfLabelWithSize+  , pdfTextWithSize+  -- ** Image+  , pdfImage+  -- ** URL+  , pdfURL+  -- ** Shading+  , pdfAxialShading+  , pdfRadialShading   ) where  @@ -51,90 +75,23 @@  import qualified Data.Foldable                 as F import           Data.Monoid.Split-import           Data.Typeable import qualified Control.Monad.State.Strict as S import Control.Monad.Trans(lift) import Diagrams.TwoD.Path import Control.Monad(when)+import Diagrams.Backend.Pdf.Specific+import           Data.Typeable+import qualified Diagrams.TwoD.Shapes as Sh+import Data.Maybe(isJust) +--import Debug.Trace as T++--debug a = T.trace (show a) a + -- | This data declaration is simply used as a token to distinguish this rendering engine. data Pdf = Pdf     deriving (Eq,Ord,Read,Show,Typeable) -{-- -For a future release to support some specific HPDF features---}-{--data LabelStyle = LabelStyle Int Justification P.Orientation --data TextBox = TextBox T2 Double Double LabelStyle String--type instance V TextBox = R2--instance Transformable TextBox where-  transform t (TextBox tt w h a s) = TextBox (t <> tt) w h a s--instance IsPrim TextBox--instance HasOrigin TextBox where-  moveOriginTo p = translate (origin .-. p)--instance Renderable TextBox NullBackend where-  render _ _ = mempty--pdfText :: (Renderable TextBox b) -        => LabelStyle -        -> String -        -> Double -        -> Double -        -> Diagram b R2-pdfText ls s w h = mkQD (Prim (TextBox mempty w h ls s))-                         (getEnvelope r)-                         (getTrace r)-                         mempty-                         (Query $ \p -> Any (isInsideEvenOdd p r))--  where r :: Path R2-        r = rect w h--drawStringLabel :: LabelStyle -                -> String -                -> PDFFloat -                -> PDFFloat -                -> PDFFloat -                -> PDFFloat -                -> Draw () -drawStringLabel (LabelStyle fs j o) s x y w h = do-  let (r,b) = drawTextBox x y w h o NormalParagraph (P.Font (PDFFont Times_Roman fs) P.black P.black) $ do-                setJustification j-                paragraph $ do-                    txt $ s-  b--instance Renderable TextBox Pdf where-  render _ (TextBox t w h ls text) = D $ do-    let r :: Path R2-        r = rect w h -        r' = transform t r -        b = boundingBox r' -        corners = getCorners b -    case corners of -       Just (a,b) -> do -        let (xa,ya) = unp2 a -            (xb,yb) = unp2 b-        drawM $ P.stroke $ Rectangle (xa :+ ya) (xb :+ yb) -        drawM (drawStringLabel ls text xa ya (xb-xa) (yb-ya)) -       Nothing -> return() --}--{-- -End of the specific part---}- -- | The drawing state -- I should give a name to the different fields and use lens -- The first three parameters are for the font@@ -153,6 +110,7 @@                                  , _mustFill :: Bool                                  , _mustStroke :: Bool                                  , _isloop :: Bool+                                 , _shading :: Maybe PDFShading                                }  -- | The stack of drawing state@@ -171,7 +129,7 @@  -- | Initial drawing state initState :: StateStack-initState = StateStack (DrawingState FontSlantNormal FontWeightNormal 1 Winding (0 :+ 0) False True False) []+initState = StateStack (DrawingState FontSlantNormal FontWeightNormal 1 Winding (0 :+ 0) False True True Nothing) []   -- | The drawing monad with state@@ -192,55 +150,55 @@  -- | Generate an HPDF font mkFont :: DrawingState -> PDFFont -mkFont (DrawingState FontSlantNormal FontWeightNormal s _ _ _ _ _) = PDFFont Times_Roman s-mkFont (DrawingState FontSlantNormal FontWeightBold s _ _ _ _ _) = PDFFont Times_Bold s-mkFont (DrawingState FontSlantItalic FontWeightNormal s _ _ _ _ _) = PDFFont Times_Italic s-mkFont (DrawingState FontSlantItalic FontWeightBold s _ _ _ _ _) = PDFFont Times_BoldItalic s-mkFont (DrawingState FontSlantOblique FontWeightNormal s _ _ _ _ _) = PDFFont Helvetica_Oblique s-mkFont (DrawingState FontSlantOblique FontWeightBold s _ _ _ _ _) = PDFFont Helvetica_BoldOblique s+mkFont (DrawingState FontSlantNormal FontWeightNormal s _ _ _ _ _ _) = PDFFont Times_Roman s+mkFont (DrawingState FontSlantNormal FontWeightBold s _ _ _ _ _ _) = PDFFont Times_Bold s+mkFont (DrawingState FontSlantItalic FontWeightNormal s _ _ _ _ _ _) = PDFFont Times_Italic s+mkFont (DrawingState FontSlantItalic FontWeightBold s _ _ _ _ _ _) = PDFFont Times_BoldItalic s+mkFont (DrawingState FontSlantOblique FontWeightNormal s _ _ _ _ _ _) = PDFFont Helvetica_Oblique s+mkFont (DrawingState FontSlantOblique FontWeightBold s _ _ _ _ _ _) = PDFFont Helvetica_BoldOblique s    setFontSize :: Double -> DrawS () setFontSize fs = do    let s = floor fs-  StateStack (DrawingState fsl fw _ wr p f st ilp) l <- S.get -  S.put $! StateStack (DrawingState fsl fw s wr p f st ilp) l+  StateStack (DrawingState fsl fw _ wr p f st ilp shade) l <- S.get +  S.put $! StateStack (DrawingState fsl fw s wr p f st ilp shade) l  setFontWeight :: FontWeight -> DrawS () setFontWeight w = do -  StateStack (DrawingState fsl _ fs wr p f st ilp) l <- S.get -  S.put $! StateStack (DrawingState fsl w fs wr p f st ilp) l+  StateStack (DrawingState fsl _ fs wr p f st ilp shade) l <- S.get +  S.put $! StateStack (DrawingState fsl w fs wr p f st ilp shade) l     setFontSlant :: FontSlant -> DrawS () setFontSlant sl = do -  StateStack (DrawingState _ fw fs wr p f st ilp) l <- S.get -  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp) l+  StateStack (DrawingState _ fw fs wr p f st ilp shade) l <- S.get +  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp shade) l    setFillRule :: FillRule -> DrawS () setFillRule wr = do -  StateStack (DrawingState sl fw fs _ p f st ilp) l <- S.get -  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp) l+  StateStack (DrawingState sl fw fs _ p f st ilp shade) l <- S.get +  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp shade) l  savePoint :: P.Point -> DrawS ()  savePoint p = do -  StateStack (DrawingState sl fw fs wr _ f st ilp) l <- S.get -  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp) l+  StateStack (DrawingState sl fw fs wr _ f st ilp shade) l <- S.get +  S.put $! StateStack (DrawingState sl fw fs wr p f st ilp shade) l  currentPoint :: DrawS P.Point  currentPoint = do -  StateStack (DrawingState _ _ _ _ p _ _ _) _ <- S.get +  StateStack (DrawingState _ _ _ _ p _ _ _ _) _ <- S.get    return p   getFillState :: DrawS FillRule  getFillState = do -  StateStack (DrawingState _ _ _ w _ _ _ _) _ <- S.get +  StateStack (DrawingState _ _ _ w _ _ _ _ _) _ <- S.get    return w  mustFill :: DrawS Bool  mustFill = do-  StateStack (DrawingState _ _ _ _ _ b _ _) _ <- S.get +  StateStack (DrawingState _ _ _ _ _ b _ _ _) _ <- S.get    return b  -- | From the alpha value of a fill color, we check if the filling must be disabled@@ -248,12 +206,12 @@ setFillingColor alpha = do      let b | alpha /= 0.0 = True            | otherwise = False-    StateStack (DrawingState fsl w fs wr p _ st ilp) l <- S.get -    S.put $! StateStack (DrawingState fsl w fs wr p b st ilp) l+    StateStack (DrawingState fsl w fs wr p _ st ilp shade) l <- S.get +    S.put $! StateStack (DrawingState fsl w fs wr p b st ilp shade) l  mustStroke :: DrawS Bool mustStroke = do -  StateStack (DrawingState _ _ _ _ _ _ b _) _ <- S.get +  StateStack (DrawingState _ _ _ _ _ _ b _ _) _ <- S.get    return b  -- | From the linew width we check if stroke must be disabled@@ -261,14 +219,19 @@ setTrokeState w = do    let st | w == 0 = False           | otherwise = True-  StateStack (DrawingState fsl fw fs wr p b _ ilp) l <- S.get -  S.put $! StateStack (DrawingState fsl fw fs wr p b st ilp) l+  StateStack (DrawingState fsl fw fs wr p b _ ilp shade) l <- S.get +  S.put $! StateStack (DrawingState fsl fw fs wr p b st ilp shade) l  isALoop :: DrawS Bool  isALoop = do    StateStack s _ <- S.get   return $ _isloop s +getShading :: DrawS (Maybe PDFShading) +getShading = do +  StateStack s _ <- S.get+  return $ _shading $  s+ setLoop :: Bool -> DrawS ()  setLoop b = do    StateStack s l <- S.get@@ -282,33 +245,43 @@      P.setWidth defaultWidth      d -strokeOrFill :: DrawS () -strokeOrFill = do +withShading :: Transformation R2 -> Bool -> Maybe PDFShading -> DrawS () -> DrawS () -> DrawS () +withShading td evenodd (Just shade) diag _ = do +    withContext $ do +      diag+      drawM $ do+         if evenodd +         then P.setAsClipPathEO+         else P.setAsClipPath+         P.applyShading (unTrans $ transform td (TransSh shade))+withShading _ _ _ diag paint = do +  diag +  paint++strokeOrFill :: Transformation R2 -> DrawS () -> DrawS () +strokeOrFill td r = do    mf <- mustFill   ms <- mustStroke    fs <- getFillState   isloop <- isALoop+  sh <- getShading   -- Set the diagram opacity in a new PDF context   case (ms,mf,fs,isloop) of -       (True,True,Winding,True) -> drawM (P.fillAndStrokePath)-       (True,True,EvenOdd,True) -> drawM (P.fillAndStrokePathEO)-       (False,True,Winding,True) -> drawM (P.fillPath)-       (False,True,EvenOdd,True) -> drawM (P.fillPathEO)-       (True,_,_,_) -> drawM (P.strokePath) -       (_,_,_,_) -> return ()+       (True,True,Winding,True) -> withShading td False sh r $ drawM (P.fillAndStrokePath)+       (True,True,EvenOdd,True) -> withShading td True sh r $ drawM (P.fillAndStrokePathEO)+       (False,True,Winding,True) -> withShading td False sh r $ drawM (P.fillPath)+       (False,True,EvenOdd,True) -> withShading td True sh r $ drawM (P.fillPathEO)+       (True,_,_,_) -> r >> drawM (P.strokePath) +       (_,_,_,_) -> r >> return ()   setLoop True -instance Backend Pdf R2 where-  data Render  Pdf R2 = D (DrawS ())-  type Result  Pdf R2 = Draw ()-  data Options Pdf R2 = PdfOptions {-      pdfsizeSpec :: SizeSpec2D-    } deriving(Show)-     -  -- There is something I don't understand here with the frozen style.-  -- On the tests it is working but I would not have put-  -- the calls in this order ... so it must be checked later   -  withStyle _ s t (D r) = D $ do+-- | Perform a rendering operation with a local style.+withStyle'     :: Style R2    -- ^ Style to use+               -> Transformation R2  -- ^ Transformation to be applied to the style+               -> Transformation R2 -- ^ Transformation that was applied to the diagram+               -> Render Pdf R2 -- ^ Rendering operation to run+               -> Render Pdf R2 -- ^ Rendering operation using the style locally+withStyle' s t td (D r) = D $ do     withContext $ do        pdfMiscStyle s        mf <- mustFill@@ -321,38 +294,50 @@           pdfFrozenStyle s           when (mf || ms) $ do              withPdfOpacity s $ do-               r-               strokeOrFill+               strokeOrFill (td) r +instance Backend Pdf R2 where+  data Render  Pdf R2 = D (DrawS ())+  type Result  Pdf R2 = Draw ()+  data Options Pdf R2 = PdfOptions {+      pdfsizeSpec :: SizeSpec2D+    } deriving(Show)+     +  -- There is something I don't understand here with the frozen style.+  -- On the tests it is working but I would not have put+  -- the calls in this order ... so it must be checked later   +  withStyle _ s t (D r) = withStyle' s t mempty (D r)+   doRender _ _ (D r) = setTranform (runDS r)    renderDia Pdf opts d =-    centerAndScale opts d . doRender Pdf opts' . mconcat . map renderOne . prims $ d'+    centerAndScale d' . doRender Pdf opts' . mconcat . map renderOne . prims $ d'       where (opts', d') = adjustDia Pdf opts d             renderOne :: (Prim Pdf R2, (Split (Transformation R2), Style R2))                       -> Render Pdf R2             renderOne (p, (M t,      s))-              = withStyle Pdf s mempty (render Pdf (transform t p))+              = withStyle' s mempty t (render Pdf (transform t p))              renderOne (p, (t1 :| t2, s))               -- Here is the difference from the default               -- implementation: "t2" instead of "t1 <> t2".-              = withStyle Pdf s t1 (render Pdf (transform t2 p))-            centerAndScale opts diag renderedDiagram  = do+              = withStyle' s t1 t2 (render Pdf (transform t2 p))+            centerAndScale diag renderedDiagram  = do                 let bd = boundingBox diag                     (w,h) = sizeFromSpec (pdfsizeSpec opts)                     rescaledD (Just (ll,ur)) =                                 let (vx,vy) = unp2 $ centroid [ll,ur]                                     (xa,ya) = unp2 ll                                      (xb,yb) = unp2 ur -                                    ps = max (abs (xb - xa)) (abs (yb - ya))-                                    sx = w / ps-                                    sy = h / ps+                                    --ps = max (abs (xb - xa)) (abs (yb - ya))+                                    sx = w / (abs (xb - xa))+                                    sy = h / abs (yb - ya)+                                    s = min sx sy                                     pageCenter = (w / 2.0) P.:+ (h/2.0)                                 in                                 do                                   P.applyMatrix (P.translate pageCenter) -                                  P.applyMatrix (P.scale sx sy)+                                  P.applyMatrix (P.scale s s)                                   P.applyMatrix (P.translate $ (-vx) P.:+ (-vy))                     rescaledD Nothing = return ()                 rescaledD (getCorners bd)@@ -431,11 +416,34 @@   setFillingColor a  pdfStrokeColor :: (Real b, Floating b) => AlphaColour b -> DrawS ()-pdfStrokeColor c = drawM $ do-  let (r,g,b,a) = colorToSRGBA c-  P.setStrokeAlpha a-  P.strokeColor (Rgb r g b)+pdfStrokeColor c = do+  drawM $ do+     let (r,g,b,a) = colorToSRGBA c+     P.setStrokeAlpha a+     P.strokeColor (Rgb r g b) +setShadingData :: Maybe PDFShading -> DrawS () +setShadingData sh = do +  StateStack s l <- S.get+  S.put $! StateStack (s {_shading = sh, _mustFill = _mustFill s || isJust sh}) l++setShading :: PdfShadingData -> DrawS ()+setShading (PdfAxialShadingData pa pb ca cb) = do +  let (ra,ga,ba,_) = colorToSRGBA ca+      (rb,gb,bb,_) = colorToSRGBA cb +      colora = Rgb ra ga ba +      colorb = Rgb rb gb bb+      (xa,ya) = unp2 pa +      (xb,yb) = unp2 pb +  setShadingData $ Just (AxialShading xa ya xb yb colora colorb)+setShading (PdfRadialShadingData pa radiusa pb radiusb ca cb) = do +  let (ra,ga,ba,_) = colorToSRGBA ca+      (rb,gb,bb,_) = colorToSRGBA cb +      colora = Rgb ra ga ba +      colorb = Rgb rb gb bb+      (xa,ya) = unp2 pa +      (xb,yb) = unp2 pb +  setShadingData $ Just $ RadialShading xa ya radiusa xb yb radiusb colora colorb {-  Conversions between diagrams and HPDF types@@ -508,6 +516,7 @@                           , handle lColor                           , handle lFillRule                           , handle checklWidth+                          , handle shading                           ]   where handle :: AttributeClass a => (a -> DrawS ()) -> Maybe (DrawS ())         handle f = f `fmap` getAttr s@@ -518,6 +527,7 @@         lColor c = pdfStrokeColor . toAlphaColour . getLineColor $ c         fColor c = pdfFillColor . toAlphaColour . getFillColor $ c         lFillRule = setFillRule . getFillRule+        shading = setShading . getShadingData         checklWidth w = do            let d = getLineWidth w           setTrokeState d@@ -547,7 +557,16 @@ unP r = let (x,y) = unp2 r  in (x :+ y) +--showTrans :: Transformation R2 -> String +--showTrans t = show a1 ++ " " ++ show b1 ++ " " ++ show c1 ++ "\n" +++--              show a2 ++ " " ++ show b2 ++ " " ++ show c2 ++ "\n"+--   where (a1,a2) = unr2 $ apply t unitX+--         (b1,b2) = unr2 $ apply t unitY+--         (c1,c2) = unr2 $ transl t +--instance Show (Transformation R2) where +--  show = showTrans+ pdfTransf :: Transformation R2 -> DrawS () pdfTransf t = drawM $ applyMatrix (Matrix a1 a2 b1 b2 c1 c2)   where (a1,a2) = unr2 $ apply t unitX@@ -596,4 +615,228 @@               P.applyMatrix (P.translate (x' :+ y'))               P.drawText $ P.text theFont 0 0 (toPDFString str)             +{- +Rendering of specific HPDF primitives++-}++instance Renderable PdfTextBox Pdf where+  render _ (PdfTextBox t w h para) = D $ do+    withContext $ do+       pdfTransf t+       drawM (drawStringLabel w h para)++-- | Typeset a text with a given style in a suggested box.+-- The function is returning a diagram for the typeset text+-- and a diagram for the bounding box which may be smaller+-- than the suggested size : smaller width when the algorithm+-- has done some line justification. +-- The text may also be bigger than the suggested width in case+-- of overflow (similar to the way TeX is doing thing. There are+-- settings in HPDF to control the elegance of the line cuts but+-- those settings are not accessible from this simple API).+-- The text will not be longer than the suggested height. In that+-- case the additional text is not displayed.+genericPdfText :: (Renderable PdfTextBox Pdf,Renderable (Path R2) Pdf) +               => Bool -- ^ Suggested size +               -> TextOrigin+               -> Double -- ^ Suggested width+               -> Double -- ^ Suggested height+               -> AnyFormattedParagraph+               -> (Diagram Pdf R2,Diagram Pdf R2) -- ^ Text and bounding rect of the typeset text+genericPdfText suggested o w h formatted = +    let diag = mkQD (Prim (PdfTextBox mempty w h formatted))+                    (getEnvelope r)+                    (getTrace r)+                    mempty+                    (Query $ \p -> Any (isInsideEvenOdd p r))+        f v = (moveOriginTo v diag, moveOriginTo v textBounds)+    in+    case o of +            LeftSide -> f east +                  where +                    east = p2 (0,-hlinewrap / 2.0)+            RightSide -> f west +                  where +                    west = p2 (wlinewrap,-hlinewrap / 2.0)+            Center -> f theCenter+                  where +                    theCenter = p2 (wlinewrap / 2.0,-hlinewrap / 2.0)+            TopSide -> f topSide +                  where +                    topSide = p2 (wlinewrap / 2.0,0)+            BottomSide -> f bottomSide +                  where +                    bottomSide = p2 (wlinewrap / 2.0,-hlinewrap)+            TopLeftCorner -> f topLeft +                  where +                    topLeft = p2 (0,0)+            BottomLeftCorner -> f bottomLeft+                  where +                    bottomLeft = p2 (0,-hlinewrap )+            TopRightCorner -> f topRight+                  where +                    topRight = p2 (wlinewrap,0)+            BottomRightCorner -> f bottomRight+                  where +                    bottomRight = p2 (wlinewrap,-hlinewrap )+        +  where wlinewrap :: Double +        hlinewrap :: Double+        Rectangle (xa :+ ya) (xb :+ yb) | suggested = matchingContainerSize w h formatted+                                        | otherwise = Rectangle (0 :+ 0) (w :+ h)+        wlinewrap = xb - xa+        hlinewrap = yb - ya+   +        r :: Path R2+        r = rect wlinewrap hlinewrap # moveOriginTo (p2 (-wlinewrap / 2.0,hlinewrap / 2.0))+        textBounds :: Diagram Pdf R2+        textBounds = Sh.rect wlinewrap hlinewrap # moveOriginTo (p2 (-wlinewrap / 2.0,hlinewrap / 2.0))++-- | Typeset a text with a given style in a suggested box.+-- The function is returning a diagram for the text+-- and a diagram for the bounding box which may be smaller+-- than the suggested size : smaller width when the algorithm+-- has done some line justification. +-- The text may also be bigger than the suggested width in case+-- of overflow (similar to the way TeX is doing thing. There are+-- settings in HPDF to control the elegance of the line cuts but+-- those settings are not accessible from this simple API).+-- The text will not be longer than the suggested height. In that+-- case the additional text is not displayed except perhaps partially the last+-- line since no clipping is done.+pdfLabelWithSuggestedSize :: (Renderable PdfTextBox Pdf,Renderable (Path R2) Pdf) +                          => LabelStyle -- ^ Style of the label+                          -> String -- ^ String to display with this style+                          -> Double -- ^ Suggested width+                          -> Double -- ^ Suggested height+                          -> (Diagram Pdf R2,Diagram Pdf R2) -- ^ Text and bounding rect of the typeset text+pdfLabelWithSuggestedSize (LabelStyle fn fs j o fillc) s w h = +  let pdfColor (r,g,b,_) = P.Rgb r g b+      pdffc = pdfColor . colorToSRGBA . toAlphaColour $ fillc +  in+  genericPdfText True o w h $ (AFP NormalParagraph (P.Font (PDFFont fn fs) pdffc pdffc) $ do +    setJustification j+    paragraph $ do+        txt $ s)++-- | Similar to the @pdfLabelWithSuggestedSize@ but supporting the full features of HPDF+pdfTextWithSuggestedSize :: (ParagraphStyle ps s, P.Style s,Renderable PdfTextBox Pdf,Renderable (Path R2) Pdf) +                         => TextOrigin -- ^ Text origin+                         -> Double -- ^ Suggested width+                         -> Double -- ^ Suggested height+                         -> ps -- ^ Paragraph (vertical) style+                         -> s  -- ^ Horizontal style+                         -> TM ps s () -- ^ Text+                         -> (Diagram Pdf R2,Diagram Pdf R2) -- ^ Text and bounding rect of the typeset text+pdfTextWithSuggestedSize o w h ps hs tm = genericPdfText True o w h (AFP ps hs tm)++-- | Similar to the @pdfLabelWithSuggestedSize@ but here the size is forced and even+-- if the bounding box of the text is smaller it will not be taken into account+-- for the diagram envelope.+pdfLabelWithSize :: (Renderable PdfTextBox Pdf,Renderable (Path R2) Pdf) +                 => LabelStyle -- ^ Style of the label+                 -> String -- ^ String to display with this style+                 -> Double -- ^ Suggested width+                 -> Double -- ^ Suggested height+                 -> Diagram Pdf R2 -- ^ Text+pdfLabelWithSize (LabelStyle fn fs j o fillc) s w h = +  let pdfColor (r,g,b,_) = P.Rgb r g b+      pdffc = pdfColor . colorToSRGBA . toAlphaColour $ fillc +  in+  fst $ genericPdfText False o w h $ (AFP NormalParagraph (P.Font (PDFFont fn fs) pdffc pdffc) $ do +    setJustification j+    paragraph $ do+        txt $ s)++-- | Similar to @pdfTextWithSuggestedSize@ but the size if forced and not just suggested+pdfTextWithSize :: (ParagraphStyle ps s, P.Style s,Renderable PdfTextBox Pdf,Renderable (Path R2) Pdf) +                => TextOrigin -- ^ Text origin+                -> Double -- ^ Suggested width+                -> Double -- ^ Suggested height+                -> ps -- ^ Paragraph (vertical) style+                -> s  -- ^ Horizontal style+                -> TM ps s () -- ^ Text+                -> Diagram Pdf R2 -- ^ Text+pdfTextWithSize o w h ps hs tm = fst $ genericPdfText False o w h (AFP ps hs tm)++instance Renderable PdfImage Pdf where+  render _ (PdfImage t ref) = D $ do+    withContext $ do+       pdfTransf t+       drawM . drawXObject $ ref ++-- | Create an image diagram+pdfImage :: (Monad m, PDFGlobals m)+         => PDFReference PDFJpeg -- ^ Reference to the Jpeg image in the PDF resources+         -> m (Diagram Pdf R2)+pdfImage ref = do +    (w,h) <- P.bounds ref+    let r :: Path R2+        r = rect w h # moveOriginTo (p2 (-w/2, h/2.0))+        diag = mkQD (Prim (PdfImage mempty ref))+                    (getEnvelope r)+                    (getTrace r)+                    mempty+                    (Query $ \p -> Any (isInsideEvenOdd p r))+    return (diag # moveOriginTo (p2 (w/2.0,h/2.0)))++instance Renderable PdfURL Pdf where+  render _ (PdfURL t url w h) = D $ do+    withContext $ do+       pdfTransf t+       drawM $ do +        newAnnotation (URLLink (toPDFString "diagrams link") [0,0,w,h] url True)++-- | Create an URL diagram+pdfURL :: String -- ^ URL (in a next version it should be URI)+       -> Double -- ^ Width of active area+       -> Double -- ^ Height of active area+       -> Diagram Pdf R2 +pdfURL url w h = +  let r = rect w h # moveOriginTo (p2 (-w/2, h/2.0))+      diag = mkQD (Prim (PdfURL mempty url w h))+                    (getEnvelope r)+                    (getTrace r)+                    mempty+                    (Query $ \p -> Any (isInsideEvenOdd p r))+  in +  diag # moveOriginTo (p2 (w/2.0,h/2.0))+++-- To avoid an Orphan instance warning for Transformable PDFShading+newtype TransSh =TransSh {unTrans :: PDFShading}++type instance V TransSh = R2++instance Transformable TransSh where +    transform t (TransSh (AxialShading xa ya xb yb ca cb)) = TransSh $ AxialShading xa' ya' xb' yb' ca cb +      where +        (xa',ya') = unp2 . transform t $ p2 (xa,ya)+        (xb',yb') = unp2 . transform t $ p2 (xb,yb)+    transform t (TransSh (RadialShading xa ya ra xb yb rb ca cb)) = TransSh $ RadialShading xa' ya' ra xb' yb' rb ca cb +      where +        (xa',ya') = unp2 . transform t $ p2 (xa,ya)+        (xb',yb') = unp2 . transform t $ p2 (xb,yb)+       +{-++Paragraph shapes ++-}++{-    +data EnvelopedPara v = EnvelopedPara (Envelope R2) v++instance ComparableStyle v => ComparableStyle (EnvelopedPara v) where +  isSameStyleAs (EnvelopedPara _ va) (EnvelopedPara _ vb) = isSameStyleAs va vb ++instance (ComparableStyle v,P.Style s, ParagraphStyle v s) => ParagraphStyle (EnvelopedPara v) s where +   linePosition (EnvelopedPara _ v) = P.linePosition v+   lineWidth (EnvelopedPara _ v) = P.lineWidth v+   interline (EnvelopedPara _ v) = P.interline v+   paragraphChange (EnvelopedPara a v) i l = let (np,r) = P.paragraphChange v i l in (EnvelopedPara a np,r)+   paragraphStyle (EnvelopedPara _ v) = P.paragraphStyle v++-}
+ src/Diagrams/Backend/Pdf/Specific.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE FlexibleContexts          #-}+{-# LANGUAGE DeriveDataTypeable        #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ExistentialQuantification #-}+module Diagrams.Backend.Pdf.Specific(+      LabelStyle(..)+    , PdfTextBox(..)+    , drawStringLabel+    , getTextBoundingBox+    , TextOrigin(..)+    , LabelSize+    , PdfImage(..)+    , PdfURL(..)+    , PdfShadingData(..)+    , getShadingData+    , pdfAxialShading+    , pdfRadialShading+    , AnyFormattedParagraph(..)+    , CanBeFormatted(..)+    ) where ++import Graphics.PDF hiding(translate)+import qualified Graphics.PDF as P+import Diagrams.Prelude+import Data.Typeable++--import qualified Debug.Trace as T ++--debug a = T.trace (show a) a++data TextOrigin = Center +                | LeftSide +                | RightSide +                | TopSide +                | BottomSide +                | TopLeftCorner +                | TopRightCorner +                | BottomLeftCorner +                | BottomRightCorner +                deriving(Eq)++type LabelSize = Int++-- | Style for a label.+-- It is not considered as an attribute but as a different primitive+-- because internaly it is a complex text which can support several styles +-- in the same paragraph. +-- Label is just a convenience wrapper when the full features are not needed+data LabelStyle = LabelStyle FontName LabelSize Justification TextOrigin (Colour Double)++data PdfTextBox = PdfTextBox { _transform :: T2 +                             , _suggestedWidth :: Double +                             , _suggestedHeight :: Double +                             , _paragraph :: AnyFormattedParagraph+                             }++type instance V PdfTextBox = R2++instance Transformable PdfTextBox where+  transform t (PdfTextBox tt sw sh para) = PdfTextBox (t <> tt) sw sh para++instance IsPrim PdfTextBox++instance HasOrigin PdfTextBox where+  moveOriginTo p = translate (origin .-. p)++instance Renderable PdfTextBox NullBackend where+  render _ _ = mempty++data PdfImage = PdfImage T2 (PDFReference PDFJpeg)++type instance V PdfImage = R2++instance Transformable PdfImage where+  transform t (PdfImage tt ref) = PdfImage (t <> tt) ref++instance IsPrim PdfImage++instance HasOrigin PdfImage where+  moveOriginTo p = translate (origin .-. p)++instance Renderable PdfImage NullBackend where+  render _ _ = mempty++data PdfURL = PdfURL T2 String Double Double ++type instance V PdfURL = R2++instance Transformable PdfURL where+  transform t (PdfURL tt s w h) = PdfURL (t <> tt) s w h++instance IsPrim PdfURL++instance HasOrigin PdfURL where+  moveOriginTo p = translate (origin .-. p)++instance Renderable PdfURL NullBackend where+  render _ _ = mempty++drawStringLabel :: PDFFloat +                -> PDFFloat +                -> AnyFormattedParagraph+                -> Draw () +drawStringLabel w h para = typesetText w h para++data AnyFormattedParagraph = forall s ps. (ParagraphStyle ps s, P.Style s) => AFP ps s (TM ps s ())++class CanBeFormatted m where +  putIntoContainer :: Double -> Double -> m -> Draw ()+  matchingContainerSize :: Double -> Double -> m -> Rectangle++instance CanBeFormatted AnyFormattedParagraph where +  putIntoContainer w h (AFP ps p t) = +    let b = getBoxes ps p t+        sh = styleHeight p+        c = mkContainer 0 0 w h sh+        (d,_,_) = fillContainer (defaultVerState ps) c b+    in +    d+  matchingContainerSize w h (AFP ps p t) = +    let b = getBoxes ps p t+        sh = styleHeight p+        c = mkContainer 0 0 w h sh+        (_,c',_) = fillContainer (defaultVerState ps) c b+    in +    containerContentRectangle  c'++typesetText :: PDFFloat -- ^ width limit+            -> PDFFloat -- ^ height limit+            -> AnyFormattedParagraph+            -> P.Draw ()+typesetText w h para = putIntoContainer w h para++getTextBoundingBox :: PDFFloat -- ^ width limit+                   -> PDFFloat -- ^ height limit+                   -> AnyFormattedParagraph+                   -> Rectangle+getTextBoundingBox w h para  = matchingContainerSize w h para++data PdfShadingData = PdfAxialShadingData P2 P2 (Colour Double) (Colour Double) +                    | PdfRadialShadingData P2 Double P2 Double (Colour Double) (Colour Double) deriving (Show,Typeable)+newtype PdfShading = PdfShading (Last PdfShadingData) deriving (Typeable, Semigroup)++instance AttributeClass PdfShading++getShadingData :: PdfShading -> PdfShadingData+getShadingData (PdfShading (Last c)) = c++addshading :: (HasStyle a) => PdfShadingData -> a -> a+addshading s = applyAttr (PdfShading . Last $ s)+++-- | Define Axial shading for a diagram+pdfAxialShading :: HasStyle a => P2 -> P2 -> Colour Double -> Colour Double -> a -> a+pdfAxialShading pa pb ca cb = addshading (PdfAxialShadingData pa pb ca cb)++-- | Define Radial shading for a diagram+pdfRadialShading :: HasStyle a +                 => P2 -- ^ Center of inner circle+                 -> Double -- ^ Radius of inner circle+                 -> P2 -- ^ Center of outer circle+                 -> Double -- ^ Radius of outer circle+                 -> Colour Double -- ^ Inner colour+                 -> Colour Double -- ^ Outer colour+                 -> a -> a+pdfRadialShading pa ra pb rb ca cb = addshading (PdfRadialShadingData pa ra pb rb ca cb)
+ test/Makefile view
@@ -0,0 +1,11 @@+all:+	ghc -o mytest --make test.hs -package-db ../dist/package.conf.inplace ++clean:+	rm -f mytest +	rm -f *.o +	rm -f *.hi+	rm -f *.pdf++run:+	./mytest --compressed -o circle.pdf
+ test/logo.jpg view

binary file changed (absent → 2745 bytes)

+ test/test.hs view
@@ -0,0 +1,308 @@+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiParamTypeClasses #-}+import Diagrams.Prelude+import Diagrams.Backend.Pdf+import Diagrams.Backend.Pdf.CmdLine+import Data.Colour (withOpacity)+import Graphics.PDF hiding(scale,red,green,blue,white,black,text,rotate,rect,stroke)+import qualified Diagrams.Backend.SVG.CmdLine as S+import qualified Diagrams.Example.Logo as L+import           Diagrams.Coordinates ((&))+import qualified Graphics.PDF.Typesetting as T+import qualified Graphics.PDF as P+import System.Random++pageWidth = 600 +pageHeight = 400 +titleH = 50++data MyParaStyles = Normal+                  | Bold+                  | Crazy+                  | SuperCrazy [Int] [PDFFloat]+                  | DebugStyle+                  | RedRectStyle+                  | BlueStyle+                  +instance ComparableStyle MyParaStyles where+  isSameStyleAs Normal Normal = True+  isSameStyleAs Bold Bold = True+  isSameStyleAs Crazy Crazy = True+  isSameStyleAs (SuperCrazy _ _) (SuperCrazy _ _) = True+  isSameStyleAs DebugStyle DebugStyle = True+  isSameStyleAs RedRectStyle RedRectStyle = True+  isSameStyleAs BlueStyle BlueStyle = True+  isSameStyleAs _ _ = False+  +                  +instance T.Style MyParaStyles where+    textStyle Normal = TextStyle (PDFFont Times_Roman 10) P.black P.black FillText 1.0 1.0 1.0 1.0+    textStyle Bold = TextStyle (PDFFont Times_Bold 12) P.black P.black FillText 1.0 1.0 1.0 1.0+    textStyle RedRectStyle = TextStyle (PDFFont Times_Roman 10) P.black P.black FillText 1.0 1.0 1.0 1.0+    textStyle DebugStyle = TextStyle (PDFFont Times_Roman 10) P.black P.black FillText 1.0 1.0 1.0 1.0+    textStyle Crazy = TextStyle (PDFFont Times_Roman 10) P.red P.red FillText 1.0 1.0 1.0 1.0+    textStyle (SuperCrazy _ _) = TextStyle (PDFFont Times_Roman 12) P.black P.black FillText 1.0 2.0 0.5 0.5+    textStyle BlueStyle = TextStyle (PDFFont Times_Roman 10) P.black P.black FillText 1.0 1.0 1.0 1.0+    +    sentenceStyle BlueStyle = Just $ \r d -> do+        P.fillColor $ Rgb 0.6 0.6 1+        P.strokeColor $ Rgb 0.6 0.6 1+        P.fillAndStroke r+        d+        return()+    +    sentenceStyle RedRectStyle = Just $ \r d -> do+        P.strokeColor P.red+        P.stroke r+        d+        return()+    sentenceStyle Crazy = Just $ \r d -> do+       d+       P.strokeColor P.blue+       P.stroke r+    sentenceStyle _ = Nothing+           +    wordStyle DebugStyle = Just $ \r m d ->+      case m of+          DrawWord -> d >> return ()+          DrawGlue -> d >> P.stroke r+    wordStyle Crazy = Just crazyWord+    wordStyle (SuperCrazy l _) = Just ws +     where+        ws _ DrawGlue _ = return ()+        ws (Rectangle (xa :+ ya) (xb :+ yb)) DrawWord drawWord = do+            let [a,b,c,d,e,f,g,h] :: [PDFFloat] = map (\x -> x / 16.0) . map fromIntegral . take 8 $ l+                --angle = head angl+                p = Polygon [ (xa-a) :+ (ya+b)+                            , (xb+c) :+ (ya+d)+                            , (xb+e) :+ (yb-f)+                            , (xa-g) :+ (yb-h)+                            , (xa-a) :+ (ya+b)+                            ]+            P.strokeColor P.red+            P.stroke p+            P.fillColor $ Rgb 0.8 1.0 0.8+            P.fill p+            withNewContext $ do+              --applyMatrix . rotate . Degree $ angle+              drawWord+            return ()++    wordStyle _ = Nothing+    +    updateStyle (SuperCrazy a b) = SuperCrazy (drop 8 a) (tail b)+    updateStyle a = a+    +    styleHeight r@(SuperCrazy _ _) = (getHeight . textFont . textStyle $ r) + 4.0+    styleHeight r = getHeight . textFont . textStyle $ r+    +    styleDescent r@(SuperCrazy _ _) = (getDescent . textFont . textStyle $ r) + 2+    styleDescent r = getDescent . textFont . textStyle $ r+    +crazyWord :: Rectangle -> StyleFunction -> Draw a -> Draw ()+crazyWord r@(Rectangle (xa :+ ya) (xb :+ yb)) DrawWord d = do+    P.fillColor $ Rgb 0.6 1 0.6 +    P.fill r+    d+    P.strokeColor $ Rgb 0 0 1+    let m = (ya+yb)/2.0+    P.stroke $ P.Line xa m xb m +crazyWord (Rectangle (xa :+ ya) (xb :+ yb)) DrawGlue _ = do+    P.fillColor $ Rgb 0 0 1+    P.fill (Circle ((xa+xb)/2.0) ((ya+yb)/2.0) ((xb-xa)/2.0))+    +   +    +superCrazy :: MyParaStyles+superCrazy = SuperCrazy (randomRs (0,32) (mkStdGen 0)) (randomRs (-10.0,10.0) (mkStdGen 10000))+    +data MyVertStyles = NormalPara+                  | CirclePara+                  | BluePara !PDFFloat++instance ComparableStyle MyVertStyles where+    isSameStyleAs NormalPara NormalPara = True+    isSameStyleAs CirclePara CirclePara = True+    isSameStyleAs (BluePara _) (BluePara _) = True+    isSameStyleAs _ _ = False+++instance ParagraphStyle MyVertStyles MyParaStyles  where+    lineWidth (BluePara a) w nb = (if nb > 3 then w else w-a) - 20.0+    lineWidth CirclePara _ nb = +           let nbLines = 15.0+               r = nbLines * (getHeight . textFont . textStyle $ Normal)+               pasin x' = if x' >= 1.0 then pi/2 else if x' <= -1.0 then (-pi/2) else asin x'+               angle l = pasin $ (nbLines - (fromIntegral l)  ) / nbLines+           in+           abs(2*r*cos (angle nb))+    lineWidth _ w _ = w+           +    linePosition (BluePara a) _ nb = (if nb > 3 then 0.0 else a) + 10.0+    linePosition a@(CirclePara) w nb = max 0 ((w - P.lineWidth a w nb) / 2.0)+    linePosition _ _ _ = 0.0+    +    interline (BluePara _) = Just $ \r -> do+        P.fillColor $ Rgb 0.6 0.6 1+        P.strokeColor $ Rgb 0.6 0.6 1+        P.fillAndStroke r+    interline _ = Nothing+        +    paragraphChange (BluePara _) _ (AChar st c _:l) = +        let f = PDFFont Helvetica_Bold 45+            w' = charWidth f c +            charRect = Rectangle (0 :+ (- getDescent f)) (w' :+ (getHeight f - getDescent f))+            c' = mkLetter (0,0,0) Nothing . mkDrawBox $ do+                withNewContext $ do+                    applyMatrix $ P.translate ((-w') :+ (getDescent f - getHeight f + styleHeight st - styleDescent st))+                    P.fillColor $ Rgb 0.6 0.6 1+                    P.strokeColor $ Rgb 0.6 0.6 1+                    P.fillAndStroke $ charRect+                    P.fillColor P.black+                    drawText $ do+                        renderMode AddToClip+                        textStart 0 0+                        setFont f+                        displayText (toPDFString [c])+                    paintWithShading (AxialShading 0 (- getDescent f) w' (getHeight f - getDescent f) (Rgb 1 0 0) (Rgb 0 0 1)) (addShape charRect)+        in+        (BluePara w', c':l)+    +    paragraphChange s _ l = (s,l)+    +    paragraphStyle (BluePara _) = Just $ \(Rectangle (xa :+ ya) (xb :+ yb)) b -> do+        let f = Rectangle ((xa-3) :+ (ya-3)) ((xb+3) :+ (yb+3))+        P.fillColor $ Rgb 0.6 0.6 1+        P.fill f+        b+        P.strokeColor P.red+        P.stroke f+        return ()+    paragraphStyle _ = Nothing+ +standardStyleTest :: TM MyVertStyles MyParaStyles ()+standardStyleTest = do+    paragraph $ do+        txt $ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut "+        txt $ "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "+        setStyle Crazy+        txt $ "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "+        txt $ "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "+        txt $ "proident, sunt in culpa qui officia deserunt mollit anim id est laborum."+ ++complexText = +  centerXY (fst (pdfTextWithSuggestedSize Center 400 200 NormalPara Normal standardStyleTest) +    ===+    strutY 20 +    ===+    fst (pdfTextWithSuggestedSize Center 300 200 NormalPara Normal standardStyleTest) # rotate (20 :: Deg)+  )+  <> rect pageWidth (pageHeight - titleH)++t s x j = +    let (td, rd) = pdfLabelWithSuggestedSize (LabelStyle Times_Roman 12 j x blue) s 50 100 +    in +    td # showOrigin # lw 0.03  <> rd++tfs s x j = +    let td = pdfLabelWithSize (LabelStyle Times_Roman 12 j x blue) s 50 50 +    in +    td # showOrigin # lw 0.03 ++testpdfsuggestedtextsize = centerXY $ (centerXY squareText) <> rect pageWidth (pageHeight - titleH)+ where +  squareText = (t "Top Left" TopLeftCorner LeftJustification ||| t "Top" TopSide Centered ||| t "Top Right" TopRightCorner RightJustification)+               ===+               (t "Left" LeftSide LeftJustification ||| t "Center" Center Centered ||| t "Right" RightSide RightJustification)+               ===+               (t "Bottom Left" BottomLeftCorner LeftJustification ||| t "Bottom" BottomSide Centered ||| t "Bottom Right" BottomRightCorner RightJustification)+  +testpdftextsize = centerXY $ (centerXY squareText) <> rect pageWidth (pageHeight - titleH)+ where +  squareText = (tfs "Top Left" TopLeftCorner LeftJustification ||| tfs "Top" TopSide Centered ||| tfs "Top Right" TopRightCorner RightJustification)+               ===+               (tfs "Left" LeftSide LeftJustification ||| tfs "Center" Center Centered ||| tfs "Right" RightSide RightJustification)+               ===+               (tfs "Bottom Left" BottomLeftCorner LeftJustification ||| tfs "Bottom" BottomSide Centered ||| tfs "Bottom Right" BottomRightCorner RightJustification)+  ++ +testShading = +   let loopyStar = fc red+                 . mconcat . map (cubicSpline True)+                 . pathVertices+                 . star (StarSkip 3)+                 $ regPoly 7 1+       f z d = +        let s = 20+        in+        loopyStar # scale s # fillRule z # pdfAxialShading (p2 (-1,-1)) (p2 (1,1)) red green # rotate (d :: Deg)+   in   centerXY (hcat (map (f Winding) [0,20,40,60,80,100,120,140,160]))+        === centerXY (hcat (map (f EvenOdd) [0,20,40,60,80,100,120,140,160]))+        === square 40 # pdfRadialShading (p2 (0,0)) 5 (p2 (0,0)) 40 blue red++testImage img = +    let url = "http://www.alpheccar.org" +    in +       circle 100 +    <> mconcat (map (\r -> img # scale 0.5 # translateX 100 # rotate r) ([0,20..360] :: [Deg]))+    <> pdfURL url 100 20 +    <> fst (pdfLabelWithSuggestedSize (LabelStyle Times_Roman 12 Centered Center blue) url 150 40)++mkSection s sect = +    let (d,_) = pdfLabelWithSuggestedSize (LabelStyle Times_Roman 36 Centered Center blue) s pageWidth pageHeight +    in do+      page1 <- addPage Nothing+      drawWithPage page1 $ do+        renderDia Pdf (PdfOptions (Dims pageWidth pageHeight)) d+      sect++page s d = header s === content d + where +  header s = +    let (d,_) = pdfLabelWithSuggestedSize (LabelStyle Times_Roman 24 Centered Center black) s pageWidth titleH +    in +    d <> (rect pageWidth titleH # pdfAxialShading (p2 (-pageWidth/2,-titleH/2)) (p2 (pageWidth/2,titleH/2)) blue white)+  clipRect :: Path R2+  clipRect =  rect pageWidth (pageHeight - titleH) +  clipRectDiag :: Diagram Pdf R2 +  clipRectDiag = stroke clipRect+  content d = (clipRectDiag # lw 0 <> (centerXY d)) # clipBy clipRect # withEnvelope clipRectDiag+  ++mkPage :: String -> Diagram Pdf R2 -> PDF ()+mkPage s d = do +  page1 <- addPage Nothing+  drawWithPage page1 $ do+        renderDia Pdf (PdfOptions (Dims pageWidth pageHeight)) $ page s d++testShadeFroz = do+  page1 <- addPage Nothing+  drawWithPage page1 $ do+    renderDia Pdf (PdfOptions (Dims pageWidth pageHeight)) $ +        w +  where +    w :: Diagram Pdf R2 +    w = rect pageWidth (pageHeight - titleH) <> centerXY (+       square 100 # pdfAxialShading (p2 (-50,-50)) (p2 (50,50)) blue white+       ===+       square 100 # rotate (45 :: Deg) # freeze # pdfAxialShading (p2 (-50,-50)) (p2 (50,50)) blue white+    +        )++main = do+  Right jpgf <- readJpegFile "logo.jpg" +  let theDocRect = PDFRect 0 0 pageWidth pageHeight+  runPdf "demo.pdf" (standardDocInfo { author=toPDFString "alpheccar", compressed = False}) theDocRect $ do+      testShadeFroz+      --mkSection "HPDF Specific Primitives" $ do+      --     jpg <- createPDFJpeg jpgf+      --     image <- pdfImage jpg+      --     mkPage "Test JPEG and URL" (testImage image)+      --     mkPage "Test Shading" testShading+      --     mkPage "Test Suggested Text Container Size" testpdfsuggestedtextsize+      --     mkPage "Test Forced Text Container Size" testpdftextsize+      --     mkPage "Text Complex Text" complexText+--