poppler-0.12.0: demo/PdfViewer.hs
-- | PDF viewer demo
-- Author : Andy Stewart
-- Copyright : (c) 2010 Andy Stewart <lazycat.manatee@gmail.com>
-- | The PDF viewer base on poppler library.
--
-- Usage:
-- pdfviewer file
--
module Main where
import Control.Applicative
import Control.Concurrent.STM
import Control.Monad
import Data.Maybe
import Graphics.Rendering.Cairo
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Gdk.EventM
import Graphics.UI.Gtk.Poppler.Document
import Graphics.UI.Gtk.Poppler.Page
import System.Environment
import System.Process
data Viewer =
Viewer {viewerArea :: DrawingArea
,viewerDocument :: Document
,viewerScrolledWindow:: ScrolledWindow
,viewerPage :: TVar Int}
-- | Main entry.
main :: IO ()
main = do
-- Get program arguments.
args <- getArgs
case args of
-- Display help
["--help"] ->
putStrLn $ "PDF viewer demo. \n\n" ++
"Usage: pdfviewer file\n\n"
-- Start program.
[arg] -> viewerMain arg
_ -> putStrLn "Usage: pdfviewer file"
-- | Internal browser fucntion.
viewerMain :: FilePath -> IO ()
viewerMain file = do
-- Init.
initGUI
-- Create window.
window <- windowNew
windowSetDefaultSize window 600 780
windowSetPosition window WinPosCenter
-- Create window box.
windowBox <- vBoxNew False 0
window `containerAdd` windowBox
-- Create viewer.
viewer <- viewerNew file
let area = viewerArea viewer
doc = viewerDocument viewer
sWin = viewerScrolledWindow viewer
-- Set title.
title <- get doc documentTitle
windowSetTitle window ("PdfViewer " ++ title)
-- Create spin button to select page.
pages <- documentGetNPages doc -- get maximum page
spinButton <- spinButtonNewWithRange 0 (integralToDouble pages) 1.0
-- Redraw viewer after change value of spin button.
afterValueSpinned spinButton $ do
page <- spinButtonGetValue spinButton
writeTVarIO (viewerPage viewer) (truncate page)
widgetQueueDraw area
-- Show.
boxPackStart windowBox sWin PackGrow 0
boxPackStart windowBox spinButton PackNatural 0
window `onDestroy` mainQuit
widgetShowAll window
mainGUI
viewerNew :: FilePath -> IO Viewer
viewerNew file = do
area <- drawingAreaNew
doc <- liftM (fromMaybe (error "Error when open pdf file.")) (documentNewFromFile ("file://" ++ file) Nothing)
sWin <- scrolledWindowNew Nothing Nothing
page <- newTVarIO 0
let viewer = Viewer area doc sWin page
scrolledWindowAddWithViewport sWin area
scrolledWindowSetPolicy sWin PolicyAutomatic PolicyAutomatic
area `on` exposeEvent $ tryEvent $ viewerDraw viewer
return viewer
viewerDraw :: Viewer -> EventM EExpose ()
viewerDraw viewer = do
let doc = viewerDocument viewer
area = viewerArea viewer
(winWidth, winHeight) <- eventWindowSize
liftIO $ do
pageNumber <- readTVarIO $ viewerPage viewer
page <- documentGetPage doc pageNumber
frameWin <- widgetGetDrawWindow area
(docWidth, docHeight) <- pageGetSize page
let scaleX = winWidth / docWidth
width = winWidth
height = scaleX * docHeight
widgetSetSizeRequest area (truncate width) (truncate height)
renderWithDrawable frameWin $ do
setSourceRGB 1.0 1.0 1.0
scale scaleX scaleX
pageRender page
eventWindowSize :: EventM EExpose (Double, Double)
eventWindowSize = do
dr <- eventWindow
(w,h) <- liftIO $ drawableGetSize dr
return $ if w * h > 1
then (fromIntegral w, fromIntegral h)
else (1,1)
-- | Transform Int to Doube
integralToDouble :: Integral a => a -> Double
integralToDouble v = fromIntegral v :: Double
-- | The IO version of `writeTVar`.
writeTVarIO :: TVar a -> a -> IO ()
writeTVarIO a b = atomically $ writeTVar a b