alternative solutions for embedding pdf in gui

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

alternative solutions for embedding pdf in gui

30 Jan 2024, 19:29

My main goal is a distraction free high performance way to view the content of a pdf.
Top priority: Performance in both windows explorer preview and embedded gui preview. I need to cycle through pdf previews as fast as possible.
Second Priority: Ability to hide the entire user interface of pdf preview host program to remove distractions and maximize the size of the pdf viewport when it is embedded in my wrapper GUI.

I tested several viewers and did a benchmark to see how long it took to load the same pdf file in the explorer preview pane. Below are results.

Code: Select all

/*
Average time to preview sample file in windows explorer (10 Samples)
Adobe DC:      1.013s
Adobe XI:	   0.361s
Foxit          0.203s
SumatraPDF:    0.192s
*/
Sumatra is very impressive. It is the fastest for file preview, but does not have any way to embed it in a gui with activex plugin. It is open source so maybe it is possible to create one?
Foxit is just as fast, but it does not have ability to fully hide the UI except for in reader mode. Reader mode does not work because it spawns a quick access toolbar that steals focus from the host GUI. Also, their ativex plugin is noticeably slower than adobe XI.
Currently I am using Adobe XI. It allows for a fullscreen embed and is fast enough. However, it crashes a lot and locks windows explorer folders with file preview. I want to move away for stability and security concerns.
Adobe DC is beyond hope.

I did see some stuff about pdfium. It looks interesting, but am not sure if this sort of thing could ever be used as a gui control.
Here it is in use https://www.youtube.com/watch?v=tSW3l0A-r84

So, anyone have a secret way to embed a pdf in gui?

benchmark.ahk

Code: Select all

#NoEnv
#SingleInstance Force
SetBatchLines -1
coordMode,pixel,screen

;pixels to wait for. when they become visible the pdf has loaded
;knownPix := {x:970,y:655,color:"0x000000"} ;adobeDC
;knownPix := {x:968,y:673,color:"0x000000"} ;sumatra
;knownPix := {x:974,y:607,color:"0x000000"} ;foxit
knownPix := {x:727,y:467,color:"0x000000"} ;adobeXI
numSamples := 10
results := 0
loop % numSamples 
{
	selectInExplorer("Y:\Downloads\test\Start.txt") ;deselect pdf
	selectInExplorer("Y:\Downloads\test\A.pdf") ;select the pdf	
	results += waitForPreviewComplete(knownPix) ;time it
}

msgbox % round(results / numSamples,3) . "s"

waitForPreviewComplete(p)
{
	start := a_tickCount
	loop
	{		
		PixelGetColor, actualColor, % p.x, % p.y			
		if(actualColor == p.color)
		{
			return (a_tickCount - start) / 1000
		}
	}
}

selectInExplorer(fp)
{
	WinGet, currentHandle , id, A
	SplitPath, fp , OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive	
	For pExp in ComObjCreate("Shell.Application").Windows
    {		
		try
		{
			if(OutDir == pExp.Document.Folder.self.path)
			{					
				pExp.Document.SelectItem(fp ,0x1D) ; Select our File
				Return
			}
		}
		catch
		{
			;tooltip fail find
		}
    }
}
User avatar
mikeyww
Posts: 27191
Joined: 09 Sep 2014, 18:38

Re: alternative solutions for embedding pdf in gui

30 Jan 2024, 21:30

You could look at Ghostscript. I have not tested it for your need.
RussF
Posts: 1294
Joined: 05 Aug 2021, 06:36

Re: alternative solutions for embedding pdf in gui

31 Jan 2024, 07:08

Sumatra (which I love, BTW) uses MuPDF as it's core engine. They have both Open Source – AGPL and commercial license agreements.

Russ
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: alternative solutions for embedding pdf in gui

31 Jan 2024, 14:17

Thanks for the suggestions. I may have to give up on using the activex control, seems like it is phased out.

I was able to embed the pdf in my gui by launching the pdf in sumatra and then setting the parent win of sumatra to my gui.
Needed to set the following advanced options for sumatra to hide the title bar and menu bar.

ShowMenubar = false
ShowToolbar = false


Wasn't able to figure out a way to unhide it once embedded if sumatra was launched hidden.

Code: Select all

setBatchLines -1
#singleinstance force

pdfFile := A_scriptDIr . "\test.pdf"
if(tryLaunchingHidden := false) ;never had a successful embed
{
	DetectHiddenWindows, on
	Run, %pdfFile%,,Hide,sumatraPdfPID
	WinWait, ahk_pid %sumatraPdfPID%  
	WinShow, ahk_pid %sumatraPdfPID%
}
else
{
	Run, %pdfFile%,,,sumatraPdfPID
	WinWait, ahk_pid %sumatraPdfPID%  
}

fileGetSize,size,%pdfFile%,K
Gui, +hwndParentHWND +Resize +MinSize500x500
Gui, Show, maximize , % "PDF VIEWER  |  " . pdfFile . "  |  "  . size . "kb"

loop 3 ;for somereason 1x = blank. 2x = black. 3x actually embed
{
	childHWND := WinExist("ahk_pid " . sumatraPdfPID) + 0  
	DllCall("SetParent", "ptr", childHWND, "ptr", ParentHWND)
}
;remove title and border
WinSet, Style, -0xC00000, ahk_id %childHWND%
WinSet, Style, -0x40000, ahk_id %childHWND%
gosub guiSize
Return

guiSize: ;move the embedded win to match parent
	VarSetCapacity(rect,16)
	DllCall("GetClientRect", "ptr", ParentHWND, "ptr", &rect) 
	hostWidth := NumGet(rect,8,"int")
	hostHeight := NumGet(rect,12,"int")  
	WinMove ,  ahk_id %childHWND%, , 0, 0, hostWidth, hostHeight
return

guiclose:
	exitApp
return
garry
Posts: 3787
Joined: 22 Dec 2013, 12:50

Re: alternative solutions for embedding pdf in gui

31 Jan 2024, 15:48

@colt your example works fine
I use 'Foxit Reader' , then I not needed the loop in your script . ( With loop,2 or loop,3 I get a small PDF-file , ahk_id %childHWND% . )
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: alternative solutions for embedding pdf in gui

31 Jan 2024, 21:57

garry wrote: I use 'Foxit Reader' , then I not needed the loop in your script . ( With loop,2 or loop,3 I get a small PDF-file , ahk_id %childHWND% . )
Yeah the loop seemed very strange and was inconsistent between computers and depended on what applications i had running. Most importantly the loop count was different if sumatra was loaded hidden. I figured out that there are "layers" that need to be stripped away by the SetParent call until the class SUMATRA_PDF_FRAME has bubbled to the top.

I also saw Frosti's post about using sendmessage to send DDE commands viewtopic.php?t=89193. With the dde commands i was able to swap pdfs in the embedded control just like wb.navigate would do, but so much faster.

Code: Select all

setBatchLines -1
#singleinstance force
#Requires AutoHotkey Unicode 64-bit 
;big thanks to Frosti's post
;https://www.autohotkey.com/boards/viewtopic.php?t=89193

start := A_tickCount

pdfFile := A_args[1]

pdfSet := ["D.pdf","C.pdf","B.pdf","A.pdf"] ;pdfs in script dir to swap between (attempt to simulate wb.navigate function). hit f7 to swap to next

if(!pdfFile)
{
	pdfFile :=  A_scriptDIr . "\test.pdf"
}
Gui, +hwndParentHWND +Resize +MinSize500x500

sumatraHWND := embedSumatra(ParentHWND)

guiTail := showPdf(sumatraHWND,pdfFile)
fileGetSize,size,%pdf%,K
guiName := "PDF VIEWER  |  " . pdfFile . "  |  "  . size . "kb"
Gui, Show, maximize , % guiName
gosub guiSize
tooltip % "Cold start time : " .  round((A_tickCount - start)/1000,3) 
Return

f7:: ;cycle pdfs in pdfSet
	start := A_tickCount
	nextPDF := A_scriptDir . "\" . pdfSet.pop()
	currentVisPdf := showPdf(sumatraHWND,nextPDF)	
	fileGetSize,size,%nextPDF%,K
	guiName := "PDF VIEWER  |  " . nextPDF . "  |  "  . size . "kb"
	Gui, Show,,  % guiName
	tooltip % "Swap time : " .  round((A_tickCount - start)/1000,3) . "s"
return

embedSumatra(hostHWND)
{
	runCmd := "C:\Program Files\SumatraPDF\SumatraPDF.exe"

	DetectHiddenWindows, on
	Run %runCmd%,,HIDE,sumatraPdfPID
	WinWait, ahk_pid %sumatraPdfPID%  	
	
	gui,temp:+hwndtempParentHWND ;temp gui to pop off unwanted layers
	discardedLayers := ""
	loop ;for me there are a variable amount layers over the top that need to be discarded like teamviewer and tooltips
	{
		layerHWND := WinExist("ahk_pid " . sumatraPdfPID) + 0
		WinGetClass,class,ahk_id %layerHWND%		
		if(class == "SUMATRA_PDF_FRAME")
		{		
			DllCall("SetParent", "ptr", layerHWND, "ptr", hostHWND)	
			break
		}
		else
		{
			DllCall("SetParent", "ptr", layerHWND, "ptr", tempParentHWND)	
			discardedLayers .=  layerHWND . "`t" . class . "`n"
		}
	}
	gui,temp:destroy
	WinSet, Style, -0xC00000, ahk_id %layerHWND%
	WinSet, Style, -0x40000, ahk_id %layerHWND%
	WinShow, ahk_id %layerHWND%
	;msgbox % discardedLayers
	return layerHWND + 0
}

showPdf(viewportHWND,pdf)
{		
	SendDDE(viewportHWND,"[CmdClose]")	
	SendDDE(viewportHWND,"[Open(""" . pdf . """,0,0,1)]")
}

SendDDE(hWin, lpData)
{ 
	static ddeSignal := 0x44646557
	;very helpful post
	;https://www.autohotkey.com/boards/viewtopic.php?t=89193

	VarSetCapacity(COPYDATASTRUCT, 3*A_PtrSize, 0)
	cbData := (StrLen(lpData) + 1) * (A_IsUnicode ? 2 : 1)
	NumPut(ddeSignal   , COPYDATASTRUCT, 0*A_PtrSize)
	NumPut(cbData     , COPYDATASTRUCT, 1*A_PtrSize)
	NumPut(&lpData    , COPYDATASTRUCT, 2*A_PtrSize)	
	SendMessage, 0x4a, 0, &COPYDATASTRUCT,, % "ahk_id " . hWin ; 0x4a WM_COPYDATA
	return ErrorLevel 
}

guiSize: ;move the embedded win to match parent
	VarSetCapacity(rect,16)
	DllCall("GetClientRect", "ptr", ParentHWND, "ptr", &rect) 
	hostWidth := NumGet(rect,8,"int")
	hostHeight := NumGet(rect,12,"int")  
	WinMove , % "ahk_id " sumatraHWND, , 0, 0, hostWidth, hostHeight
return

guiclose:
	exitApp
return
garry
Posts: 3787
Joined: 22 Dec 2013, 12:50

Re: alternative solutions for embedding pdf in gui

01 Feb 2024, 09:20

@colt thank you , works fine with sumatra
( only a small typo > fileGetSize,size,%pdfFile%,K )

this your last script before works fine with a standalone 'Foxit Reader' :

Code: Select all

;- alternative solutions for embedding pdf in gui 
;- https://www.autohotkey.com/boards/viewtopic.php?f=76&t=125498
;- https://www.autohotkey.com/boards/viewtopic.php?p=557479#p557479
;-
;--- Example works fine with a StandAlone 'Foxit Reader'
;-
#Warn
#NoEnv
#singleinstance force
setBatchLines -1
;-
pdfFile:=A_scriptdir . "\basicmanual_1964.pdf"
;-
Try Run, %pdfFile%,,hide,PID3
catch,err
    {
    x1:="Message   =" . err.Message
    x2:="Message   =" . err.extra
    x3:="This-File =" . err.file
    x4:="In Line   =" . err.line
    x5:="Command   =" . err.what
    msgbox, 262208,ERROR,Error=`n%x1%`n----------------------`n%x3%`n%x2%`n%x4%  >  %x5%`n--------------------`n
    exitapp
    }
;------------------------------------------------	
WinWait, ahk_pid %PID3%  
fileGetSize,size,%pdfFile%,K
Gui, +hwndParentHWND +Resize +MinSize500x500 -dpiscale
WA:=A_screenwidth,HA:=A_screenheight,xx:=100
aa:="PDF VIEWER AHK-USER =colt  |  " . pdfFile . "  |  "  . size . "kb"
x:=(WA*0)/xx,y:=(ha*0)/xx,w:=(wa*90)/xx,h:=(ha*93)/xx
Gui,show,x%x% y%y% w%w% h%h%,%aa%               ;- I used not maximized GUI
global childHWND
  childHWND := WinExist("ahk_pid " . PID3) + 0  
  DllCall("SetParent", "ptr", childHWND, "ptr", ParentHWND)
WinSet, Style, -0xC00000, ahk_id %childHWND%    ;- remove title and border
WinSet, Style, -0x40000, ahk_id %childHWND%
                                                ;- move the embedded win to match parent
	VarSetCapacity(rect,16)
	DllCall("GetClientRect", "ptr", ParentHWND, "ptr", &rect) 
	hostWidth := NumGet(rect,8,"int")
	hostHeight := NumGet(rect,12,"int")  
WinMove ,ahk_id %childHWND%, , 0, 0, hostWidth, hostHeight
return
;-----------
guiclose:
exitApp
;-----------
esc::exitapp
;==============================================

Ralf_Reddings200244
Posts: 102
Joined: 11 Mar 2023, 14:16

Re: alternative solutions for embedding pdf in gui

01 Feb 2024, 11:07

@colt
Hmm interesting idea. This is a problem I have been trying to solve myself.
The PDF reader/editor that I use PDF-Xchange (premium product), goes further than the other premium PDF editors in that it will let you hide all of its UI and show it back with a hotkey. Its only shortcoming for a 100% UI less is its title bar, this could have been solved if it used a native windows title bar.

I tried to get the developers to provide an option to hide their awful title bar or at least use the native title bar but they just ignored me.

Perhaps give PDF-Xchange a try, its a very advanced PDF reader/editor that can be simplified when needed as well.

As for solving the UI problem of using AutoHotkey to hide the windows undesired UI, have you tried HellBent's Dock-It script. It lets you hide undesired UI for any window by essentially cropping the window.

In my tests it was really efficient and I see it being extremely useful for a lot of things. You will notice the script has its own UI, such as the title bar, if you understood the source code though, I suspect you could easily change it, remove the scripts UI and get it to to work for just one type of window. Its for this reason that I am not using it and put it aside for later, when my AHK skills are good enough.

Hellbent explains how the script works HERE.

The following is a recording I made for you. Both windows are PDF-Xchange windows. I cropped the top window, essentially hiding its titlebar. See attached (I had to upload it like this as the size is too big for ImgUr)


Ahhh...my GIF is too big for the forum too...welp..Here are GIFs Helbent made for the script, which demonstrate what I am talking about anyways. I hope this helps

Image

Image
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: alternative solutions for embedding pdf in gui

04 Feb 2024, 16:39

@Ralf_Reddings200244 Thanks for the suggestion, i did not know about pdfxchange. It does look pretty good. I like that it comes with the activex plugin, but like you said, no way to get toolbarless embed. I tried going fullscreen as embedded but it just escapes the container. My deal breaker is that pdfxchange blocks overwrite by third party application while the pdf is open.

I benchmarked against sumatra and preview time is a little slower, but still impressive. I do not know what pdf i used for the first benchmark so this is a relative result.

Code: Select all

pdfxchange   0.094s
sumatra      0.073s
I have not used hellbent's script, looks like it uses a similar technique to the script i am using. I wonder how it handles resizing of the crop. No doubt it would take some time to understand the source good enough to modify.

One problem i am trying to solve now is to capture events sent to the child window. Being able to intercept guievents like doubleclick and rightclick inside the ahk host application would be useful.
User avatar
Hellbent
Posts: 2109
Joined: 23 Sep 2017, 13:34

Re: alternative solutions for embedding pdf in gui

04 Feb 2024, 19:31

colt wrote:
04 Feb 2024, 16:39

I have not used hellbent's script, looks like it uses a similar technique to the script i am using. I wonder how it handles resizing of the crop. No doubt it would take some time to understand the source good enough to modify.

One problem i am trying to solve now is to capture events sent to the child window. Being able to intercept guievents like doubleclick and rightclick inside the ahk host application would be useful.
My script simply makes your window the child of another window so your events should still be sent just fine.
The way I have it is you set the size of an inner window and then your target window is placed inside with an offset ( neg x and neg y )

So if your target window is 100px wide and you want to display only 80px centered, the target is set as a child and then moved to x := -10.

The display window is then also set as a child of another window that acts as the border/window frame and title.
colt
Posts: 291
Joined: 04 Aug 2014, 23:12
Location: Portland Oregon

Re: alternative solutions for embedding pdf in gui

06 Feb 2024, 09:45

Hellbent wrote: My script simply makes your window the child of another window so your events should still be sent just fine.
I am actually looking for the opposite. I want to intercept the double click windows message sent to the embedded pdf viewer.

How i detect that I double clicked on the pdf now

Code: Select all

~LButton::
~^LButton::
	If(WinActive("ahk_id " . sumatraHWND))
	{
		If ((A_TimeSincePriorHotkey<400) && (A_TimeSincePriorHotkey != -1))
		{
			MouseGetPos, , , id
			WinGetClass, class, ahk_id %id%	
			;tooltip %class%
			if(class == "SUMATRA_PDF_FRAME")
			{
				if(getKeyState("ctrl"))
				{
					;open pdf
				}
				else
				{
					;select pdf on disk
				}				
			}
		}
	}
Return
but would be awesome to selectively intercept messages sent to the embedded window like so

Code: Select all

onMessage(WM_LBUTTONDBLCLK := 0x0203,"dblClickedPDF") ;somehow register for parent and child windows

dblClickedPDF(wParam, lParam, msg, hwnd)
{
	WinGetClass, class, ahk_id %hwnd%	
	;tooltip % class
	if(class == "SUMATRA_PDF_FRAME")
	{
		if(getKeyState("ctrl"))
		{
			;open pdf
		}
		else
		{
			;select pdf on disk
		}				
	}
}
however, the above script only captures the double click events if i am hovering over top level gui elements.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 168 guests