Open ecrypted PDF with C++/Qt (known passwords) - c++

I am stuck with the following issue:
I need to open encrypted PDF files (with known passwords) from a simple C++/Qt program with the default PDF editor on the PC. I know the password to the PDFs, this is not the issue here.
Alternatively, it would be also ok, if the PDF is rendered within my Qt window, but I think that this would be even more complicated.
I know that I am able to open standard PDFs with fairly simple commands like
QDesktopServices::openUrl(QUrl("file:///home/.../fileName.pdf"));
But I do not know any option to insert a password here.
Does anybody know a way how to do this (preferably with mainly standard C++/Qt methods)?
Thank you very much and best regards

You may decrypt the original PDF file first, for instance with the qpdf library saving the output to a temporary file, and then open this temporary file with QDesktopServices::openUrl().
To decrypt a PDF file with the qpdf command line utility, the syntax is:
qpdf --password=KNOWNPASSWORD --decrypt input.pdf output.pdf
Here is a simple example of PDF decryption using the qpdf library from a Qt program, using the pkg-config utility to configure the dependency.
test.pro
QT = core
CONFIG += c++11 console link_pkgconfig
TEMPLATE = app
SOURCES += main.cpp
PKGCONFIG += libqpdf
main.cpp
#include <QCoreApplication>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFWriter.hh>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString inputFile = "input.pdf";
QString outputFile = "output.pdf";
QString userPassword = "USERPASS";
try
{
QPDF qpdf;
qpdf.processFile(inputFile.toLocal8Bit(), userPassword.toLocal8Bit());
QPDFWriter w(qpdf, outputFile.toLocal8Bit());
w.setPreserveEncryption(false);
w.write();
}
catch (std::exception& e)
{
qFatal("Error. %s", e.what());
}
}

Related

"Failed to setup resampler" when starting QAudioSink

I'm porting some QtMultimedia code from Qt 5.15 to 6.4.1. The following program, when built with Qt 6.4.1 on Windows:
int main (int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QAudioDevice device = QMediaDevices::defaultAudioOutput();
QAudioFormat format = device.preferredFormat();
QAudioSink *output = new QAudioSink(device, format);
output->start();
return a.exec();
}
Fails to start the audio output, printing the following message:
qt.multimedia.audiooutput: Failed to setup resampler
The equivalent code in Qt5 (using QAudioDeviceInfo and QAudioOutput) seems to run fine. What am I missing here?
Apparently, it's a bug in Qt 6.4.1 on Windows, where, as the user johnco3 discovered in that forum post, for some reason QAudioSink is looking for a DLL named "mfplat.dll.dll" when it should be looking for "mfplat.dll" (it adds an extra ".dll" suffix).
The correctly named version of this DLL lives in the Windows system directory (e.g. C:\Windows\System32\mfplat.dll), so there are a couple of workaround until the bug is fixed:
Go back to Qt 6.4.0, apparently it's a new issue in 6.4.1, or
Copy mfplat.dll to somewhere in the DLL path then rename it to "mfplat.dll.dll":
Either copy it to the application executable's directory and rename it there, or
Create some folder somewhere, copy and rename it there, then add that folder to the PATH environment variable.
It's a somewhat silly bug, but alas. At least the workaround exists and can be easily undone when the bug is eventually fixed.
See also:
https://bugreports.qt.io/browse/QTBUG-108383 (johnco3's bug report)
https://bugreports.qt.io/browse/QTBUG-108669 (a duplicate bug report; I filed it before I found any of this)

Qt plugin not loaded

I have problems loading the built-in plugins for iconengines for a deployed application. Below is a minimal program to show the problem. It is not exactly the same, because Qt scans the plugin directories at start and registers it according to the file suffix, but I hope when I can get the minimal program to run, then the automatic scanning works, too.
main.cpp:
#include <QCoreApplication>
#include <QPluginLoader>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QPluginLoader loader("C:/Qt/5.15.1/msvc2019_64/plugins/iconengines/qsvgicon.dll");
if (loader.load()) {
qDebug() << "load ok";
} else {
qDebug() << "load failed";
}
return a.exec();
}
and PluginTest.pro:
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
SOURCES += main.cpp
When I start it from the Qt Creator IDE, version 4.13.1, with Visual Studio 2019, 64 bit compiled, it prints "load ok". Now I do this from a "x64 Native Tools Command Prompt for VS 2019" command prompt in the project directory:
set PATH=%PATH%;C:\Qt\5.15.1\msvc2019_64\bin
mkdir deploy
copy release\PluginTest.exe deploy
windeployqt --release release\PluginTest.exe --plugindir deploy\QtPlugins
When I start PluginText.exe from the command prompt in the deploy directory, I get the output "load failed".
Additional information: when I set set qt_debug_plugins=1 and start the real application, I see these errors:
QFactoryLoader::QFactoryLoader() checking directory path "C:/projects/deploy/QtPlugins/iconengines" ...
QFactoryLoader::QFactoryLoader() looking at "C:/projects/deploy/QtPlugins/iconengines/qsvgicon.dll"
"Failed to extract plugin meta data from 'C:/projects/deploy/QtPlugins/iconengines/qsvgicon.dll'"
not a plugin
The qsvgicon.dll file is identical to "c:\Qt\5.15.1\msvc2019_64\plugins\iconengines\qsvgicon.dll".
I found the problem. It used some other Qt DLLs from the path when starting the application. This fixed it:
xcopy /y c:\Qt\5.15.1\msvc2019_64\bin\*.dll deploy

Invisible text in QTextEdit

I am learning Qt and running examples from Qt SDK 5.9.1. I run the code below and write inside QTextEdit but no text appears. Cursor moves as I write but no text is shown. Window title text is shown. I added addApplicationFont and setFont calls below I found from web to the sample but it didn't help.
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QFontDatabase::addApplicationFont("://Ubuntu-R.ttf");
app.setFont(QFont("Ubuntu", 11, QFont::Normal, false));
QTextEdit textEdit;
textEdit.show();
return app.exec();
}
I am on Ubuntu 16.04 and run following commands on bash to make executable:
qmake -makefile
make
./part1
I want the app to use the default Ubuntu system font. I learned that Qt uses fontconfig for fonts but I don't know how to trace the issue.
Edit
I thought QFontDatabase::addApplicationFont("://Ubuntu-R.ttf") call referenced system font but instead it is referencing font app resource file. I don't have resource file so obviously it won't work.
.pro file is below(unmodified sample file):
QT += widgets
SOURCES = main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/gettingStarted/gsQt/part1
INSTALLS += target
I tried to get system font using QFontDatabase but it didn't work:
app.setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
This doesn't do anything with any of enum values including QFontDatabase::GeneralFont
QFontDatabase database;
QStringList fam = database.families();
fam size is zero.
I will try to use embedded font next.
I don't know the exact reason of the problem but the reason was not configuring fontconfig dependency properly before building qt. I solved it by reconfiguring and recompiling qt again. You can find more details at qt forum.

QAudioDecoder - no service found

I am trying to decode a .wav file using QAudioDecoder class. Even though I had included the QtMultimedia module into my .pro file by adding
QT += multimedia I am receiving an error that service for the QAudioDecoder was not found. I am not able to see where to problem lies.
I am using Qt 5.1.0 with MingGW 4.8 32 bit on Windows 7.
Error message:
defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.audiodecode"
.pro file:
QT += core
QT += multimedia
QT -= gui
TARGET = test
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
main file:
#include <QCoreApplication>
#include <QAudioDecoder>
#include <QAudioBuffer>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString pathToFile = "C:/Users/Mateusz/Documents/Szkola/Sound Processing/Lab1/artificial/easy/506Hz.wav";
QAudioDecoder decoder;
decoder.setSourceFilename(pathToFile);
decoder.start();
while(decoder.bufferAvailable()) {
QAudioBuffer buffer = decoder.read();
qDebug() << "Buffer size: " << buffer.byteCount();
}
return a.exec();
}
The Multimedia module uses plugins that are different on each platform (or compiler).
See http://qt-project.org/wiki/Qt_Multimedia_Backends
On Windows you have DirectShow and MediaFoundation (WMF).
Only the WMF plugin implements audio decoding features.
WMF plugin is only available with MSVC compiler.
See http://qt-project.org/doc/qt-5.1/qtmultimedia/platform-notes-windows.html
I had the same problem in Qt5.5 running under Linux.
The problem disappeared after upgrade to Qt5.5.1 using their MaintenanceTool.
I also struggled with this issue and finally got it to work by using the MS visual studio compiler in QT Creator, like Fernando Pelliccioni suggested.
Steps were:
-Use the Qt MaintenanceTool to add support for msvc2013
-Install Visual Studio 2013
-In Qt Creator go to Projects->Manage Kits and add msvc2013
-Build and run. Now QAudioDecoder works.

Qt how to open a file in current dir ? or what's wrong with this?

I'm trying to open an xml file in the current location of the executable
QString path = QDir::currentPath();
path.append("/acc.xml");
QFile file(path);
if(!file.open(QIODevice::ReadOnly))
{
insertItem("IO ERR");
}
When I run it from Qt creator, everything works. currentPath() returns the path to the executable's folder
When I go to project-build-desktop/ folder and try to run it manually currentPath() returns /home/user/Documents
EDIT
also tried with same results:
Qt::current().path();
Qt::current().absolutePath();
Try to use QCoreApplication::applicationDirPath() instead of QDir::currentPath().
For details see http://doc.qt.io/qt-5/qcoreapplication.html#applicationDirPath
Check the returned value of QDir::currentPath(). I think when you run from Qt Creator, it returns the path where the project file (*.pro) is located. When you run from outside, you get path of the binary.
Edit
I never worked with Linux. However, you can try other functions/combinations from QDir:
QDir::current().path()
QDir::current().absolutePath()
etc.
To open a file in the current directory, you simply call QFile constructor
I tested this on my Linux machine and it works
#include <QtCore>
int main(int argc, char** argv){
QFile some_file("test.xml");
if(!some_file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug() << "Unable to open file";
} else {
qDebug() << "File open successfully";
}
exit(-1);
}
I run ./TestQFile and if there is a test.xml in the current directory, it works.
UPDATE: I notice that the wording of your question says that you want the file in the same directory as the executable, this can be done as follow:
// Getting directory of the executable
QFileInfo exec_fileinfo(argv[0]);
qDebug() << "Executable is in" << exec_fileinfo.absolutePath();
UPDATE 2: Under the project panel of QtCreator, there is a field for Working Directory. This is the directory that is returned by QDir::currentPath() if you are running it via QtCreator.
I found this discussion while searching for a similar solution. I think that the most portable way of opening an external file that has a fixed name (and no dialogs and the user are involved) is to use the Resource System.
In my case I created a new resource file with the prefix /config and added the file (called settings.xml). Inside the code, I don't need to use any path functions at all. I use the resource system instead. Thus a call like QFile file(":/config/settings.xml") works fine. Using QT creator 2.0.1 and QT 4.7 on Windows.
My tip is this : name of the file + the absolute path to it before opening it. For that I call the method applicationDirPath on our QCoreApplication object (the a object in my case), which returns us the path to the executable of the application. No need going through the argv array. That's it and works
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
const QString fileName = "someJsonFile.JSON";
const QString currentExecDir = a.applicationDirPath();
QFile myFile(currentExecDir + '/' + fileName);
if (myFile.open(QIODevice::ReadOnly)) {
qDebug()<< "The file "<< fileName<< " has been opened successfully";
}
else {
qDebug()<< "Failed to open file "<< fileName<< " in "<< currentExecDir;
}
return a.exec();
}
NOTE
Please see the Qt docs for the applicationDirPath method, because it assumes that the current directory has not been changed by the application