Skip to content

dmitriychunikhin/pdfium-vfp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VFPX

This and a dozen other components and tools are provided to you by VFPX community

Latest release Test coverage ChangleLog ChangleLog CN Downloads Discussions

pdfium-vfp

English | 简体中文

pdfium-vfp is a open source PDF viewer control and ReportOutput + ReportPreview implementation for Visual Fox Pro 9 SP2 and VFP Advanced based on

Table of contents

Features:

  • Viewing PDF files
  • Interactive form filling
  • Text selection and copying
  • Text searching
  • Printing PDF
  • Multiple control instances
  • VFP frx reports previewing, printing and saving (as pdf) without High DPI pain in the neck
  • Export VFP frx reports to docx (OOXML strict format)
  • Frx report rendering supports private fonts (non system fonts)
  • Frx report rendering supports dynamics and rotation properties
  • Supports VFP Advanced x86 and x64

Minumum system requirements

Windows

  • Windows Vista SP 2
  • 1 core CPU
  • 1024 MB of RAM

Linux

  • Tested on Debian (12 bookworm) and Alt (kworkstation 10) distros
  • Wine 9.0

Getting started

Thor

  • Install Thor https://github.com/VFPX/Thor
  • Run VFP and open Thor / Check for updates in VFP system menu
  • Download pdfium-vfp component
  • Open Thor / Folders / Components in VFP system menu and then open pdfium-vfp folder in Explorer
  • Read Basic Usage section on this page

Windows (full sources with samples)

Linux (full sources with samples)

  • Check wine version
> wine --version
wine-9.0
  • Clone repo and run sample.exe
cd ~
git clone https://github.com/dmitriychunikhin/pdfium-vfp
cd ~/pdfium-vfp/Sample
WINEDLLOVERRIDES="gdiplus=n" wine sample.exe

#wine built-in gdiplus.dll doesn't work as expected, thus it has to be overrided. You can take one from C:/Windows/SysWOW64 folder.

Sample VFP project

Open sample.pjx project from pdfium-vfp/Sample folder or just run Sample/sample.exe

Sample screen shot

Sample screen shot

Known issues

  • PdfiumViewer doesn't support page bookmarks, annotations and active hyperlinks
  • Fallback font in report previewer is Helvetica with no chance to change it
  • Report previewer can deal with ttf/ttc fonts only, non ttf font (bitmap fonts) and symbol fonts are rendered as images
  • Interface language always is your system language

Basic usage of PdfiumViewer

  1. Copy pdfium-vfp.vcx, pdfium-vfp.vct from Release folder to your project folder


  2. VFP: Copy dependency binaries pdfium.dll, pdfium-vfp.dll from Release folder to your project's folder

    VFPA x64: Copy dependency binaries pdfium64.dll, pdfium-vfp64.dll from Release folder to your project's folder

  3. Add PdfiumViewer object from pdfium-vfp.vcx on the form

  4. Open PDF file

Thisform.PdfiumViewer.OpenPdf("some.pdf")
  1. Setup PdfiumViewer
Thisform.PdfiumViewer.FitWidth = .T. && Scale the document to fit viewport width
Thisform.PdfiumViewer.FitHeight = .T. && Scale the document to fit viewport height
* Rotate document in the viewport, possible values: 
*                             0 (normal)
*                             1 (rotated 90 degrees clockwise)
*                             2 (rotated 180 degrees)
*                             3 (rotated 90 degrees counter-clockwise)
Thisform.PdfiumViewer.Rotation = 0
  1. Print document
Thisform.PdfiumViewer.PrintDocument()
  1. Save document to the file

Saving without changing original document password protection state and meta-data tags values

Thisform.PdfiumViewer.SaveDocument("c:\myfolder\mydoc.pdf")

Saving and encrypting with custom password, setting custom values for PDF meta-data tags

LOCAL loPDFMeta
m.loPDFMeta = NEWOBJECT("pdfium_pdfmeta", "pdfium-vfp.vcx")

* PDF password protection
* m.loPDFMeta.OwnerPassword = "" && Owner Password protects permissions of the doc.
m.loPDFMeta.UserPassword = "MyPassword" && This password user inputs when open pdf file

* PDF metadata setup sample, setting up metadata is not mandatory 
* If loPDFMeta property value is NULL then the meta-data tag of the original document will not be changed
* m.loPDFMeta.Author = "Me"
* m.loPDFMeta.Creator = "Pdfium-vfp sample app"
m.loPDFMeta.Keywords = "My custom keywords for PDF"
* m.loPDFMeta.Subject = "sample"
* m.loPDFMeta.Title = "Sample"

* PDF reader permissions 
* If loPDFMeta property value is NULL then the permission flag of the original document will not be changed
* m.loPDFMeta.Permit_Print = .T. && Allow to print document
* m.loPDFMeta.Permit_Edit_All = .T. && Allow to edit contents other than annotations and forms
* m.loPDFMeta.Permit_Copy = .T. && Allow copy contents of the document
* m.loPDFMeta.Permit_Edit = .T. && Allow to make annotations and fill forms

Thisform.PdfiumViewer.SaveDocument("c:\myfolder\mydoc.pdf", m.loPDFMeta)
  1. Close PDF file
Thisform.PdfiumViewer.ClosePdf()

Basic usage of PdfiumReport

  1. Copy PdfiumReport.app from Release folder to your project folder


  2. VFP: Copy dependency binaries pdfium.dll, pdfium-vfp.dll from Release folder to your project's folder

    VFPA x64: Copy dependency binaries pdfium64.dll, pdfium-vfp64.dll from Release folder to your project's folder

More examples can be found at pdfium-vfp/Sample/sample.scx

Standalone

LOCAL loPdfiumReport
DO pdfiumreport.app WITH .F., loPdfiumReport, .T. && Create new instance of PdfiumReport
* DON'T USE NewObject("PdfiumReport", "pdfium-vfp.vcx", "pdfiumreport.app") to create new instance of PdfiumReport

*******************************************
* Report previewing
*******************************************
loPdfiumReport.SaveAs_Filename = "myreport" && Filename suggestion for "save as" dialog, not mandatory

loPdfiumReport.BatchBegin()

REPORT FORM Report1.frx OBJECT loPdfiumReport
REPORT FORM Report2.frx OBJECT loPdfiumReport PREVIEW

loPdfiumReport.BatchEnd()

** OR **

REPORT FORM Report1.frx OBJECT loPdfiumReport NOPAGEEJECT
REPORT FORM Report2.frx OBJECT loPdfiumReport PREVIEW


*******************************************
* Saving report output to the file
*******************************************
loPdfiumReport.BatchBegin()

REPORT FORM Report1.frx OBJECT loPdfiumReport 
REPORT FORM Report2.frx OBJECT loPdfiumReport TO FILE "some.pdf"

loPdfiumReport.BatchEnd()


** OR **

REPORT FORM Report1.frx OBJECT loPdfiumReport NOPAGEEJECT 
REPORT FORM Report2.frx OBJECT loPdfiumReport TO FILE "some.pdf"

as _REPORTOUTPUT

SET REPORTBEHAVIOR 90

LOCAL lSave_REPORTOUTPUT
lSave_REPORTOUTPUT = _REPORTOUTPUT

TRY
    _REPORTOUTPUT = "pdfiumreport.app"

    DO pdfiumreport.app WITH .T. && Initialization (mandatory) / Execute on initialization step of your application

    *******************************************
    * Report previewing
    *******************************************
    REPORT FORM Report1.frx NOPAGEEJECT 
    REPORT FORM Report2.frx PREVIEW

    *******************************************
    * Saving report output to the file
    *******************************************
    REPORT FORM Report1.frx NOPAGEEJECT
    REPORT FORM Report2.frx TO FILE "some.pdf"

    DO pdfiumreport.app WITH .F. && Release / Execute on release step of your application
        
FINALLY    
    _REPORTOUTPUT = lSave_REPORTOUTPUT
ENDTRY

PdfiumReport.app and private fonts

Private font is a font that is not installed in system in your development, testing or production environment.

Well know examples: barcode fonts, open-source unicode fonts, custom fonts

Usage sample can be found in pdfium-vfp/Sample/Sample.scx in cmdReport.Click

Standalone

* Manually create Pdfium environment and add your private fonts in Pdfium_env.PrivateFonts collection

LOCAL loPdfiumEnv
loPdfiumEnv = NEWOBJECT("Pdfium_env", "pdfium-vfp.vcx", "pdfiumreport.app") 
* You can omit "pdfiumreport.app" from NewObject 3rd argument if you have pdfium-vfp.vcx included in your project

* parameters: font file path, font face name
loPdfiumEnv.PrivateFonts.Add("Fonts\KurintoSansSC-Rg.ttf", "Kurinto Sans SC")

* Pass pdfium_env object as the first parameter of DO PdfiumReport.app command
LOCAL loPdfiumReport
DO pdfiumreport.app WITH loPdfiumEnv, loPdfiumReport, .T. && Create new instance of PdfiumReport


* Run report with private fonts
REPORT FORM Report1.frx OBJECT loPdfiumReport PREVIEW

as _REPORTOUTPUT

* Manually create Pdfium environment and add your private fonts in Pdfium_env.PrivateFonts collection

LOCAL loPdfiumEnv
loPdfiumEnv = NEWOBJECT("Pdfium_env", "pdfium-vfp.vcx", "pdfiumreport.app")
* You can omit "pdfiumreport.app" from NewObject 3rd argument if you have pdfium-vfp.vcx included in your project

* parameters: font file path, font face name
loPdfiumEnv.PrivateFonts.Add("Fonts\KurintoSansSC-Rg.ttf", "Kurinto Sans SC")

* Pass pdfium_env object as the first parameter of PdfiumReport.app initialization routine
DO pdfiumreport.app WITH loPdfiumEnv

* Run report with private fonts
REPORT FORM Report1.frx PREVIEW

PdfiumReport PDF metadata and password protection

LOCAL loPdfiumReport

loPdfiumReport = Application.PdfiumReport
* or *
DO pdfiumreport.app WITH .F., loPdfiumReport, .T. && Create new instance of PdfiumReport


********************************************************************************************** 
* Application.PdfiumReport is global variable created by pdfiumreport.app on initialization
**********************************************************************************************

loPdfiumReport.SaveAs_Filename = "myreport" && Filename suggestion for save as dialog in preview mode, not mandatory

* PDF metadata setup sample, setting up metadata is not mandatory 
loPdfiumReport.SaveAs_PDFMeta.Author = "Me"
loPdfiumReport.SaveAs_PDFMeta.Creator = "Pdfium-vfp sample app"
loPdfiumReport.SaveAs_PDFMeta.Keywords = "pdfium-vfp,sample"
loPdfiumReport.SaveAs_PDFMeta.Subject = "report1.frx and report2.frx batch"
loPdfiumReport.SaveAs_PDFMeta.Title = "Sample report"

* PDF password protection, input any owner password and user password for testing
loPdfiumReport.SaveAs_PDFMeta.OwnerPassword = "" && Owner Password protects permissions of the doc. Mandatory if User Password was set. Owner password mustn't be equal to user password
loPdfiumReport.SaveAs_PDFMeta.UserPassword = "" && This password user inputs when open pdf file

* PDF reader permissions (matter only if Owner passwords is set)
loPdfiumReport.SaveAs_PDFMeta.Permit_Print = .T. && Allow to print document
loPdfiumReport.SaveAs_PDFMeta.Permit_Edit_All = .T. && Allow to edit contents other than annotations and forms
loPdfiumReport.SaveAs_PDFMeta.Permit_Copy = .T. && Allow copy contents of the document
loPdfiumReport.SaveAs_PDFMeta.Permit_Edit = .T. && Allow to make annotations and fill forms
**********************************************************************************************

Filling PDF forms programmatically

PdfiumViewer gives a read-write access to form fields values, and read-only access to other field's properties like name, options and etc, adding new fields is not allowed.

PdfiumViewer::GetFormFieldsCount()

Returns number of fields in PDF form

PdfiumViewer::GetFormField(tcFieldNameOrIndex as String)

Accepts PDF form field name in UTF-16LE or 1-based field index, returns object if field exists otherwise returns .F..

Return object is a clone of current internal state of a field in document, thus setting values of object properties doesn't change anything inside document.

Return object fields:

  • Name: field name in UTF-16LE encoding

  • Type: field type, string (ANSI encoding)

    values: CheckBox, ComboBox, ListBox, Button, TextBox, OptionGroup, Signature, Unknown

  • Value: value of a field, the property contains

    • String value (UTF-16LE) for TextBox, ComboBox
    • Logical value for CheckBox
    • Numeric value for OptionGroup that is 1-based index of selected RadioButton in the group
    • NULL for Button
  • ValueRaw: unformatted field value in PDF (String, UTF-16LE encoding)

  • GroupItems: Collection of items for OptionGroup fields. Contains objects with props:

    • "Value" String (UTF-16LE): RadioButton internal value in PDF
    • "PageIndex": 1-based index of a page where RadioButton widget is located
    • "AnnotIndex": 1-based index of a RadioButton widget annotation
  • Options: Collection of options for ComboBox and ListBox fields

    Contains objects with props "Label" String (UTF-16LE), "IsSelected" Logical

  • PageIndex: 1-based index of a page where field's widget is located

  • AnnotIndex: 1-based index of a field's widget annotation

PdfiumViewer::SetFormFieldValue(tcFieldNameOrIndex as String, tvFormFieldValue)

Sets value of a field. Accepts two parameters:

  • field name in UTF-16LE or 1-based form field index
  • field value of type String (UTF-16LE) for textbox, combobox, Logical for checkbox, Numeric 1-based index of selected RadioButton for OptionGroup; Returns .T. if a value was set successfully otherwise returns .F.

Code samples

Thisform.NewObject("oPdfiumViewer", "PdfiumViewer", "pdfium-vfp.vcx")
LOCAL loFormField
WITH Thisform.oPdfiumViewer
    * TextBox
    m.loFormField = .GetFormField(STRCONV('teacher_name', 5))
    IF VARTYPE(m.loFormField) = "O"
        ? STRCONV(m.loFormField.Value, 6) && TextBox value is a string in UTF-16LE
        IF NOT .SetFormFieldValue(STRCONV('teacher_name', 5), STRCONV('John Doe', 5))
            ? teacher_name value wasn't set
        ENDIF
    ENDIF

    * ComboBox
    m.loFormField = .GetFormField(STRCONV('Combo1', 5))
    IF VARTYPE(m.loFormField) = "O"
        ? STRCONV(m.loFormField.Value, 6) && ComboBox value is a string in UTF-16LE
        IF NOT .SetFormFieldValue(STRCONV('Combo1', 5), 10) && This selects 10th item in combobox
            ? Combo1 value wasn't set
        ENDIF
    ENDIF

    * CheckBox
    m.loFormField = .GetFormField(STRCONV('checkbox', 5))
    IF VARTYPE(m.loFormField) = "O"
        ? m.loFormField.Value && CheckBox value is of Logical type
        IF NOT .SetFormFieldValue(STRCONV('checkbox', 5), .T.)
            ? checkbox value wasn't set
        ENDIF
    ENDIF

    * OptionGroup
    m.loFormField = .GetFormField(STRCONV('radiobutton', 5))
    IF VARTYPE(m.loFormField) = "O"
        ? m.loFormField.Value && OptionGroup value is of Numeric type
        IF NOT .SetFormFieldValue(STRCONV('radiobutton', 5), 2) && This selects 2nd RadioButton in OptionGroup
            ? OptionGroup value wasn't set
        ENDIF
    ENDIF
ENDWITH

Binaries

What binaries exactly do you need to run all the stuff (or your own latest version of it)

VFP

VFPA x64

VFP environment effects

  • Adds Application.Pdfium_instance_count property
  • Adds Application.PdfiumReportEnv property as pdfium_env of pdfium-vfp
  • Adds Application.PdfiumReport property as pdfiumreport of pdfium-vfp
  • Declares WIN32API and GDIPlus functions via WinApi_* pattern (with aliases)
  • Declares pdfium.dll functions via FPDF_* pattern (with aliases)
  • Declares pdfium-vfp.dll functions via VFPDF_* pattern (with aliases)
  • Doesn't perform CLEAR DLLS
  • Adds fonts from Pdfium_env.PrivateFonts collection to GDIPlus PrivateFontCollection (https://learn.microsoft.com/en-us/dotnet/api/system.drawing.text.privatefontcollection?view=net-8.0)