Printing web content

Mac OSX specific forum
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Printing web content

Post by jesperbrannmark »

Hi all.
When I want to print something in windows i can use the webgadget and then a code like this http://www.purebasic.fr/english/viewtop ... 7&p=116305

When I want ot print web content on the mac I use applescript wrapper:

COCOA_AppleScript("tell application "+Chr(34)+"Safari"+Chr(34)+Chr(13)+Chr(10)+"activate"+Chr(13)+Chr(10)+"end tell")
COCOA_AppleScript("tell application "+Chr(34)+"Safari"+Chr(34)+Chr(13)+Chr(10)+"make new document at end of documents"+Chr(13)+Chr(10)+"set url of document 1 to "+Chr(34)+universal_url+Chr(34)+Chr(13)+Chr(10)+"end tell")

and have <body onload=document.print> in the html code.

Is there any remote chance someone with a great deal of knowledge in xcode can do something to print without using applescript? It gives me popups etc that stay and my customers are printing hundreds of times per day...
Any ideas?
WilliamL
Addict
Addict
Posts: 1252
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Printing web content

Post by WilliamL »

Well, I don't have any answers for you but I do have questions. :)

It would appear (haven't tried it) that you are putting both lines in your code to print with AppleScript and are printing with thru Safari. I would like to know if it is possible to send text, thru a string variable, in AppleScript, to the printer (and not thru Safari)? I would like to loop thru the lines of a listviewgadget, for example, and send them to the printer. Oh, right now I save the text to a file and then load the file into TextEdit and print from there. I don't do much printing so it isn't much of a problem right now.

..then the next step will be to change the font and size...
MacBook Pro-M1 (2021), Sequoia 15.4, PB 6.20
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

Now we are on to something.. I will make your day ;-)

Code: Select all

a.s="tell application "+Chr(34)+"TextEdit"+Chr(34)+#CRLF$
a.s+"open (choose file)"+#CRLF$
;or a.s+"open "+chr(34)+"textfile.rtf"+chr(34)+#crlf$
a.s+"tell front document"+#CRLF$
a.s+"print"+#CRLF$
a.s+"close"+#CRLF$
a.s+"End tell"+#CRLF$
a.s+"End tell"+#CRLF$
COCOA_AppleScript(a.s)
Probably web content could be printed by doing something in applescript like:
open document x
set size of window to 10,10 px (so basicly hidden)
print using default printer without a dialogue
close document x

Anyone know how?
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

Duh... "I think we are on to something"..
My status should be downgraded from "enthusiast" to "donkey"..

Try switch out tell application "texteditor" to tell application "safari".

Code in applescript would be:

Code: Select all

tell application "Safari"
	open "/tmp/temp40617.html"
	tell front document
		print
		close
	end tell
	close
end tell
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

That works for local files. If you want a URL this is the applescript code we need

Code: Select all

tell application "Safari"
	make new document at end of documents
	set URL of document 1 to "http://purebasic.com"
	--check if page has loaded
	try
		repeat
			delay 0.5
			tell application "System Events" to ¬
				tell application process "Safari"
					if (name of static text 1 of group 1 of window 1 as text) ¬
						begins with "Contacting" or (name of static text 1 of group 1 ¬
						of window 1 as text) begins with "Loading" then
					else
						exit repeat
					end if
				end tell
		end repeat
	on error
-- not allowed to check
		delay 3
	end try
	
	tell front document
		print
		close
	end tell
	close
end tell

WilliamL
Addict
Addict
Posts: 1252
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Printing web content

Post by WilliamL »

Thanks jasper!

I ran your first code and the file went off to Safari fine but then the printer has a problem (/Library/Printers/Xerox/Filters/xc6120pstops failed). I dunno what that means other than it won't print. Oh, I got the same response in TextEdit.. the printer refused to cooperate.

Would there be a way to have the text file just load into TextEdit so I could re-format and access the printer dialogue? This works but it is just a stab in the dark.

Code: Select all

a.s="tell application "+Chr(34)+"TextEdit"+Chr(34)+#CRLF$
a.s+"open (choose file)"+#CRLF$
;or a.s+"open "+chr(34)+"textfile.rtf"+chr(34)+#crlf$
a.s+"tell front document"+#CRLF$   ;  *
; a.s+"print"+#CRLF$
; a.s+"close"+#CRLF$
a.s+"End tell"+#CRLF$   ;  *
a.s+"End tell"+#CRLF$
COCOA_AppleScript(a.s)
Take out * these two lines and it gets ugly. The debugger crashes!
MacBook Pro-M1 (2021), Sequoia 15.4, PB 6.20
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

I think you should be able to do a keystroke P with command (similar to doing the CMD-P shortcut to print)

Code: Select all

tell application "System Events" 
tell process "ProcessName" 
keystroke "p" 
end tell 
end tell 
or maybe just throw in a

Code: Select all

keystroke "P" using {command down}
You can always put "TRY" and "END TRY" in the Applescript code AND you can see the output if doing
debug COCOA_APPLESCRIPT("activate")
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

Final procedure for Print webcontent:

Code: Select all

Procedure Printurl(url.s)      
  a.s="tell application "+Chr(34)+"Safari"+Chr(34)+#CRLF$
  a.s+"make new document at end of documents"+#CRLF$
  a.s+"set URL of document 1 to "+Chr(34)+url+Chr(34)+#CRLF$
  a.s+"try"+#CRLF$
  a.s+"repeat"+#CRLF$
  a.s+"delay 0.5"+#CRLF$
  a.s+"tell application "+Chr(34)+"System Events"+Chr(34)+" to "
  a.s+"tell application process "+Chr(34)+"Safari"+Chr(34)+#CRLF$
  a.s+"if (name of static text 1 of group 1 of window 1 as text) begins with "+Chr(34)+"Contacting"+Chr(34)
  a.s+" or (name of Static text 1 of group 1 of window 1 as text) begins with "+Chr(34)+"Loading"+Chr(34)+" then "+#CRLF$
  a.s+"else"+#CRLF$
  a.s+"exit repeat"+#CRLF$
  a.s+"end if"+#CRLF$
  a.s+"end tell"+#CRLF$
  a.s+"end repeat"+#CRLF$
  a.s+"on error"+#CRLF$
  a.s+"delay 5"+#CRLF$
  a.s+"end try"+#CRLF$
  a.s+"tell front document"+#CRLF$
  a.s+"print"+#CRLF$
  a.s+"close"+#CRLF$
  a.s+"end tell"+#CRLF$
  a.s+"close"+#CRLF$
  a.s+"end tell"+#CRLF$  
  Debug a.s     
  COCOA_AppleScript(a.s)
EndProcedure
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Printing web content

Post by wilbert »

jesperbrannmark wrote:Is there any remote chance someone with a great deal of knowledge in xcode can do something to print without using applescript? It gives me popups etc that stay and my customers are printing hundreds of times per day...
Any ideas?
Does this help ?

Code: Select all

ImportC ""
  objc_getClass(name.s)
  sel_registerName(str.s)
  objc_msgSend(theReceiver, theSelector, arg1 = #Null, arg2 = #Null)
  HIWebViewGetWebView(inView)
EndImport

Sel_mainFrame = sel_registerName("mainFrame")
Sel_frameView = sel_registerName("frameView")
Sel_printOperationWithPrintInfo = sel_registerName("printOperationWithPrintInfo:")
Sel_runOperation = sel_registerName("runOperation")

SharedPrintInfo = objc_msgSend(objc_getClass("NSPrintInfo"), sel_registerName("sharedPrintInfo"))

If OpenWindow(0, 0, 0, 600, 340, "WebPrint", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ButtonGadget(0, 10, 10, 100, 20, "Print")
  
  PBWebView = WebGadget(#PB_Any, 10, 50, 580, 280, "http://www.purebasic.com")
  WebView = HIWebViewGetWebView(GadgetID(PBWebView))
  MainFrame = objc_msgSend(WebView, Sel_mainFrame)
  
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
          
        Case 0; *** Print content *** 

          FrameView = objc_msgSend(MainFrame, Sel_frameView)
          PrintOperation = objc_msgSend(FrameView, Sel_printOperationWithPrintInfo, SharedPrintInfo)
          objc_msgSend(PrintOperation, Sel_runOperation)          
          
      EndSelect
    EndIf      
  Until EventID = #PB_Event_CloseWindow
  
EndIf
jesperbrannmark
Enthusiast
Enthusiast
Posts: 536
Joined: Mon Feb 16, 2009 10:42 am
Location: sweden
Contact:

Re: Printing web content

Post by jesperbrannmark »

OMG

Amazing. Is there a way to have it print with default printer (no printerrequester)
Also I noticed that if I move the lines that does the printing

Code: Select all

            FrameView = objc_msgSend(MainFrame, Sel_frameView)
          PrintOperation = objc_msgSend(FrameView, Sel_printOperationWithPrintInfo, SharedPrintInfo)
          objc_msgSend(PrintOperation, Sel_runOperation)          
To just before the repeat (so like doing an autoprint), we can actually print before the entire page is loaded. I had a similar problem in windows http://www.purebasic.fr/english/viewtop ... 13&t=46816 where it was solved with

Code: Select all

Repeat    ;check if page has begun to load
    Delay(20)
    While WindowEvent(): Wend
  Until GetGadgetText(gadget)=url
  Repeat     ;check if page is done loading
    WebObject\get_Busy(@IsBusy.l)
    Delay(20)
    While WindowEvent(): Wend
  Until IsBusy = 0
A funny thing with your code is that if i do a

Code: Select all

HideGadget(PBWebView,1)
it is hidden until i press the print button.... then it becomes visible. I also tried moving the webgadget outside of the window and that works for hiding the webgadget.

Thanks :-)

J
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Printing web content

Post by wilbert »

You don't have to hide the gadget. You can simply set its size to zero.

Code: Select all

ImportC ""
  objc_getClass(name.p-ascii)
  sel_registerName(str.p-ascii)
  objc_msgSend(theReceiver, theSelector, arg1 = #Null, arg2 = #Null)
  HIWebViewGetWebView(inView)
EndImport

Procedure MsgSend(receiver, selector.s, arg1 = #Null, arg2 = #Null)
  ProcedureReturn objc_msgSend(receiver, sel_registerName(selector), arg1, arg2)
EndProcedure

Procedure MsgSendF(receiver, selector.s, arg1.f)
  objc_msgSend(receiver, sel_registerName(selector), PeekL(@arg1))
EndProcedure

Procedure ClassMsgSend(class.s, selector.s, arg1 = #Null, arg2 = #Null)
  ProcedureReturn objc_msgSend(objc_getClass(class), sel_registerName(selector), arg1, arg2)
EndProcedure

Procedure NSString(string.s)
  Length = Len(String)
  UniString = AllocateMemory(Length * 2 + 2)
  PokeS(UniString, string, Length, #PB_Unicode)
  Result = ClassMsgSend("NSString", "stringWithCharacters:length:", UniString, Length)
  FreeMemory(UniString)
  ProcedureReturn Result
EndProcedure

; get a shared print info object and set it up

PrintInfo = ClassMsgSend("NSPrintInfo", "sharedPrintInfo")
MsgSend(PrintInfo, "setOrientation:", 0); // 0 = portrait, 1 = landscape
MsgSend(PrintInfo, "setHorizontallyCentered:", #False)
MsgSend(PrintInfo, "setVerticallyCentered:", #False)
MsgSendF(PrintInfo, "setTopMargin:", 56.7); // 56.7 point = about 2 cm
MsgSendF(PrintInfo, "setLeftMargin:", 70.9); // 70.9 point = about 2.5 cm
MsgSendF(PrintInfo, "setBottomMargin:", 56.7)
MsgSendF(PrintInfo, "setRightMargin:", 56.7)

; main code

If OpenWindow(0, 0, 0, 600, 340, "WebPrint", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ButtonGadget(0, 10, 10, 100, 20, "Print")
  
  PBWebView = WebGadget(#PB_Any, 0, 0, 0, 0, "")
  WebView = HIWebViewGetWebView(GadgetID(PBWebView))
  MainFrame = MsgSend(WebView, "mainFrame")
  
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
          
        Case 0; *** Print purebasic site content ***
          
          AutoreleasePool = ClassMsgSend("NSAutoreleasePool", "new")
          
          ; *** Set URL content ***
          
          MsgSend(WebView, "setMainFrameURL:", NSString("http://www.purebasic.com"))
          
          ; ***
          
          FrameView = MsgSend(MainFrame, "frameView")
          Repeat
            Delay(100)
            IsBusy = MsgSend(WebView, "isLoading")
            While WindowEvent() : Wend
          Until IsBusy = 0
          PrintOperation = MsgSend(FrameView, "printOperationWithPrintInfo:", PrintInfo)
          MsgSend(PrintOperation, "setShowsPrintPanel:", #False)          
          MsgSend(PrintOperation, "runOperation")
          MsgSend(AutoreleasePool, "drain")
          
      EndSelect
    EndIf      
  Until EventID = #PB_Event_CloseWindow
  
EndIf
Last edited by wilbert on Wed Jul 06, 2011 1:02 pm, edited 2 times in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Printing web content

Post by wilbert »

It's also possible by the way to set HTML content directly instead of loading from a file.
Here's how that can be done

Code: Select all

ImportC ""
  objc_getClass(name.p-ascii)
  sel_registerName(str.p-ascii)
  objc_msgSend(theReceiver, theSelector, arg1 = #Null, arg2 = #Null)
  HIWebViewGetWebView(inView)
EndImport

Procedure MsgSend(receiver, selector.s, arg1 = #Null, arg2 = #Null)
  ProcedureReturn objc_msgSend(receiver, sel_registerName(selector), arg1, arg2)
EndProcedure

Procedure MsgSendF(receiver, selector.s, arg1.f)
  objc_msgSend(receiver, sel_registerName(selector), PeekL(@arg1))
EndProcedure

Procedure ClassMsgSend(class.s, selector.s, arg1 = #Null, arg2 = #Null)
  ProcedureReturn objc_msgSend(objc_getClass(class), sel_registerName(selector), arg1, arg2)
EndProcedure

Procedure NSString(string.s)
  Length = Len(String)
  UniString = AllocateMemory(Length * 2 + 2)
  PokeS(UniString, string, Length, #PB_Unicode)
  Result = ClassMsgSend("NSString", "stringWithCharacters:length:", UniString, Length)
  FreeMemory(UniString)
  ProcedureReturn Result
EndProcedure

; get a shared print info object and set it up

PrintInfo = ClassMsgSend("NSPrintInfo", "sharedPrintInfo")
MsgSend(PrintInfo, "setOrientation:", 0); // 0 = portrait, 1 = landscape
MsgSend(PrintInfo, "setHorizontallyCentered:", #False)
MsgSend(PrintInfo, "setVerticallyCentered:", #False)
MsgSendF(PrintInfo, "setTopMargin:", 56.7); // 56.7 point = about 2 cm
MsgSendF(PrintInfo, "setLeftMargin:", 70.9); // 70.9 point = about 2.5 cm
MsgSendF(PrintInfo, "setBottomMargin:", 56.7)
MsgSendF(PrintInfo, "setRightMargin:", 56.7)

; main code

If OpenWindow(0, 0, 0, 600, 340, "WebPrint", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ButtonGadget(0, 10, 10, 100, 20, "Print")
  
  PBWebView = WebGadget(#PB_Any, 0, 0, 0, 0, "")
  WebView = HIWebViewGetWebView(GadgetID(PBWebView))
  MainFrame = MsgSend(WebView, "mainFrame")
  
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
          
        Case 0
          
          AutoreleasePool = ClassMsgSend("NSAutoreleasePool", "new")
          
          ; *** Set HTML content directly using a string
          
          HTMLString = NSString("This is a <b>test</b><hr><i>Italic</i>")
          MsgSend(MainFrame, "loadHTMLString:baseURL:", HTMLString, #Null)

          ; *** 
          
          FrameView = MsgSend(MainFrame, "frameView")
          Repeat
            Delay(100)
            IsBusy = MsgSend(WebView, "isLoading")
            While WindowEvent() : Wend
          Until IsBusy = 0
          PrintOperation = MsgSend(FrameView, "printOperationWithPrintInfo:", PrintInfo)
          MsgSend(PrintOperation, "setShowsPrintPanel:", #False)          
          MsgSend(PrintOperation, "runOperation")
          MsgSend(AutoreleasePool, "drain")
          
      EndSelect
    EndIf      
  Until EventID = #PB_Event_CloseWindow
  
EndIf
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Printing web content

Post by wilbert »

One more example.
This one shows how to use inline svg to draw vector shapes.

Code: Select all

ImportC ""
  objc_getClass(name.p-ascii)
  sel_registerName(str.p-ascii)
  objc_msgSend(theReceiver, theSelector, arg1 = #Null, arg2 = #Null, arg3 = #Null, arg4 = #Null)
  HIWebViewGetWebView(inView)
EndImport

Procedure MsgSend(receiver, selector.s, arg1 = #Null, arg2 = #Null, arg3 = #Null, arg4 = #Null)
  ProcedureReturn objc_msgSend(receiver, sel_registerName(selector), arg1, arg2, arg3, arg4)
EndProcedure

Procedure MsgSendF(receiver, selector.s, arg1.f)
  objc_msgSend(receiver, sel_registerName(selector), PeekL(@arg1))
EndProcedure

Procedure ClassMsgSend(class.s, selector.s, arg1 = #Null, arg2 = #Null)
  ProcedureReturn objc_msgSend(objc_getClass(class), sel_registerName(selector), arg1, arg2)
EndProcedure

Procedure NSString(string.s)
  Length = Len(String)
  UniString = AllocateMemory(Length * 2 + 2)
  PokeS(UniString, string, Length, #PB_Unicode)
  Result = ClassMsgSend("NSString", "stringWithCharacters:length:", UniString, Length)
  FreeMemory(UniString)
  ProcedureReturn Result
EndProcedure

; get a shared print info object and set it up

PrintInfo = ClassMsgSend("NSPrintInfo", "sharedPrintInfo")
MsgSend(PrintInfo, "setOrientation:", 0); // 0 = portrait, 1 = landscape
MsgSend(PrintInfo, "setHorizontallyCentered:", #False)
MsgSend(PrintInfo, "setVerticallyCentered:", #False)
MsgSendF(PrintInfo, "setTopMargin:", 56.7); // 56.7 point = about 2 cm
MsgSendF(PrintInfo, "setLeftMargin:", 70.9); // 70.9 point = about 2.5 cm
MsgSendF(PrintInfo, "setBottomMargin:", 56.7)
MsgSendF(PrintInfo, "setRightMargin:", 56.7)

; main code

If OpenWindow(0, 0, 0, 600, 340, "WebPrint", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ButtonGadget(0, 10, 10, 100, 20, "Print")
  
  PBWebView = WebGadget(#PB_Any, 0, 0, 0, 0, "")
  WebView = HIWebViewGetWebView(GadgetID(PBWebView))
  MainFrame = MsgSend(WebView, "mainFrame")
  
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_Gadget
      Select EventGadget()
          
        Case 0
          
          AutoreleasePool = ClassMsgSend("NSAutoreleasePool", "new")
          
          ; *** Set content directly using a string
          
          XML.s = "<html xmlns='http://www.w3.org/1999/xhtml'><head></head><body>"
          XML = XML + "This is a <b>test</b><hr/><i>Italic</i><br/>"
          XML = XML + "<svg xmlns='http://www.w3.org/2000/svg' width='500' height='400'>"
          XML = XML + "<rect x='0' y='0' width='500' height='400' style='fill:yellow; stroke:blue; stroke-width:12;' />"
          XML = XML + "<polygon points='50,50 50,300 300,300' style='fill:blue; stroke:black;' />"
          XML = XML + "</svg>"
          XML = XML + "</body></html>"
          
          XMLData = MsgSend(NSString(XML), "dataUsingEncoding:", 10)
          MsgSend(MainFrame, "loadData:MIMEType:textEncodingName:baseURL:", XMLData, NSString("image/svg+xml"), NSString("ISO-10646-UCS-2"), #Null)

          ; *** 
          
          FrameView = MsgSend(MainFrame, "frameView")
          Repeat
            Delay(100)
            IsBusy = MsgSend(WebView, "isLoading")
            While WindowEvent() : Wend
          Until IsBusy = 0
          PrintOperation = MsgSend(FrameView, "printOperationWithPrintInfo:", PrintInfo)
          MsgSend(PrintOperation, "setShowsPrintPanel:", #False)          
          MsgSend(PrintOperation, "runOperation")
          MsgSend(AutoreleasePool, "drain")
          
      EndSelect
    EndIf      
  Until EventID = #PB_Event_CloseWindow
  
EndIf
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Printing web content

Post by wilbert »

I converted my solution to print web content into a userlib.
http://www.purebasic.fr/english/viewtop ... 19&t=46856
Post Reply