It is currently Sun Jun 25, 2017 6:25 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Simple PDF viewer
PostPosted: Wed Apr 20, 2011 9:59 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Apr 21, 2005 2:38 pm
Posts: 1423
Location: Germany
Have you ever had the need to display PDF documents in your own Mac application?
In contrast to Windows (where you have to buy 3rd party products like the high
priced Adobe Acrobat or other products or where you have to fight with the poorly
documented API of the Adobe Reader) MacOS X offers all the necessary API functions
to display PDF documents in your own applications. The following code example
demonstrates the basics of a very simple PDF viewer:
Code:
EnableExplicit

ImportC ""
  CFStringCreateWithCString(CFAllocatorRef.L, CString, CFStringEncoding.L)
  CFRelease(CFTypeRef.L)
  CFURLCreateWithFileSystemPath(CFAllocatorRef.L, CFStringFilePath.L, PathStyle.L, IsDirectory.L)
  CGContextDrawPDFPage(CGContextRef.L, CGPDFPageRef.L)
  CGPDFDocumentCreateWithURL(CFURLRef.L)
  CGPDFDocumentGetNumberOfPages(PDFDocumentRef.L)
  CGPDFDocumentGetPage(PDFDocumentRef.L, PageNumber.L)
  CGPDFDocumentRelease(PDFDocumentRef.L)
  GetWindowPort(WindowRef.L)
  QDBeginCGContext(*ColorGraphicsPort, *CGContextRef)
  QDEndCGContext(*ColorGraphicsPort, *CGContextRef)
EndImport

#kCFAllocatorDefault = 0
#kCFStringEncodingMacRoman = 0
#kCFURLPOSIXPathStyle = 0

Procedure.L OpenPDFDocument(PathAndPDFFilename.S)
  Protected FilePathRef.L
  Protected PDFDocumentRef.L
  Protected URLRef.L

  ; ----- Convert PDF file path from PureBasic String into Core Foundation
  ;       string (CFString)
  FilePathRef = CFStringCreateWithCString(#kCFAllocatorDefault, @PathAndPDFFilename, #kCFStringEncodingMacRoman)

  If FilePathRef
    ; ----- Create CFURL object using CFString with local file system path
    URLRef = CFURLCreateWithFileSystemPath(#kCFAllocatorDefault, FilePathRef, #kCFURLPOSIXPathStyle, #False)
   
    If URLRef
      ; ----- Create Quartz PDF document with URL of PDF file
      PDFDocumentRef = CGPDFDocumentCreateWithURL(URLRef)
      CFRelease(URLRef)
    EndIf

    CFRelease(FilePathRef)
  EndIf

  ProcedureReturn PDFDocumentRef
EndProcedure

Procedure DrawPDFPage(PDFDocumentRef.L, PageNumber.L)
  Protected ContextRef.L
  Protected *GraphicsPort
  Protected PDFPageRef.L

  ; ----- Read page from Quartz PDF document
  PDFPageRef = CGPDFDocumentGetPage(PDFDocumentRef, PageNumber)
 
  If PDFPageRef
    ; ----- Obtain ColorGraphicsPort of window
    *GraphicsPort = GetWindowPort(WindowID(0))
   
    If *GraphicsPort
      ; ----- Obtain Quartz 2D drawing environment associated with graphics port
      QDBeginCGContext(*GraphicsPort, @ContextRef)
     
      If ContextRef
        ; ----- Draw PDF page into current graphics context
        CGContextDrawPDFPage(ContextRef, PDFPageRef)

        ; ----- Terminate Quartz 2D drawing environment
        QDEndCGContext(*GraphicsPort, @ContextRef)
      EndIf
    EndIf
  EndIf
EndProcedure

Define CurrentPage.L
Define LastPage.L
Define PathAndPDFFilename.S
Define PDFDocumentRef.L
Define WindowEvent.L

OpenWindow(0, 200, 50, 580, 790, "PDF-Viewer")
SetWindowColor(0, $FFFFFF)

; ----- Draw ToolBar buttons for one page back and forward
CreateImage(0,16,16)
StartDrawing(ImageOutput(0))
Box(0, 0, 16, 16, $FFFFFF)
DrawText(3, 0, "<", 0, $FFFFFF)
StopDrawing()
CreateImage(1,16,16)
StartDrawing(ImageOutput(1))
Box(0, 0, 16, 16, $FFFFFF)
DrawText(5, 0, ">", 0, $FFFFFF)
StopDrawing()
CreateToolBar(0, WindowID(0))
ToolBarImageButton(0,ImageID(0))
ToolBarImageButton(1,ImageID(1))

; ----- Create Quartz PDF object
PathAndPDFFilename = "/Developer/Documentation/CHUD/Saturn/SaturnUserGuide.pdf"
PDFDocumentRef = OpenPDFDocument(PathAndPDFFilename)

If PDFDocumentRef
  CurrentPage = 1
  LastPage = CGPDFDocumentGetNumberOfPages(PDFDocumentRef)
  DrawPDFPage(PDFDocumentRef, CurrentPage)

  Repeat
    WindowEvent = WaitWindowEvent()
   
    Select WindowEvent
      Case #PB_Event_Repaint
        DrawPDFPage(PDFDocumentRef, CurrentPage)
      Case #PB_Event_Menu
        Select EventMenu()
          Case 0
            If CurrentPage > 1
              CurrentPage - 1
            EndIf
          Case 1
            If CurrentPage < LastPage
              CurrentPage + 1
            EndIf
        EndSelect

        SetWindowColor(0, $FFFFFF)
        DrawPDFPage(PDFDocumentRef, CurrentPage)
    EndSelect
  Until WindowEvent = #PB_Event_CloseWindow

  ; ----- Release Quartz PDF document
  CGPDFDocumentRelease(PDFDocumentRef)
EndIf


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Wed Nov 23, 2011 8:07 pm 
Offline
Addict
Addict

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 1096
Location: Seattle, USA
Nice! Works fine here.

Code:
; to load your own PDF
;PathAndPDFFilename = "/Developer/Documentation/CHUD/Saturn/SaturnUserGuide.pdf"
PathAndPDFFilename = OpenFileRequester("Load PDF file...", "", "", 0) ; pattern$ doesn't work on Mac
PDFDocumentRef = OpenPDFDocument(PathAndPDFFilename)


Thanks Shardik :)

@zabenka
Are you on a Mac? You don't need (or want) Acrobat Reader to get involved this, the PDF viewer runs in PureBasic.

_________________
MacBook Pro-r, OSX 10.11.6, Command Line Tools 7.3 (10.11), PB-5.60x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Fri Jun 14, 2013 5:43 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 2875
Location: Netherlands
I get missing symbols on x64.

Here's an alternative approach.
It's probably not as flexible but seems to work
Code:
ImportC "/System/Library/Frameworks/Quartz.framework/Quartz" : EndImport

Procedure PDFGadget(Gadget, x, y, Width, Height, Flags = 0)
  Protected Result, ContainerID, Viewer, Frame.NSRect
  Result = ContainerGadget(Gadget, x, y, Width, Height, Flags)
  CloseGadgetList()
  If Gadget = #PB_Any
    ContainerID = GadgetID(Result)
  Else
    ContainerID = GadgetID(Gadget)
  EndIf
  Viewer = CocoaMessage(0, CocoaMessage(0, 0, "PDFView alloc"), "initWithFrame:@", @Frame)
  CocoaMessage(0, ContainerID, "setContentView:", Viewer)
  CocoaMessage(0, Viewer, "release")
  ProcedureReturn Result
EndProcedure

Procedure PDFGadgetCatchPDF(PDFGadget, *MemoryAddress, Size)
  Protected Viewer, Doc, PDFData
  PDFData = CocoaMessage(0, 0, "NSData dataWithBytes:", *MemoryAddress, "length:", Size)
  Doc = CocoaMessage(0, CocoaMessage(0, 0, "PDFDocument alloc"), "initWithData:", PDFData)
  If Doc
    Viewer = CocoaMessage(0, GadgetID(PDFGadget), "contentView")
    CocoaMessage(0, Viewer, "setDocument:", Doc)
    CocoaMessage(0, Doc, "release")
  EndIf
EndProcedure

Procedure PDFGadgetLoadPDF(PDFGadget, Filename$)
  Protected PDFData = CocoaMessage(0, 0, "NSData dataWithContentsOfFile:$", @Filename$)
  If PDFData
    PDFGadgetCatchPDF(PDFGadget, CocoaMessage(0, PDFData, "bytes"), CocoaMessage(0, PDFData, "length"))
  EndIf
EndProcedure

Procedure.s PDFGadgetGetText(PDFGadget)
  Protected Result.s, Document = CocoaMessage(0, CocoaMessage(0, GadgetID(PDFGadget), "contentView"), "document")
  If Document
    Result = PeekS(CocoaMessage(0, CocoaMessage(0, Document, "string"), "UTF8String"), -1, #PB_UTF8)
  EndIf
  ProcedureReturn Result
EndProcedure

Procedure PDFThumbnailGadget(Gadget, x, y, Width, Height, Flags = 0)
  Protected Result, ContainerID, Viewer, Frame.NSRect
  Result = ContainerGadget(Gadget, x, y, Width, Height, Flags)
  CloseGadgetList()
  If Gadget = #PB_Any
    ContainerID = GadgetID(Result)
  Else
    ContainerID = GadgetID(Gadget)
  EndIf
  Viewer = CocoaMessage(0, CocoaMessage(0, 0, "PDFThumbnailView alloc"), "initWithFrame:@", @Frame)
  CocoaMessage(0, ContainerID, "setContentView:", Viewer)
  CocoaMessage(0, Viewer, "release")
  ProcedureReturn Result
EndProcedure

Procedure PDFThumbnailGadgetSetPDFGadget(PDFThumbnailGadget, PDFGadget)
  Protected ThumbnailViewer = CocoaMessage(0, GadgetID(PDFThumbnailGadget), "contentView")
  Protected Viewer = CocoaMessage(0, GadgetID(PDFGadget), "contentView")
  CocoaMessage(0, ThumbnailViewer, "setPDFView:", Viewer)
EndProcedure



If OpenWindow(0, 0, 0, 600, 400, "PDF Viewer example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  PDFGadget(0, 120, 10, 460, 300, #PB_Container_Flat)
  PDFThumbnailGadget(1, 10, 10, 100, 380, #PB_Container_Flat)
  EditorGadget(2, 120, 320, 460, 70, #PB_Editor_ReadOnly | #PB_Editor_WordWrap)
  PDFThumbnailGadgetSetPDFGadget(1, 0)
  PDFGadgetLoadPDF(0, "test.pdf")
  SetGadgetText(2, PDFGadgetGetText(0))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf


Edit : I just notice this was a very old thread that came to the front due to a spam message. Well, maybe someone can use my code anyhow.

_________________
MacOS 10.12, PB 5.51 x64


Last edited by wilbert on Fri Jun 14, 2013 6:41 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Fri Jun 14, 2013 6:12 pm 
Offline
Addict
Addict

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 1096
Location: Seattle, USA
Hi wilbert!

Your code works fine here. I just wish there was a way to get the text from the displayed pdf. I was looking at your code and trying to figure out if the text could be copied out of the containers like we do with GetGadgetText().

I guess getting the text out of a pdf is pretty hard since all I see are programs that can do it are being sold for $s. I bought an app to read pdfs but I keep looking for a pb way to do it anyway.

_________________
MacBook Pro-r, OSX 10.11.6, Command Line Tools 7.3 (10.11), PB-5.60x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Fri Jun 14, 2013 6:47 pm 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 2875
Location: Netherlands
WilliamL wrote:
I guess getting the text out of a pdf is pretty hard since all I see are programs that can do it are being sold for $s.

Actually it's easy (see updated example above).
If you don't need to display the PDF but only want its text, it's even easier
Code:
ImportC "/System/Library/Frameworks/Quartz.framework/Quartz" : EndImport

PDFFile.s = "test.pdf"
PDFDocument = CocoaMessage(0, CocoaMessage(0, 0, "PDFDocument alloc"), "initWithURL:", CocoaMessage(0, 0, "NSURL fileURLWithPath:$", @PDFFile))
PDFText.s = PeekS(CocoaMessage(0, CocoaMessage(0, PDFDocument, "string"), "UTF8String"), -1, #PB_UTF8)
CocoaMessage(0, PDFDocument, "release")
MessageRequester("", PDFText)

_________________
MacOS 10.12, PB 5.51 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Fri Jun 14, 2013 7:43 pm 
Offline
Addict
Addict

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 1096
Location: Seattle, USA
Hey wilbert!

That works! I like the way you modified your first example with the EditorGadget. :D

Now that I have the text and can play with it...

[later]
ok, it works fine with paragraphs but I get lists for columns (tables) a column at a time. It's pretty confusing. I think I read somewhere that the formatting of the text would be hosed.. and it is. It's too bad that the column elements don't have LFs (or some other delimiter) and CRs at the end of the lines.. but they don't. It's all CRs.

Ah, the 'devil is in the details'.

_________________
MacBook Pro-r, OSX 10.11.6, Command Line Tools 7.3 (10.11), PB-5.60x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Sat Jun 15, 2013 7:13 am 
Offline
PureBasic Expert
PureBasic Expert

Joined: Sun Aug 08, 2004 5:21 am
Posts: 2875
Location: Netherlands
WilliamL wrote:
ok, it works fine with paragraphs but I get lists for columns (tables) a column at a time. It's pretty confusing. I think I read somewhere that the formatting of the text would be hosed.. and it is. It's too bad that the column elements don't have LFs (or some other delimiter) and CRs at the end of the lines.. but they don't. It's all CRs.

It's possible to get it as html text but I don't know if that would make a difference.

_________________
MacOS 10.12, PB 5.51 x64


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Wed Oct 02, 2013 6:55 pm 
Offline
Enthusiast
Enthusiast

Joined: Thu Jul 02, 2009 5:42 am
Posts: 327
is there anyway to create a pdf file using text?


Top
 Profile  
Reply with quote  
 Post subject: Re: Simple PDF viewer
PostPosted: Fri Jan 20, 2017 2:43 am 
Offline
Enthusiast
Enthusiast

Joined: Tue Jun 21, 2011 10:39 am
Posts: 326
Built in PDF? Marvelous! Thank you guys. :D

I tried both but can't get Shardik's code to work. It's lower level and more functions but fails at CGPDFDocumentCreateWithURL.

I modified and extended wilbert's code to load with "PDFDocument alloc initWithURL" and added the password and page functions and they work - SO FAR!

But when trying to get the dimensions of a page with boundsForBox: with any enumeration value the function fails with "boundsForBox: box is out of range".

What is causing this?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye