We haven't written about Qt for a long time, so let's do something simple but powerful. The framework has been created for more than ten years ago (soon and 20), but still continues to delight and surprise us thanks to the efforts of the Qt community.
I want to give an example of developing an application with a little effort spent at the interface between desktop application creation and web programming.
A few weeks ago, I was looking for a way to convert specific PDF documents into images, taking into account the possibility of automation and scripting in the future. Of course, there is an old-timer - the ImageMagic package with the convert utility, but unfortunately I was faced with the fact that this tool is not as good as I expected on these files — it doesn’t render many files correctly and that wasn’t happy at all — many of the illustrations were corrupted.
')
I began to look for other tools and although there are a lot of different utilities, but each has its own characteristics, so I never chose which one to use.
Instead, I had an idea, can Qt as a rather mature technology help me? In Qt, it is very easy to create a PDF document using QPrinter, but what about the reverse functionality - to make an image from a PDF page? But there is another well-developed technology - PDF.js.
Is it possible to combine these two technologies? Of course! Qt has a QWebEngineView component. Let's demonstrate in the code:
Quickly based on QMainWindow:
m_webView = new QWebEngineView(this); m_webView->load(url); setCentralWidget(m_webView);
The result will be a window with a web page inside. Now it's the PDF.js turn. The project has a fairly large amount of code, but it is possible to build a compact (minified) version that can be easily embedded in the website. Build example:
$ git clone git://github.com/mozilla/pdf.js.git $ cd pdf.js $ brew install npm $ npm install -g gulp-cli $ npm install $ gulp minified
The result will be the “compiled” version of pdf.js in the build / minified folder, which we copy into our project. Install the starting URL on the local minified / web / viewer.html file
auto url = QUrl::fromLocalFile(app_path+"/minified/web/viewer.html");
Build and run:

It works fine, the approach is correct, but it shows the default PDF file. How can I transfer the file name to javascript? Qt has another great QWebChannel module for this. The idea is that on the C ++ / Qt side, a QWebChannel object is created and it is set up by the channel for the download web page. With this channel, we can register objects that will be available already inside the JavaScript code. Q_PROPERTY properties will be visible from JavaScript:
auto url = QUrl::fromLocalFile(app_path+"/minified/web/viewer.html"); m_communicator = new Communicator(this); m_communicator->setUrl(pdf_path); m_webView = new QWebEngineView(this); QWebChannel * channel = new QWebChannel(this); channel->registerObject(QStringLiteral("communicator"), m_communicator); m_webView->page()->setWebChannel(channel); m_webView->load(url); setCentralWidget(m_webView);
The code above allows you to access a communicator from JavaScript. Now you need to make changes to viewer.html / viewer.js, add a standard qwebchannel.js to make communication work - quite simple:
For viewer.html, simply add the inclusion of qwebchannel.js. For viewer.js, we add QWebChannel initialization and get from the channel the name of the file that will be used instead of the default file:
Code:
var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf'; new QWebChannel(qt.webChannelTransport ,function(channel) { var comm = channel.objects.communicator; DEFAULT_URL = comm.url; ...
Here's how it works: Before loading the page, the web channel is attached and the communicator object is registered. Then, when the viewer.html is loaded for the first time, the QWebChannel JS class is determined. After determining the DEFAULT_URL, a JS QWebChannel object is created and as soon as the communication is established, the attached js function will be called which reads the URL from the communicator object. The new URL will be used instead of the sample file. In the same way, you can transfer the rendered page as an image from JavaScript to C ++ / Qt part of the application.
Having finished changes to PDF.js, just rebuild minified:
$ gulp minified
Copy the minified version to the project folder. Let's finish getting the list of files from the command line arguments and so on.

Done, desktop desktop application PDF viewer for a couple of hours.
→
GitHub