QML flickering with Animations on images - qt

I'm writing a QML application that displays a collection images.
To display next and previous image I use a ParallelAnimation to animate the x coordinate translation but the result is ugly: images animate but there is a flicking during the animation.
I've tried with opengl viewport and some optimizations (see here) but no success.

try adding view->setAttribute(Qt::WA_NoSystemBackground);
in main.cpp

Related

Pixelated gif in QT

I'm trying to show a gif file in QT app, using the approach provided in the link: https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/widgets/movie?h=5.15
Approach makes use of QMovie object set in a QLabel.
The example works well and fine.
But if I enable High DPI scaling for the app, the gif becomes all pixelated. Please see the screenshots below.
This is the line that I add to enable High DPI scaling.
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Any ideas to get this fixed ?
I have tried the following fixes already:
setScaledSize for the QMovie object
setScaledContents(true) for the QLabel
QT version I'm using is 5.15.2 and platform is Windows.
A GIF picture cannot have more than 256 unique colours. When you load such an image into Qt, it is internally represented in that exact format with the palette (of 256 colours) from the GIF representation, even if your hardware might be able to display many more colours.
This also means that when you scale such an image, Qt is not allowed to extend the colour space to render in-between colours - This means that scaled GIF pictures generally have to look much worse than scaled high-colour images.
The solution to this is either to transform the QImage you created from a GIF picture into a format with a larger colour space before scaling it (with QImage::convertToFormat) or, better still, don't use GIF images at all. After all, GIF is a format developed 30 years ago and has never really been updated to adapt to modern hardware, and using it, you artificially limit your programs to the capabilities of that format.
It seems at this moment there is no way to render sharp gifs when scaled using QMovie and QLabel. I have filed a bug for the same in QT bug tracker.
Meanwhile I have found a workaround that works fine. It is done making use of QML in the QWidget system, using QQuickWidget.
Let me add the full steps here, so that it is helpful to anyone else who run into this problem:
First we need to add support for Qml and QuickWidgets. I use CMake and Visual Studio. Hence I add the below lines in the CMakeLists.txt file. Equivalent changes needs to be made in the .pro file, if QT Creator is used instead.
# I'm only adding the relevant lines for brevity
find_package(Qt5 COMPONENTS Qml QuickWidgets)
target_link_libraries(${APP_TARGET_NAME}
Qt5::Qml
Qt5::QuickWidgets)
# Note the --qmldir switch
add_custom_command (TARGET ${APP_TARGET_NAME} POST_BUILD
COMMAND ${QTDIR}/bin/windeployqt
--qmldir ${CMAKE_CURRENT_SOURCE_DIR}/qml
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${APP_TARGET_NAME}.exe)
Then create a spinner.qml file inside a folder named qml:
import QtQuick 2.15
Rectangle {
width: 12
height: 12
AnimatedImage {
y: 5
width: 12
height: 12
id: spinner
source: "img/spinner.gif"
speed: 1.0
}
}
And then load the qml file using QQuickWidget and add the QQuickWidget instance to the QWidget layout.
QHBoxLayout *main_layout = new QHBoxLayout();
auto *spinner_gif = new QQuickWidget(QUrl::fromLocalFile(":/spinner.qml"));
main_layout->addWidget(spinner_gif);
this->setLayout(main_layout);
The gif that shows up won't be pixelated even when scaled and we can see the GPU in use, in the Task Manager, as expected for a QQuickWidget.

QML Canvas: problem with drawing of SVG image with lines containing arrows

In QML canvas, I am trying to draw an image which is in svg format and contains lines with arrow heads like below.
svg in not supported by stackoverflow, so I put the png of svg image above just for diplay.
original svg is here : https://svgshare.com/i/9u8.svg
And when I tried to draw this image in QML canvas, resulted image doesn't contain the arrow heads. The result look similar to below. Even in Qt creator, arrow heads are not shown.
I want to know is it problem with SVG generation or problem with drawing on canvas?
The reason this happens is that Qts SVG implementation is based on TinySVG - it only supports a subset of SVG and can't handle all features of the specification. Looking at the code of the SVG-file, it is propably the <marker> elements that are not supported.
A possible solution would be to either edit the image (with e.g. Inkscape) to convert these markers to normal paths or to create a bunch of PNGs of variing sizes and load them conditionally.

QML Video alpha-blending/rendering a video into a Qt Quick Scene Graph

I'm trying to get an alpha-blending effect in QML with a video in RGBA.
Now the problem is that the Video Item supplied by QtMultimedia actualy opens an overlaying window in the QtQuick scene, so I don't think it's possible to alpha-blend other QML elements with the Video element (I sure hope I'm wrong, but I can't find a solution).
So another way would be rendering a video myself in a class that inherits from QQuickItem, in the updatePaintNode method.
Has anyone seen anything like this before? Is it even possible if the guys behind QtMultimedia couldn't achieve it?
Can I maybe change the background of the MediaPlayer element, maybe to be transparent or just a color in QML?
So far I was thinking about QAbstractVideoSurface and QVideoFrame but I have no idea how to render it onto the QSG, or even how should the GeometryNode look for a video.
The best solution would be to get the alpha-blending with other QML Elements for example in:
Rectangle {
width: 1024
height: 768
color: "yellow"
focus: true
Video {
id: video
anchors.fill: parent
source: "alpha-video.mov"
autoPlay: true
}
}
Thanks in advance!
I tried a few things, but in the end I used the Qt example called VideoWidget that uses QAbstractVideoSurface and QVideoFrame, and painted the frames in a QQuickPaintedItem, using MediaPlayer to load the data from QML.
It's important to put ARGB32 on top of the QList that describes the supported pixel formats in the QAbstractVideoSurface, unfortunately the Qt logic is that they take the first availibe format and that's why the native Video element doesn't show the alpha channel (it plays the video in RGB32, either that or it's a thing with the overlaying window in the native element instead of painting it in the QtQuick Scene Graph).

Creating a permanent static overlay for QGraphicsView scene

I am making an app using Qt (currently 4.8) which displays a literal map from a large number of QGraphicsScene items. I would like to annotate the view with a scale. My requirement for the scale is that it is permanently fixed w.r.t the viewport widget. It needs to be updated whenever the view scale changes (zoom in, etc). There are other possible overlay items as well (compass, etc) so I'd prefer a generic solution.
I have looked at earlier questions around this which suggest:
using the ItemIgnoresTransform
using an overlay pixmap.
I tried IgnoresTransform but that way didn't work right: I couldn't figure out how to fix it in place in (say) the bottom corner of the viewport and was having some difficulty getting the text and lines always displaying in the correct size.
I scrapped that and subclassed QGraphicsView, adding an overlay pixmap by reimplementing the paintEvent (calls original one, then paints the overlay pixmap on top), and an alignment option to indicate where it goes. Coding some pixmap paint code produces a usable scale on the view. Yay! ... but it doesn't work with scrolls - I get "shattered" renderings of the scale all over, or sometimes no scale at all. I think this is because QGraphicsView::scrollViewportBy() uses viewport()->scroll() so I wondered if switching to ViewportSmartUpdate would help, but it doesn't help enough. I'd prefer not to switch to ViewportFullUpdate as that would likely slow the app down too much (there are millions of items in the scene and that would require a full repaint just to move around).
So. Any ideas from here? Would adapting my pixmap code to write to a new mostly-transparent Widget that is overlaid on the viewport be a better way?
Thanks for any help...
Though it may not be the best way of doing this, in the past I've added custom widgets to the window that holds the QGraphicsView / QGraphicsScene, which have the same graphic style as the QGraphicObjects in the scene. When the view is then used to move objects in the scene, or the scene itself, the items on the window remain in the same place.
Hope that helps.

QT: Painting bitmap/PNG images to a QWidget

I am building a game using QT in c++. I have extended the QWidget class as a painting surface and have set up a thread to refresh the screen. What I need now is to load the sprite sheets from file, break them up into separate 64x64 pixel images, and then paint them to the screen. Does anyone have some advice for how I should go about doing this?
TIA
Some QPainter::drawPixmap() variants has the option to specify the rectangle in the pixmap to be drawn. This will help you keeping the sprite sheets without breaking them up into small images.
For repeated sprites, QPainter::drawPixmapFragments() probably will have better performance and also allow sub-image drawing.

Resources