How to Get Number of Pages of Open Foxit PDF Document Topic is solved
How to Get Number of Pages of Open Foxit PDF Document
I have to work with a large number of .pdf documents using Foxit Editor (previously called Foxit Phantom). Often times, the numbering in the bottom left page navigation box is hinky. For example, the numbering in the document as shown in the page navigation box on the bottom left might go from "16/16" to "1", depending on how the document was set up.
Does anyone know how to have AHK determine the total number of pages in an open .pdf document? In the above example, the correct answer would give the result of "17" total pages, since that is the actual total number of pages in the document.
I have tried to adapt this script, but am not getting anywhere: viewtopic.php?t=89193
Does anyone know how to have AHK determine the total number of pages in an open .pdf document? In the above example, the correct answer would give the result of "17" total pages, since that is the actual total number of pages in the document.
I have tried to adapt this script, but am not getting anywhere: viewtopic.php?t=89193
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: How to Get Number of Pages of Open Foxit PDF Document
if you open those pdf's in notepad and do edit find Pages/Count do you see number of pages?
Re: How to Get Number of Pages of Open Foxit PDF Document
Oh, I see you tried one of my functions. These were written for FoxitReader. Unless I've stupidly misunderstood something in a quick read of your post, you want the total number of pages in the displayed document.
I can suggest a function. The function still results from my attempts to disassemble PDF files natively using Autohotkey and to extract data. Since PDF files can contain all kinds of content. Among other things, also compressed, encoded and compressed again content. I then decided on a built-in automatic fallback solution via the commandline tool "qpdf". qpdf you can get here.
I would say that it is anything but a slim command line tool yet.
qpdf-10.6.3-bin-msvc32.zip 9.25 MB
qpdf-10.6.3-bin-msvc64.zip 9.73 MB
However, if you want to know the exact page you are on in the document at the moment, then you will have to help yourself by reading out the surface information from the FoxitEditor.
Since I don't use the Foxit Editor, I can't really help you with reading out the controls.
I can suggest a function. The function still results from my attempts to disassemble PDF files natively using Autohotkey and to extract data. Since PDF files can contain all kinds of content. Among other things, also compressed, encoded and compressed again content. I then decided on a built-in automatic fallback solution via the commandline tool "qpdf". qpdf you can get here.
I would say that it is anything but a slim command line tool yet.
qpdf-10.6.3-bin-msvc32.zip 9.25 MB
qpdf-10.6.3-bin-msvc64.zip 9.73 MB
Code: Select all
PDFGetPages(pdfFilePath , qpdfPath:="") { ;-- returns count of pages
; last change 25.11.2021
; PDF's are written in ANSI
If !(fobj := FileOpen(pdfFilePath, "r", "CP0"))
return 0
; search string(s) that contain/s/ing page data
while !fobj.AtEof {
line := fobj.ReadLine()
If RegExMatch(line, "i)\/(Count|Pages)\s+(?<ages>\d+)\/", p)
break
else If RegExMatch(line, "Length\s+(?<seek>\d+)", file)
fobj.seek(fileseek, 1)
}
fobj.Close()
; sometimes it finds more pages than money on Elon Musk's stock portfolio - so qpdf will be used as fallback
If RegExMatch(pages, "\d+")
If (pages > 0 && pages < 10000)
return pages
; #### if there's no match, sometimes the PDF XREF table is encoded/compressed - qpdf will be used
If qpdfPath {
qpdfPages := StdoutToVar(qpdfPath "\qpdf.exe --show-npages " q pdfFilePath q)
If RegExMatch(qpdfPages, "\d+", qpages)
return qpages
}
return 0
}
StdoutToVar(sCmd, sEncoding:="UTF-8", sDir:="", ByRef nExitCode:=0) { ;-- cmdline Ausgabe in einen String umleiten
DllCall( "CreatePipe" , "PtrP" ,hStdOutRd, "PtrP",hStdOutWr, "Ptr",0, "UInt",0 )
DllCall( "SetHandleInformation" , "Ptr" ,hStdOutWr, "UInt" ,1, "UInt",1)
VarSetCapacity( pi, (A_PtrSize == 4) ? 16 : 24, 0 )
siSz := VarSetCapacity( si, (A_PtrSize == 4) ? 68 : 104, 0 )
NumPut( siSz, si, 0, "UInt" )
NumPut( 0x100, si, (A_PtrSize == 4) ? 44 : 60, "UInt" )
NumPut( hStdOutWr, si, (A_PtrSize == 4) ? 60 : 88, "Ptr" )
NumPut( hStdOutWr, si, (A_PtrSize == 4) ? 64 : 96, "Ptr" )
If (!DllCall( "CreateProcess", "Ptr",0, "Ptr",&sCmd, "Ptr",0, "Ptr",0, "Int",True, "UInt",0x08000000, "Ptr",0, "Ptr",sDir?&sDir:0, "Ptr",&si, "Ptr",&pi ))
Return ""
, DllCall( "CloseHandle", "Ptr",hStdOutWr )
, DllCall( "CloseHandle", "Ptr",hStdOutRd )
DllCall( "CloseHandle", "Ptr",hStdOutWr ) ; The write pipe must be closed before reading the stdout.
While ( 1 ) { ; Before reading, we check if the pipe has been written to, so we avoid freezings.
If (!DllCall( "PeekNamedPipe", "Ptr",hStdOutRd, "Ptr",0, "UInt",0, "Ptr",0, "UIntP",nTot, "Ptr",0 ))
Break
If ( !nTot ) { ; If the pipe buffer is empty, sleep and continue checking.
Sleep, 100
Continue
} ; Pipe buffer is not empty, so we can read it.
VarSetCapacity(sTemp, nTot+1)
DllCall( "ReadFile", "Ptr",hStdOutRd, "Ptr",&sTemp, "UInt",nTot, "PtrP",nSize, "Ptr",0 )
sOutput .= StrGet(&sTemp, nSize, sEncoding)
}
; * SKAN has managed the exit code through SetLastError.
DllCall( "GetExitCodeProcess" , "Ptr",NumGet(pi,0), "UIntP",nExitCode )
DllCall( "CloseHandle" , "Ptr",NumGet(pi,0) )
DllCall( "CloseHandle" , "Ptr",NumGet(pi,A_PtrSize) )
DllCall( "CloseHandle" , "Ptr",hStdOutRd )
Return sOutput
}
Since I don't use the Foxit Editor, I can't really help you with reading out the controls.
Re: How to Get Number of Pages of Open Foxit PDF Document
AHKStudent, opening in notepad gives me an inaccurate page count (my test .pdf is 11 pages, but Notepad thought it was 38 pages).AHKStudent wrote: ↑04 May 2022, 01:04if you open those pdf's in notepad and do edit find Pages/Count do you see number of pages?
Re: How to Get Number of Pages of Open Foxit PDF Document
BoBo: Thank you, that does look promising. Unfortunately, I don't know any C programming.BoBo wrote: ↑04 May 2022, 01:18https://docs.microsoft.com/en-us/uwp/api/windows.data.pdf.pdfdocument.pagecount?view=winrt-22000
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: How to Get Number of Pages of Open Foxit PDF Document
keep on looking in the txt file you should see the correct number of pagesAlFlo wrote: ↑04 May 2022, 11:18AHKStudent, opening in notepad gives me an inaccurate page count (my test .pdf is 11 pages, but Notepad thought it was 38 pages).AHKStudent wrote: ↑04 May 2022, 01:04if you open those pdf's in notepad and do edit find Pages/Count do you see number of pages?
Re: How to Get Number of Pages of Open Foxit PDF Document
Thanks, Frosti. Please excuse my ignorance, but is my assumption correct that I can't use your AHK script until I've installed qpdf? And that I can't install/use qpdf unless I have a C++ compiler?
If so, this looks really good, but is above my pay grade (I'm a newbie in all things AHK, let alone C++).
Re: How to Get Number of Pages of Open Foxit PDF Document
I haven't yet found a way using AHK but I've been using a PowerShell script with a free commandline utility called PDFINFO to find the page count of PDF files in a folder.
For example, scanning a folder of 60 PDF files took just 3 seconds to return a list of each PDF file with their page count. PDFINFO is a component of XPDF. Download the ZIP file from https://dl.xpdfreader.com/xpdf-tools-win-4.04.zip and unzip it. I found it easiest to just copy and paste .\xpdf-tools-win-4.04\xpdf-tools-win-4.04\bin64\pdfinfo.exe into C:\Windows so I didn't have to bother with PATH statements.
The PowerShell script is:
I'll warn you now... on folders with large nos. of PDF files there's sometimes an issue with the REGEX expression in line 5 but I have zero REGEX skills/knowledge to know what is wrong or how to fix. The point is... the PS script still just works. Here's a screenshot of just a few files so I can show both script and output:
I know it's not what you wanted but hope an alternative method is useful.
For example, scanning a folder of 60 PDF files took just 3 seconds to return a list of each PDF file with their page count. PDFINFO is a component of XPDF. Download the ZIP file from https://dl.xpdfreader.com/xpdf-tools-win-4.04.zip and unzip it. I found it easiest to just copy and paste .\xpdf-tools-win-4.04\xpdf-tools-win-4.04\bin64\pdfinfo.exe into C:\Windows so I didn't have to bother with PATH statements.
The PowerShell script is:
Code: Select all
$folder = 'C:\PDF_TEST'
$Total = $Files = 0
foreach($File in (Get-ChildItem -Path $Folder -Filter *.pdf)){
$Pages = (pdfinfo $File.FullName | Select-String -Pattern '(?<=Pages:\s*)\d+').Matches.Value
$Total += $Pages
$Files++
[PSCustomObject]@{
PdfFile = $File.Name
Pages = $Pages
}
}
"`nTotalNumber of pages: {0} in {1} files" -f $Total,$Files
I know it's not what you wanted but hope an alternative method is useful.
Re: How to Get Number of Pages of Open Foxit PDF Document Topic is solved
Code: Select all
pdfPath := "G:\7585637.pdf"
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", IID_RandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &GUID)
DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", pdfPath, "uint", Read := 0, "ptr", &GUID, "ptr*", IRandomAccessStream)
CreateClass("Windows.Data.Pdf.PdfDocument", IPdfDocumentStatics := "{433A0B5F-C007-4788-90F2-08143D922599}", PdfDocumentStatics)
DllCall(NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) ; LoadFromStreamAsync
WaitForAsync(PdfDocument)
DllCall(NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", PageCount) ; get_PageCount
ObjReleaseClose(IRandomAccessStream)
ObjReleaseClose(PdfDocumentStatics)
ObjReleaseClose(PdfDocument)
msgbox % PageCount
return
CreateClass(string, interface := "", ByRef Class := "")
{
CreateHString(string, hString)
if (interface = "")
result := DllCall("Combase.dll\RoActivateInstance", "ptr", hString, "ptr*", Class, "uint")
else
{
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint")
}
if (result != 0)
{
if (result = 0x80004002)
msgbox No such interface supported
else if (result = 0x80040154)
msgbox Class not registered
else
msgbox error: %result%
ExitApp
}
DeleteHString(hString)
}
CreateHString(string, ByRef hString)
{
DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}
DeleteHString(hString)
{
DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}
WaitForAsync(ByRef Object)
{
AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
loop
{
DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status
if (status != 0)
{
if (status != 1)
{
DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode
msgbox AsyncInfo status error: %ErrorCode%
ExitApp
}
ObjRelease(AsyncInfo)
break
}
sleep 10
}
DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults
ObjReleaseClose(Object)
Object := ObjectResult
}
ObjReleaseClose(ByRef Object)
{
if Object
{
if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}"))
{
DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close
ObjRelease(Close)
}
ObjRelease(Object)
}
Object := ""
}
Re: How to Get Number of Pages of Open Foxit PDF Document
THANKS, MALCEV! THIS SEEMS TO WORK LIKE A ROCK STAR!malcev wrote: ↑04 May 2022, 20:47Code: Select all
pdfPath := "G:\7585637.pdf" VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", IID_RandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &GUID) DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", pdfPath, "uint", Read := 0, "ptr", &GUID, "ptr*", IRandomAccessStream) CreateClass("Windows.Data.Pdf.PdfDocument", IPdfDocumentStatics := "{433A0B5F-C007-4788-90F2-08143D922599}", PdfDocumentStatics) DllCall(NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) ; LoadFromStreamAsync WaitForAsync(PdfDocument) DllCall(NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", PageCount) ; get_PageCount ObjReleaseClose(IRandomAccessStream) ObjReleaseClose(PdfDocumentStatics) ObjReleaseClose(PdfDocument) msgbox % PageCount return CreateClass(string, interface := "", ByRef Class := "") { CreateHString(string, hString) if (interface = "") result := DllCall("Combase.dll\RoActivateInstance", "ptr", hString, "ptr*", Class, "uint") else { VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID) result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint") } if (result != 0) { if (result = 0x80004002) msgbox No such interface supported else if (result = 0x80040154) msgbox Class not registered else msgbox error: %result% ExitApp } DeleteHString(hString) } CreateHString(string, ByRef hString) { DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString) } DeleteHString(hString) { DllCall("Combase.dll\WindowsDeleteString", "ptr", hString) } WaitForAsync(ByRef Object) { AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") loop { DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status if (status != 0) { if (status != 1) { DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode msgbox AsyncInfo status error: %ErrorCode% ExitApp } ObjRelease(AsyncInfo) break } sleep 10 } DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults ObjReleaseClose(Object) Object := ObjectResult } ObjReleaseClose(ByRef Object) { if Object { if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")) { DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close ObjRelease(Close) } ObjRelease(Object) } Object := "" }
Re: How to Get Number of Pages of Open Foxit PDF Document
Excellent solution, @malcev
- JoeWinograd
- Posts: 2213
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: How to Get Number of Pages of Open Foxit PDF Document
Hi @malcev,
Great stuff! Tested here on W10 and W11...worked perfectly! What is the oldest version of Windows that it will work on? Thanks, Joe
Great stuff! Tested here on W10 and W11...worked perfectly! What is the oldest version of Windows that it will work on? Thanks, Joe
Re: How to Get Number of Pages of Open Foxit PDF Document
https://docs.microsoft.com/en-us/uwp/api/windows.data.pdf.pdfdocument?view=winrt-22000Windows requirements
Device family: Windows 10 (introduced in 10.0.10240.0)
-
- Posts: 1472
- Joined: 05 May 2018, 12:23
Re: How to Get Number of Pages of Open Foxit PDF Document
AMAZINGG! Tried on 558 page book workedmalcev wrote: ↑04 May 2022, 20:47Code: Select all
pdfPath := "G:\7585637.pdf" VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", IID_RandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &GUID) DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", pdfPath, "uint", Read := 0, "ptr", &GUID, "ptr*", IRandomAccessStream) CreateClass("Windows.Data.Pdf.PdfDocument", IPdfDocumentStatics := "{433A0B5F-C007-4788-90F2-08143D922599}", PdfDocumentStatics) DllCall(NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) ; LoadFromStreamAsync WaitForAsync(PdfDocument) DllCall(NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", PageCount) ; get_PageCount ObjReleaseClose(IRandomAccessStream) ObjReleaseClose(PdfDocumentStatics) ObjReleaseClose(PdfDocument) msgbox % PageCount return CreateClass(string, interface := "", ByRef Class := "") { CreateHString(string, hString) if (interface = "") result := DllCall("Combase.dll\RoActivateInstance", "ptr", hString, "ptr*", Class, "uint") else { VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID) result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint") } if (result != 0) { if (result = 0x80004002) msgbox No such interface supported else if (result = 0x80040154) msgbox Class not registered else msgbox error: %result% ExitApp } DeleteHString(hString) } CreateHString(string, ByRef hString) { DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString) } DeleteHString(hString) { DllCall("Combase.dll\WindowsDeleteString", "ptr", hString) } WaitForAsync(ByRef Object) { AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") loop { DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status if (status != 0) { if (status != 1) { DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode msgbox AsyncInfo status error: %ErrorCode% ExitApp } ObjRelease(AsyncInfo) break } sleep 10 } DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults ObjReleaseClose(Object) Object := ObjectResult } ObjReleaseClose(ByRef Object) { if Object { if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")) { DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close ObjRelease(Close) } ObjRelease(Object) } Object := "" }
- JoeWinograd
- Posts: 2213
- Joined: 10 Feb 2014, 20:00
- Location: U.S. Central Time Zone
Re: How to Get Number of Pages of Open Foxit PDF Document
Thanks!malcev wrote:Windows requirements
Device family: Windows 10 (introduced in 10.0.10240.0)
Re: How to Get Number of Pages of Open Foxit PDF Document
@malcev -
Q: is it possible to configure your script so that it returns all available property values of 'windows.data.pdf. ...' on the fly within an object?
... creating "Magic Malcev's PDF Tool"
Q: is it possible to configure your script so that it returns all available property values of 'windows.data.pdf. ...' on the fly within an object?
... creating "Magic Malcev's PDF Tool"
Re: How to Get Number of Pages of Open Foxit PDF Document
I think it is possible, but I do not think that all this properties are really needed.
Also as I understand in future versions of autohotkey We can call uwp api natively.
viewtopic.php?f=81&t=95945
Also as I understand in future versions of autohotkey We can call uwp api natively.
viewtopic.php?f=81&t=95945
Re: How to Get Number of Pages of Open Foxit PDF Document
@malcev - Thx for your statement. Much appreciated