Svg to pdf converter for Qt project - qt

I have multiple svg files and I wish to convert them in the PDF format. The problem is that I need to work with multiple text fonts and a simple QSvgRenderer is not enough.
For example:
My problem is that I need to integrate a library in my project that does not use external dependencies (just a library that can be used as a standalone entity).
The only library that can partially suit my needs is librsvg but I have no experience and I can not find a method to integrate it in a Qt project.
Can someone give me a few tips or can point me in the right direction?
EDIT
With something basic there is not a single font that made it to the right using QSvgRenderer:
QSvgRenderer renderer;
renderer.load((QString)"E:/TEXT4.svg");
QPrinter printer;
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName("E:/TEXT4.pdf");
QPainter painter(&printer);
renderer.render(&painter);
painter.end();

Maybe a bit late, but had the same problem and found a solution using Qt only.
The problem in your case is you need to install the fonts manually and need a QApplication.
E.g.:
int main(int argc, char** argv)
{
// A QApplication instance is necessary if fonts are used in the SVG
QApplication app(argc, argv);
int id = QFontDatabase::addApplicationFont(":/DejaVuSans.ttf");
if (id != -1)
{
QStringList font_families = QFontDatabase::applicationFontFamilies(id);
// This prints: DejaVu Sans
for (const auto& item : font_families)
{
std::cout << item.toStdString() << std::endl;
}
}
// Load your SVG
QSvgRenderer renderer(QString("myimage.svg"));
QPdfWriter pdfWriter(QString("mydoc.pdf"));
pdfWriter.setPageSize(QPageSize(QPageSize::A4));
QPainter painter(&pdfWriter);
renderer.render(&painter);
}
Also tested with multiple different font families and it worked.
Note: As far as I know, you cannot change the font name in Qt, so in the SVG font-family must match exactly the added font name. In this example, font-family:DejaVu Sans.

Related

Replace QCameraViewfinder with QVideoWidget in Qt 6

I am trying to port some code to Qt 6's reworked QtMultimedia framework and running into a lot of issues of disappearing APIs.
One of these is QCameraViewfinder, which as I understand it, is a simple viewer of the current QCamera image feed.
It used to be a subclass of QVideoWidget, which still exists, and its documentation helpfully states the following:
Attaching a QVideoWidget to a QMediaPlayer or QCamera allows it to display the video or image output of that object.
player = new QMediaPlayer;
player->setSource(QUrl("http://example.com/myclip1.mp4"));
videoWidget = new QVideoWidget;
player->setVideoOutput(videoWidget);
videoWidget->show();
player->play();
Note: Only a single display output can be attached to a media object at one time.
Problem is, there is no way to do QCamera::setVideoOutput(QVideoWidget*) as that function does not exist.
Neither can I find an alternative API that connects the two.
Is this something that they forgot to provide or am I missing something?
I looked through the relevant classes' source code and documentation, but can't for the life of me find the magic incantation that's supposed to give me a simple view into a QCamera's current video feed.
You have to use QMediaCaptureSession:
#include <QApplication>
#include <QCamera>
#include <QMediaDevices>
#include <QMediaCaptureSession>
#include <QVideoWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QVideoWidget videoWidget;
videoWidget.resize(640, 480);
videoWidget.show();
QCamera camera(QMediaDevices::defaultVideoInput());
camera.start();
QMediaCaptureSession mediaCaptureSession;
mediaCaptureSession.setCamera(&camera);
mediaCaptureSession.setVideoOutput(&videoWidget);
return a.exec();
}

Why does my Qt app ignore the setting of applicationDisplayName?

I am running a small app on KDE Plasma 5 created with Qt and the KDE framework. Almost everything works like a charm, just one part doesn't work. I just cannot set the application display name. I have the following code:
int main(int argc, char **argv) {
QApplication application(argc, argv);
KLocalizedString::setApplicationDomain("blender-render-control");
KCrash::initialize();
KAboutData aboutData(QStringLiteral("blender-render-control-center"),
i18n("Blender Render Control Center"),
QStringLiteral("1.0"),
i18n("A simple application to control the blender render control server"),
KAboutLicense::Custom,
i18n("Copyright 2019, Knerd "));
aboutData.addAuthor(i18n("Knerd"), i18n("Author"), QStringLiteral("knerd#knerd.knerd"));
aboutData.setOrganizationDomain("knerd.knerd");
aboutData.setDesktopFileName(QStringLiteral("knerd.knerd.blender-render-control"));
KAboutData::setApplicationData(aboutData);
QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("knerd.knerd.blender-render-control")));
application.setApplicationDisplayName(i18n("Blender Render Control Center"));
application.setApplicationName(i18n("Blender Render Control Center"));
QCommandLineParser parser;
aboutData.setupCommandLine(&parser);
parser.process(application);
aboutData.processCommandLine(&parser);
auto *window = new MainWindow();
window->show();
return QApplication::exec();
}
From reading the docs and checking some examples, this should set the application title in my KDE environment. But it doesn't, the application name is the name of the executable.
Is this a bug in KDE or am I doing something wrong?
The docs are a bit confusing on what the applicationName and displayApplicationName are actually used for, there has been some bug reports about it, and behavior has changed between versions if I remember correcly.
If you want a window-title, I think you can do.
window->setWindowTitle( QCoreApplication::applicationName() );

How to render emoji's in with QGraphicsTextItem?

Here is the thing. I've created a little Qt chat application for my work office. It is only for lan connected clients. I implemented this by using QGraphicsTextItem for the messages inside bubbles which are a rounded rectancles.
To really complete it I need to add emojis to it. All chat-like applications have them. The thing is that I don't know how to implement them. I've read that they are part of the unicode standad. (the unicode codes for this link proves it http://unicode.org/emoji/charts/full-emoji-list.html), but I have no idea how to render it in a QGraphicsTextItem. Is it even possible?
I could do a very very manual labor of separating the user string and actually use multiple text items to render the parts fo the strings separated by emojis y and then the emoji themselves as a separate graphical entity, but I rather not do that if I can avoid it.
Any ideas?
There's nothing to do: the emojis are simply characters, you can copy-paste them from the "Brow" column in the page you cited, just like you would any other character e.g. from this answer (including the emoji!). A sane compiler assumes that your source is UTF-8 encoded, as do most editors, so it will be transparent. If the relevant fonts are installed, it will just work.
// https://github.com/KubaO/stackoverflown/tree/master/questions/emoji-text-item-38000855
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QGraphicsScene scene;
QGraphicsView view{&scene};
QGraphicsTextItem item{QStringLiteral("I'm a happy 👧. 😀")};
scene.addItem(&item);
view.ensureVisible(scene.sceneRect());
view.show();
return app.exec();
}

Embeding PySide/PyQt widget into Qt/C++ application

I have a C++/Qt application which should have its GUI extensible with modules. Extending should be simple and versatile. I am just checking a concept - is it possible to have this main C++/Qt application that would execute a Python/PySide/PyQt script which would create a QWidget (or derived class) instance and embed this widget into the main C++/Qt application?
Is there any working snippet to demonstrate the feasibility of this task? I.e. how to create and embed the widget? How to pass signals between the application and the widget?
This question is a bit old, but in case someone else is face the same issue, I will try to give a useful answer.
I think it's possible. In the following example, I create a QApplication and QMainWindow in c++, embed a python interpreter, and then, on the python side, I create a QPushButton which I add to the main window.
Try this out:
#include <QApplication>
#include <QMainWindow>
#include <iostream>
#include "Python.h"
class PythonQt
{
public:
PythonQt()
{
char name[] = "test";
Py_SetProgramName(name);
Py_Initialize();
std::string code =
"from PySide import QtGui\n"
""
"all_widgets = QtGui.QApplication.instance().allWidgets()\n"
"window = None\n"
"for widget in all_widgets:\n"
" if str(widget.objectName()) == \"main_window\":\n"
" window = widget\n"
" break\n"
""
"def message_box():\n"
" QtGui.QMessageBox.information(None, 'Test', 'Hello!', \
QtGui.QMessageBox.Ok)\n"
" QtGui.QApplication.instance().quit()\n"
""
"button = QtGui.QPushButton('Press Me')\n"
"button.clicked.connect(message_box)\n"
"window.setCentralWidget(button)\n"
"window.move(600, 300)\n"
"window.show()";
PyRun_SimpleString(code.c_str());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow win;
win.setObjectName("main_window");
PythonQt python_code;
a.exec();
}
The python script is written here in a string to have everything in a single file, but you could of course read it in from a .py file.
Object ownership could be an issue though, as shown in the link given by Trilarion.
I don't think this is possible. PySide/PyQt are wrappers around C++/Qt. That means you create C++ objects and Python wrapper objects and somehow the wrapper objects kind of refer to the C++ objects. This works one way as far as I know.
But you want the other way. Basically a wrapper around Python objects (which themselves are wrappers around C++ objects) to use in C++. I don't think PySide/PyQt are ready for thise. However it is possible to embed Python in other languages.
Also see How to shoot yourself in the foot. about the pitfalls of communication between C++/Qt and Python.

Getting font metrics without GUI (console mode)

Let's say some images have to be generated by a Qt console program and that font metrics are needed by internal algorithms (they use the text width/height as input to compute the position where the drawing should occur). This program has to be runable on a Linux without any GUI (runlevel-3, basically a cluster without any display server).
Problem: QFontMetrics are only available when running a Qt application in GUI mode.
Any workaround to get string metrics without any display server ?
Ok after additional comments I think I understand your problem.
Just do it like that:
include <QApplication>
int main(int argv, char **args)
{
QApplication app(argv, args);
QApplication::processEvents(); // this should allow `QApplication` to complete its initialization
// do here whatever you need
return 0; // or some other value to report errors
}
You can also try use QGuiApplication this version doesn't require (doesn't use) widgets.
See also example in documentation how to handle none gui cases.
This code works perfectly on my Ubnutu with Qt 5.3
#include <QGuiApplication>
#include <QFontMetrics>
#include <QDebug>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QFont font("Times", 10, QFont::Bold);
qDebug() << font;
QFontMetrics metrics(font);
qDebug() << metrics.boundingRect("test");
return 0;
}
It also works with Qt 4.8 when QApplication is used.
Project file was quite simple
QT += core
TARGET = MetricsNoGui
TEMPLATE = app
SOURCES += main.cpp
Qt 4.8 has such QApplication constructor, whose 3rd parameter can help to solve the issue. Simple provide false as 3rd argument and enjoy using QFontMetrics in Qt console application. There will be no crashes if one starts app on systems without X server.
I didn't find a way to use QFont or QPrinter with QCoreApplication :( However, if you are able to install Xvfb, then your QApplication will be runnable also on a server without any display. I'm using this setup on a headless Raspberry Pi Zero.
Xvfb :1 -screen 0 1024x768x16 &
export DISPLAY=:1.0
./YourQApplication
This isn't the most elegant solution, but after hours of desperate searching, it's the only one I found.

Resources