PDF Viewer with smooth scrolling (not a big project =p )

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

PDF Viewer with smooth scrolling (not a big project =p )

Post by KristopherWindsor »

Somewhat annoyed that the popular PDF format can't be viewed without something as simple as smooth scrolling, I decided to make my own PDF Viewer, and it was easier than I thought it would be. ;)
While Acrobat can display plain-text pages OK, it slows for images, and slow as you scroll between pages.

My program uses a PDF-to-BMP converter, so I avoided the impossible task of dealing directly with the PDF format. (Unfortunately the demo of this program puts a watermark on every page.)

It loads the bitmaps into a FBGFX screen, and has separate threads for displaying and loading, so it shouldn't seem slow at all, although it takes 1-2 seconds for each page to load.

I was experimenting with some scrolling options: if you move the mouse to the left side of the screen, you can scroll just by moving the mouse vertically. Maybe it's not practical, but it's interesting.

Of course using BMP files to load pages is inefficient, loading all the pages into memory at once is not practical for some computers, this assumes all pages are a certain size (8.5" * 11", portrait), and many features such as zooming aren't implemented, but this program has smooth scrolling! :P

Code: Select all

' PDFViewer! v1.0
' (C) 2009 Kristopher Windsor and Innova

#Include "windows.bi"
#include once "fbgfx.bi"

Function RunProc(filename As String, params As String = "", workdir As String = "") As PROCESS_INFORMATION
        Dim si As STARTUPINFO, pi As PROCESS_INFORMATION
        si.cb = Sizeof(STARTUPINFO)
        Dim wd As Zstring Ptr
        If Len(workdir) Then wd = Strptr(workdir)
        Var cl = """" & filename & """ " & params
        CreateProcess(Strptr(filename), Strptr(cl), NULL, NULL, FALSE, 0, NULL, wd, @si, @pi)
        Return pi
End Function

Function IsProcRunning(pi As PROCESS_INFORMATION) As Boolean
        Dim exitcode As Integer
        GetExitCodeProcess(pi.hProcess, @exitcode)
        Return (exitcode = STILL_ACTIVE)
End Function

Const page_max = 512, page_x = 1024, page_y = 1500, scroll_x = 96

Dim Shared As Integer screen_x, screen_y
Dim Shared As Integer page_loadprogress(1 To page_max) '0 = not loaded, 1 = loading, 2 = done, 3 = error (does not exist)
Dim Shared As String file
Dim Shared As fb.image Ptr page(1 To page_max)
Dim Shared As Any Ptr mutex

Sub load (Byval nada As Any Ptr = 0)
  Dim As PROCESS_INFORMATION process
  Dim As Integer newpage
  Dim As String pagefile
  Dim As fb.image Ptr graphic
  
  Do
    
    'find a page to load
    Mutexlock(mutex)
    newpage = 0
    For i As Integer = 1 To page_max
      If page_loadprogress(i) = 0 Then newpage = i: page_loadprogress(i) = 1: Exit For
    Next i
    Mutexunlock(mutex)
    If newpage = 0 Then Return
    pagefile = "page" & newpage & ".bmp"
    
    'make page
    Kill(pagefile)
    process = runProc("PDFtoBMP.exe", "-i """ & file & """ -o ./page" & newpage & ".bmp -b 24 -r 120 -f " & newpage & " -l " & newpage)
    
    'load page
    graphic = imagecreate(page_x, page_y)
    While isProcRunning(process): Sleep(300, 1): Wend
    If Bload(pagefile, graphic) Then
      Mutexlock(mutex)
      page_loadprogress(newpage) = 3
      Mutexunlock(mutex)
      imagedestroy(graphic)
      Return
    End If
    
    'publish page
    Mutexlock(mutex)
    page_loadprogress(newpage) = 2
    page(newpage) = graphic
    Mutexunlock(mutex)
    
  Loop
End Sub

Sub start ()
  file = Command()
  'If file = "" Then file = "./part1.pdf" 'for testing
  
  Chdir(Exepath())
  
  Screeninfo(screen_x, screen_y)
  Screenres screen_x, screen_y, 32,, fb.GFX_NO_FRAME Or fb.GFX_ALPHA_PRIMITIVES
  
  If file = "" Then Print "No file specified!": Sleep(): System()
  
  var t = Threadcreate(@load())
End Sub

Sub main ()
  Dim As Integer mx, my, ms, mb, pmx, pmy, pms, pmb
  Dim As Integer page_total, complete
  Dim As Double y, yv, yvv, document_y
  Dim As String s
  
  Do
    document_y += (page_total * page_y - document_y) * .1
    
    If complete = 0 Then
      Mutexlock(mutex)
      If page_loadprogress(page_total + 1) = 2 Then page_total += 1
      If page_total = page_max orelse page_loadprogress(page_total + 1) = 3 Then complete = 1
      Mutexunlock(mutex)
    End If
    
    pmx = mx: pmy = my: pms = ms: pmb = mb
    If Getmouse(mx, my, ms, mb) Then mb = 0
    
    yvv += (pms - ms) * 15
    
    'left bar: scroll without dragging
    If mx < scroll_x Then
      yvv += (my - pmy) * .3
    End If
    
    'right bar: drag scrollbar (no gliding)
    If mx > screen_x - scroll_x Then
      If (mb > 0 And pmb > 0) Then
        y = (my -scroll_x \ 2) * (document_y - screen_y) / (screen_y - scroll_x)
        yv = 0
        yvv = 0
      End If
    End If
    
    If (Multikey(fb.sc_down)) Then yvv += 1
    If (Multikey(fb.sc_up)) Then yvv -= 1
    If (Multikey(fb.sc_pagedown)) Then yvv += 10
    If (Multikey(fb.sc_pageup)) Then yvv -= 10
    
    yv += yvv
    y += yv
    yv *= .9
    yvv *= .9
    
    If y + screen_y > document_y Then y = document_y - screen_y: yv = 0: yvv = 0
    If y < 0 Then y = 0: yv = 0: yvv = 0
    
    Screenlock()
      Line (0, 0) - ((screen_x - page_x) \ 2, screen_y), &H22000000, BF
      Line -Step(page_x, -screen_y), &HFFFFFFFF, BF
      Line Step(0, 0) - (screen_x, screen_y), &H22000000, BF
      
      Mutexlock(mutex)
        For i As Integer = 1 To page_total
          Put ((screen_x - page_x) \ 2, (i - 1) * page_y - y), page(i), trans
        Next i
      Mutexunlock(mutex)
      
      s = Cint(yv) & "x"
      If complete = 0 Then s += " ..."
      Draw String (scroll_x \ 2 - 4 * Len(s), 3), s, &HFFFFFFFF
      
      s = Cint(y / page_y + 1) & " / " & page_total
      Circle (screen_x - scroll_x \ 2, Iif(page_total > 0, (screen_y - scroll_x) * y / (document_y - screen_y), 0#) + scroll_x \ 2), _
        scroll_x \ 2, &HFFFFFFFF,,, 1, F
      Circle Step(0, 0), scroll_x \ 2, &HFF000000,,, 1
      Draw String Step(-4 * Len(s), 0), s, &HFF000000
    Screenunlock()
    
    Sleep(15, 1)
  Loop Until Inkey = Chr(27)
End Sub

  
mutex = Mutexcreate()
start()
main()
Mutexdestroy(mutex)
Runnable program (with the PDF-to-BMP converter):
http://jafile.com/uploads/kristopherwin ... viewer.zip

A PDF file, in case you don't have one:
http://incubator.apache.org/thrift/stat ... 070401.pdf
Galeon
Posts: 563
Joined: Apr 08, 2009 5:30
Location: Philippines
Contact:

Post by Galeon »

XPDF is free and open source. It has a pdf2bmp utility, available in DOS, Linux and Windows.
Antoni
Posts: 1393
Joined: May 27, 2005 15:40
Location: Barcelona, Spain

Re: PDF Viewer with smooth scrolling (not a big project =p )

Post by Antoni »

KristopherWindsor wrote: While Acrobat can display plain-text pages OK, it slows for images, and slow as you scroll between pages.
Have you tried Foxit Reader?
It's free, it starts in a blink and it scrolls smoothly enough to me, images or not.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Re: PDF Viewer with smooth scrolling (not a big project =p )

Post by KristopherWindsor »

Antoni wrote:
KristopherWindsor wrote: While Acrobat can display plain-text pages OK, it slows for images, and slow as you scroll between pages.
Have you tried Foxit Reader?
It's free, it starts in a blink and it scrolls smoothly enough to me, images or not.
Yes I have. It might be faster than Acrobat, but the problem is still there. Of course, I understand why PDF reader can't pre-render everything like I am here (it hogs RAM), but if either Acrobat or Foxit had an option to render pages like this does, and cache up to 2GB worth of rendered pages, to make scrolling smoother, I would like it. :)
thesanman112
Posts: 538
Joined: Jul 15, 2005 4:13

hmmm

Post by thesanman112 »

doesn't adobe smooth scroll just by clicking on the page and moving the mouse??? mine does...
Conexion
Posts: 236
Joined: Feb 23, 2006 6:04

Post by Conexion »

Sooo pretttyyyy.

I've used both Adobe Acrobat and Foxit, and on my slower machine I prefer Foxit...

But now I prefer this :p it obviously isn't the most robust program in the world, but I think with a few little tweaks, I may make this the default. I love the feel of it :). Now I'd just recommend adding the clean-up work! There shouldn't be 8 bmp files after I close the program :p Awesome stuff though.
Antoni
Posts: 1393
Joined: May 27, 2005 15:40
Location: Barcelona, Spain

Post by Antoni »

Kristopher

Have you tried the current version of Foxit? They upload a new build every month or so. I have version 3.1.1.0901 and no problems with scrolling graphics.

At the job our draftsman prints his AutoCAD electric schematics to PDFs with twenty pages or so and I have no problems scrolling them with Foxit. The same with product datasheets full of graphics.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Re: hmmm

Post by KristopherWindsor »

I just downloaded Foxit recently, yes.

@Conexion

Me too. xD
And it's easy to change the code, if you want to adjust the scroll speed. :)
thesanman112 wrote:doesn't adobe smooth scroll just by clicking on the page and moving the mouse??? mine does...
The problem is that it's slow, no matter how you scroll. If you hold the down arrow key, and watch the movement of the scrollbar, you will see that it stutters / is jerky. Maybe Adobe / Foxit could fix this by just multithreading the program and rendering a couple pages before and after the current page, but they haven't.
Post Reply