It took me quite some time to figure out how to print properly from a web application. I will explain here how I did it, so you don't have to spend the same time.
Google Cloud Print API uses OAuth 2.0 for authorization.
As explained here on the Google Developer page, the best way to use OAuth with the Google API is with a Google service account. Create a service account as explained on the Google Developer page.
To use OAuth a library is required. Google has published the Google API PHP client library. If you want to use the examples from the Developer pages, you need to use version 1 of the library. In this article I use version 2 of the library.
➡️ Tip |
---|
If you need to run Google API PHP client library on PHP 5.4, make sure you use Guzzle Http version 5 instead of version 6, because the latter is not compatible with PHP 5.4. You can configure the right version in the composer.json file of the API Client library. |
Make sure the private key of your service account is accessible by your web application and that you include the library. Then you can use the following code to setup a request to the API with authorization.
$service_account_email = 'SERVICE ACCOUNT EMAIL';
$key_file_location = 'PRIVATE KEY FILE LOCATION';
$client = new Google_Client();
$client->setAuthConfig($key_file_location);
$client->setApplicationName("APPLICATION NAME");
$client->setScopes(array('https://www.googleapis.com/auth/cloudprint'));
$httpClient = $client->authorize();
Now we can send a first request to the API. We start with a search
request to see which printers are available.
$params = array();
/* Use form_params instead of body for version 6 of Guzzle Http */
$response = $httpClient->post('https://www.google.com/cloudprint/search', array('body'=>$params));
echo $response->getBody();
The response will be a list with available printers. One printer will be available, the Google Drive printer.
We need to share the printer with the service account and the printer needs to be accepted by the service account. The Google Cloud Print management interface is not available for the service account, so we need another way to accept the printer.
This Stackoverflow post documents a way to accept printers with the API, but I didn't get this to work.
I managed to share the printer with the following steps:
- Make a Google discussion group and add the service account to the group as member
- Add a second user to the group as administrator (explicitly select the user, do not use "all users")
- Share the printer with the group (by e-mail address)
- Now the administrator of the group can accept the printer for all members in the group
You can check with the search
request whether the printer is available to the service account. You can find the printer id in the management interface or in the search
response.
Now we have authorized access to a printer, we can print.
$params = array(
'printerid' => 'PRINTER ID',
'title' => 'TITLE',
'ticket' => '{"version":"1.0","print":{}}',
'content' => 'data:application/pdf;base64,' . base64_encode(file_get_contents('PDF FILE PATH')),
'contentType' => 'dataUrl'
);
/* Use form_params instead of body for version 6 of Guzzle Http */
$response = $httpClient->post('https://www.google.com/cloudprint/submit', array('body'=>$params));
echo $response->getBody();
The ticket
parameter contains printer instructions like media size and number of copies. If you would like to have an example of valid ticket
contents, print the document with Chrome to Cloud Print and capture the API request with Fiddler (Windows only).
When I printed PDFs, the documents were not properly aligned on the paper. When I printed the same document with Chrome and Cloud Print, the document was properly aligned. Chrome modifies the PDF with PDFium before sending it to Cloud Print.
I still have to figure out the exact issues with the PDF files which cause this issue, but pre-processing the PDFs with the following GhostScript command solves at least the alignment issue for now.
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile=OUTPUT.pdf INPUT.pdf
Thank you for reading this tutorial. I hope it is helpful to you, if it was, please leave behind a comment. If you have any tips, questions or remarks, you are also welcome to comment.
thanks for the example of the b64 dataUrl. i’ve been attempting to use an application/pdf mime type.