convert HTML into PDF/PNG [duplicate] - java

I am trying to use Headless feature of the Chrome to convert a html to pdf. However, i am not getting output at all. Console doesn't show any error as well. I am running below commands in my windows m/c.
chrome --headless --disable-gpu --print-to-pdf
I tried all the various options. Nothing is being generated. I am having chrome version 60

Command Line --print-to-pdf
By default, --print-to-pdf attempts to create a PDF in the User Directory. By default, that user directory is where the actual chrome binary is stored, which is the specific version folder for the version you're running - for example, "C:\Program Files (x86)\Google\Chrome\Application\61.0.3163.100". And, by default... Chrome is not allowed to write to this folder. You can watch it try, and fail, by adding --enable-logging to your command.
So unfortunately, by default, this command fails.*
You can solve this by either providing a path in the argument, where Chrome can write - like
--print-to-pdf="C:\Users\Jane\test.pdf"
Or, you can change the User Directory:
--user-data-dir="C:\Users\Jane"
One reason you might prefer to change the User Directory is if you want the PDF to automatically receive its name from the webpage; Chrome looks at the title tag and then dumps it like <title>My Page</title> => My-Page.pdf
*I think this default behavior is super confusing, and should be filed as a bug against Chrome. However, apparently part of the Chrome team is outright opposed to the mere existence of this command line option, and instead believe it would be better to force everyone using it to get a node.js build going with Puppeteer and the flag removed outright.
Limitations of Command Line on Windows
Invoking chrome in this way will work fine for example in a local dev env on IIS Express with Visual Studio, but it will fail, even in headless mode, on a server running IIS, because IIS users are not given interactive/desktop permissions, and the way chrome grabs this PDF actually requires interactive/desktop permissions. There are complicated ways to provide those permissions, but anyplace you read up on how begins with DON'T PROVIDE INTERACTIVE/DESKTOP PERMISSIONS. Further, the above risk of Chrome one day getting rid of the command-line makes working even harder to get it working an iffy proposition.
Alternatives to chrome command line
wkhtmltopdf
Behind the scenes Chrome simply uses wkhtmltopdf. I haven't tried it but it's likely this will get the job done. The one minor risk is that when producing PDFs in Chrome, testing is obvious: View the page in Chrome. Open Print Preview if you're nervous. In wkhtmltopdf, it's actually a different build of Chromium, and that may produce rendering differences. Maybe.
Selenium
Another alternative is to get ahead of the group looking to get rid of --print-to-pdf and use the browser dev API (via Selenium) as they prefer.**
private static void pdfSeleniumImpl(string url, string pdfPath)
{
var options = new OpenQA.Selenium.Chrome.ChromeOptions();
options.AddArgument("headless");
using (var chrome = new OpenQA.Selenium.Chrome.ChromeDriver(options))
{
chrome.Url = url;
var printToPdfOpts = new Dictionary<string, object>();
var resultDict = (Dictionary<string, object>)
chrome.ExecuteChromeCommandWithResult(
"Page.printToPDF", printToPdfOpts);
dynamic result = new DDict(resultDict);
string data = result.data;
var pdfFile = Convert.FromBase64String(data);
System.IO.File.WriteAllBytes(pdfPath, pdfFile);
}
}
The DDict above is the GracefulDynamicDictionary from another of my answers.
https://www.nuget.org/packages/GracefulDynamicDictionary/
https://github.com/b9chris/GracefulDynamicDictionary
https://stackoverflow.com/a/24192518/176877
Ideally this would be async, since all the calls to Selenium are actually network commands, and writing that file could take a lot of Disk IO. The data returned from Chrome is actually a Stream as well. However Selenium's conventionally used library does not use async at all unfortunately, so it would take upgrading that library or identifying a solid async Selenium library for .Net to really do this right.
https://github.com/puppeteer/puppeteer/blob/master/lib/Page.js#L1007
https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
**The Page.pdf chrome Dev API command is also deprecated, so if that contingent gets their way, neither the command line nor the Dev API will work. That said it looks like those lobbying to wreck it gave up 2 years ago.

This is working:
chrome --headless --disable-gpu --print-to-pdf=file1.pdf https://www.google.co.in/
creates file in the folder: C:\Program Files (x86)\Google\Chrome\Application\61.0.3163.100.

Do not forget to open your terminal/cmd with admin rights :) Otherwise it will just not save the file at all.

I was missing "=" after print-to-pdf command.
The correct command is:
chrome --headless --disable-gpu --print-to-pdf="C:/temp/name.pdf" https://www.google.com/
Now it is working.

extending the brilliantly simple answer by suraj, I created a small function that is in my sourced path so it works like a CLI tool:
function webtopdf(){
chromium-browser --headless --disable-gpu --print-to-pdf=$2 $1
}
so a quick
webtopdf https://goo.com/some-article some-article.pdf
does the job for me now

This worked for me in windows
start chrome --headless --disable-gpu
--print-to-pdf=C:\Users\username\pdfs\chrome.pdf --no-margins https://www.google.com

Currently, this is only available for Linux and Mac OS.

Related

What are possible ways to modify or customize an installer after it was built and signed?

We would like to brand a piece of software based on which customer's website it is downloaded from. E.g. by showing the customer's logo etc. All we need is an ID, the software can handle the rest of the customization at runtime based on that.
The number of customizations is potentially large, and we would like to avoid prebuilding and storing these installers.
I'm open to consider all options, especially some out-of-the-box ideas.
I think it is impossible to change a signed installer (exe/dmg) without breaking the signature.
Some ideas I'm toying with (and their trade-offs):
Store the ID in the installer download filename (Con: Brittle, browsers might change the name or append a suffix to avoid duplicate names)
Ask the user to enter a code shown on the download page (Con: some inconvenience for the user)
Provide a zip with installer and config-file next to it (Con: some users will not manage to unzip, or only unzip the installer without the config file)
On Linux the installer shell script can be modified at download time, as the script cannot be signed.
Set up a server that builds and signs installers on the fly at the time of the download request. To speed this up, it could be yet another installer wrapping the main installer, and it's only task would be to extract and run the main installer with the ID parameter. (Con: complex infrastructure, code signing certificates on the public facing server, very slow for MacOS notarization)
Chromium-based browsers like Google Chrome, Chromium, Opera, Microsoft Edge, etc. save the URL of origin and the referrer URL for all downloaded files on Windows 10 (only on NTFS file systems) and Linux (only on Ext4).
For details see for example here. On Windows the metadata is also accessible from command line or direcly from Java.
There seems to be a similar feature on Mac. See for example this question on superuser.
Accessing this metadata from within your installer could help to customize the behavior of your installer. While the data will not be available in all setups (e.g. Internet Explorer stores only a zone ID and no URL) and may get lost (e.g. a user deletes the data or copies the file to a file system that does not support metadata) it could propably cover the majority of your users. Asking users to enter a code when the metadata is not found could still be used as a fallback.
Main concern I would have with this approach is that the Chromium developers may decide to remove this feature in near future or make it optional, like the developers of wget (see for example here)
On latest Windows 10 I still get the following metadata for a downloaded file with both, latest Google Chrome and Microsoft Edge Browser:
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://httpd.apache.org/
HostUrl=https://mirror.klaus-uwe.me/apache//httpd/httpd-2.4.46.tar.bz2

Java - Get title of active window

I need to get title of current active window(for example right now: Google Chrome). I search smth in internet, and found only this javax.swing.FocusManager.getCurrentManager().getActiveWindow(); . But i don't know how to get PROGRAM TITLE with that code.
If you are fine with a non-java solution that will work for Windows computers, there is a programming language called AutoHotkey (AHK) that is more suited for this kind of task. There exists a popular script called "Window Spy" (also known as "ActiveWindowInfo") that has the ability to view the title of the active window, as well as other information such as PID, the name of the .exe that the Window is an instance of, and etc. (I have attached a screenshot of what Window Spy told about the Google Chrome window I was using to write this reply. In the screenshot, I have also indicated which part of it tells you the Title of the Window).
This script comes with most AutoHotkey IDEs (such as SciTe4Autohotkey if you are interested). However, you can perfectly well run the script without an IDE.
Here are some quickstart instructions:
First, you will need to install AHK itself (here is the official website)
You can download the script itself by navigating to https://raw.githubusercontent.com/fincs/SciTE4AutoHotkey/master/source/tools/ActiveWindowInfo.ahk in Chrome, using the shortcut Control+S to save the script to your computer. Make sure that when you download the script, it ends with a .ahk instead of the .txt that it will default to.
Navigate to the file that you downloaded and run it with AutoHotkey (It should be the default thing that happens if you double click the .ahk file with AutoHotkey installed).
If you need any more info on how to use the script, please let me know.

HostServices.showDocument: Default Application in Linux

How does the method showDocument in the class HostServices determine the application to execute the desired action in Linux?
I'm using Manjaro Linux and it always opens URLs in Firefox even though Chrome is defined as my standard browser. All the other applications I'm using are starting the correct browser when clicking a link.
There are several ways to define standard applications in Linux. I have checked quite a few now, but I haven't yet been able to find out which one JavaFX uses.
Edit:
Using Desktop.getDesktop().browse(URI("http://www.google.de")) works and opens the link in Chrome.
I've since posted this question on the openjfx-dev-Mailinglist. The code which determines the default browser in Linux can be found in line 174 and following in the class HostServicesDelegate.java.
Chromium is missing from the list of known browsers and that's what I'm using. This is the reason why this doesn't as expected on my machine. See also the thread on the mailinglist.

Downloading Files with ChromeDriver

I have a project where I need to download an audio file in ChromeDriver. The behavior here is different from in regular Chrome, where if I visit the URL, it'll automatically start downloading a file. If I do the same thing manually in ChromeDriver, it will not download the file.
I've tried different configurations of the chrome options/preferences. I've also found options that worked with old versions of chrome, that no longer work anymore.
Here is one of the better resources I found, but it still didn't work, even with their updated blog post
https://dkage.wordpress.com/2012/03/10/mid-air-trick-make-selenium-download-files/
When I attempt to use his solution, my chromedriver abruptly crashes itself in a non chrome-esque way. It just disappears. Not "Something went wrong" page like you'd normally expect. I end up with Java not being able to find my Session, cause it stopped existing.
Has anyone been successful at downloading files through Selenium webdriver in Chrome? If I need to use another browser, I can.
I'm currently using Chrome Canary.
I have the same problem. One solution that might work is to use another library, that is able to operate outside of the browser. I found these stackoverflow post discussiong this issue:
https://sqa.stackexchange.com/questions/2197/how-to-download-a-file-using-seleniums-webdriver
it contains this blogpost wich gives you some sugestions.
https://blog.codecentric.de/en/2010/07/file-downloads-with-selenium-mission-impossible/
Window automation
The first approach smells like “brute force”: when searching the net for a solution to the problem, you easily end up with suggestions, to control the native window with some window automation software like AutoIt. Means you have to prepare AutoIt such, that it waits for any browser download dialog, the point at which Selenium is giving up, takes control of the window, saves the file, and closes the window. After that Selenium can continue as usual.
This might eventually work, but I found it to be techical overkill. And as it turned out, there was a much simpler solution to the problem.
Change the browsers default behaviour
The second possibility is to change the default behaviour of the browser. When clicking on a PDF for example, the browser should not open a dialog and ask the user what to do with the file, but rather save it without comments and questions in a predefined directory. To accomplish that, a file download has to be initiated manually, saved to disk and marked as the default behaviour for these file types from now on.
Well, that could work. You “only” have to assure that all developers, hudson instances, etc. share the same browser profile. And depending on the amount of different file types, that could be some manual work.
Direct download
Taking a step back, why do we want to download the file with Selenium in the first place? Wouldn’t it be much cooler, to download the file without Selenium, but rather with wget? You would have solved the second problem as you go. Seems a good idea, since wget is not only available for Linux but also for Windows.
Problem solved? Not quite: what about files, that are not freely accessible? What, when I first need to create some state with Selenium in order to access a generated file? The solution seems ok for public files, but is not applicable for all situations.

Selecting folders, not files, in Google Chrome

I'm creating an extension for Google Chrome, so any code has to be compatible with Chrome and Chrome only. In this extension, I need the user to select a folder from his local machine. This simple task is becoming quite a problem. The chrome extensions options page will not run applets, so I couldn't really do Java. It's Google Chrome only so an ActiveX object is out of the question as well. I just need a simple way of selecting a folder(not a file) and passing its path to Javascript. Might this be possible in Flash Actionscript? It seems FileReference and FileReferenceList classes in AS only allow you to choose a file, and not a folder. Is there another possibility besides Flash? All the options page files DO rest on the local users machine, so it's not server side.
Thank you for your time.
You can use the webkit-directory attribute on your element to select directories and get the same sort of result as from the "multiple" attribute.
A demo of this: http://www.thecssninja.com/demo/webkitdirectory/
The chromium bug: http://crbug.com/58977

Categories