QR in Qt
As a companion question to How to scan for QR codes with Qt, I want to know how to draw a QR code from native C/C++ code in my Qt5 based desktop app, but I could not find an example of how to do this.
I know QtQR exists, but it has dependencies on python-qrtools which in my opinion kind of defeats the purpose of using Qt in the first place. I want a nimble, efficient and dependency-free solution that will compile with my app wherever I decided to take it.
How can I do that?
UPDATE 3/3-2016: It has come to my attention that there is a small library project that does what my answer does but in a more "prepackaged" way. You can check it out here.
QR in Qt
There is a small QR-code generator library in pure C and without dependencies, called libqrencode.
Step 1: Install
Before you can use it, you will have to install it. On my Ubuntu 13.10 that meant typing the following in a shell:
sudo aptitude install libqrencode-dev
On other platforms you may have to build it from source by yourself. Simply download the tarball and follow the instructions from the source code download.
Step 2: Project file
Next, you will have to add the library to your project. In my Qt5.2.0 project file (myproject.pro or similar) that meant appending the following line:
LIBS += -lqrencode
This should be similar for most versions of Qt that I know.
Step 3: encode
Next one must write the code that actually uses the library to encode some input string to QR format. That is one line of code:
QRcode *qr=QRcode_encodeString("my string", 1, QR_ECLEVEL_L, QR_MODE_8,0);
NOTE: After experimenting with the parameters I have passed to this function, I have learned that one needs to be careful. Some combinations of parameters failed for no good reason. For example passing 0 as version or using QR_MODE_AN failed with "Invalid parameters". This might be bugs in the ancient version of the library that I am using You have been warned.
Step 4: render image
Finally, before cleaning up, you need to convert the output to bitmap so that it can be rendered on the screen. This is simpler than it sounds. Instead of listing a bunch of assumptions I will instead included my complete working minimalistic QRWidget implementation here. The interesting bits are in the overridden paintEvent() method.
QRWidget.hpp
#ifndef QRWIDGET_HPP
#define QRWIDGET_HPP
#include <QWidget>
class QRWidget : public QWidget{
Q_OBJECT
private:
QString data;
public:
explicit QRWidget(QWidget *parent = 0);
void setQRData(QString data);
protected:
void paintEvent(QPaintEvent *);
};
#endif // QRWIDGET_HPP
QRWidget.cpp
#include "QRWidget.hpp"
#include <QPainter>
#include <QDebug>
#include <qrencode.h>
QRWidget::QRWidget(QWidget *parent) :
QWidget(parent),
data("Hello QR")//Note: The encoding fails with empty string so I just default to something else. Use the setQRData() call to change this.
{
}
void QRWidget::setQRData(QString data){
this->data=data;
update();
}
void QRWidget::paintEvent(QPaintEvent *pe){
QPainter painter(this);
//NOTE: I have hardcoded some parameters here that would make more sense as variables.
QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 0);
if(0!=qr){
QColor fg("black");
QColor bg("white");
painter.setBrush(bg);
painter.setPen(Qt::NoPen);
painter.drawRect(0,0,width(),height());
painter.setBrush(fg);
const int s=qr->width>0?qr->width:1;
const double w=width();
const double h=height();
const double aspect=w/h;
const double scale=((aspect>1.0)?h:w)/s;
for(int y=0;y<s;y++){
const int yy=y*s;
for(int x=0;x<s;x++){
const int xx=yy+x;
const unsigned char b=qr->data[xx];
if(b &0x01){
const double rx1=x*scale, ry1=y*scale;
QRectF r(rx1, ry1, scale, scale);
painter.drawRects(&r,1);
}
}
}
QRcode_free(qr);
}
else{
QColor error("red");
painter.setBrush(error);
painter.drawRect(0,0,width(),height());
qDebug()<<"QR FAIL: "<< strerror(errno);
}
qr=0;
}
Summary
In this little post I have summarized my experience with getting a QR code generator working with Qt.
If you feel that Fukuchi's library is too large[0] for you, consider looking at Nayuki's C++ QR Code generator library[1]: https://github.com/nayuki/QR-Code-generator/tree/master/cpp
Nayuki's library requires C++11, and is portable without needing Autotools. Sample usage:
#include <string>
#include <vector>
#include "QrCode.hpp"
using namespace qrcodegen;
// Create the QR Code object
QrCode qr = QrCode::encodeText("Hello, world!", QrCode::Ecc::MEDIUM);
// Read the black & white pixels
for (int y = 0; y < qr.size; y++) {
for (int x = 0; x < qr.size; x++) {
int color = qr.getModule(x, y); // 0 for white, 1 for black
// You need to modify this part
draw_pixel_onto_QT(x, y, color);
}
}
[0]: Fukuchi: 20 files, ~7200 lines among the main .c and .h files (excluding build and test code).
[1]: Nayuki: 6 files, ~1400 lines among the main .cpp and .hpp files (excluding demo code).
EDIT 2016-12-08 by OP
I decided, with permission, to add my own adaption to Qt. This code compiles and runs fine on my system, And I think it should be independent enough to work elsewhere without too many tweaks as well.
#include "QrCode.hpp"
void paintQR(QPainter &painter, const QSize sz, const QString &data, QColor fg)
{
// NOTE: At this point you will use the API to get the encoding and format you want, instead of my hardcoded stuff:
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(data.toUtf8().constData(), qrcodegen::QrCode::Ecc::LOW);
const int s=qr.getSize()>0?qr.getSize():1;
const double w=sz.width();
const double h=sz.height();
const double aspect=w/h;
const double size=((aspect>1.0)?h:w);
const double scale=size/(s+2);
// NOTE: For performance reasons my implementation only draws the foreground parts in supplied color.
// It expects background to be prepared already (in white or whatever is preferred).
painter.setPen(Qt::NoPen);
painter.setBrush(fg);
for(int y=0; y<s; y++) {
for(int x=0; x<s; x++) {
const int color=qr.getModule(x, y); // 0 for white, 1 for black
if(0!=color) {
const double rx1=(x+1)*scale, ry1=(y+1)*scale;
QRectF r(rx1, ry1, scale, scale);
painter.drawRects(&r,1);
}
}
}
}
For usage, please see this painter class.
The following is Qt code I used to update a label (qrCode) on a form with the QR code for "text". The label is set to a fixed size (min and max width and height=256 in my case), and scaledContents true. You might do something more efficient than the RGB32 format, but it really shouldn't matter for occasional updates.
void MyClass::updateQrCode( QString text )
{ using namespace qrcodegen;
// Create the QR Code object
QrCode qr = QrCode::encodeText( text.toUtf8().data(), QrCode::Ecc::MEDIUM );
qint32 sz = qr.getSize();
QImage im(sz,sz, QImage::Format_RGB32);
QRgb black = qRgb( 0, 0, 0);
QRgb white = qRgb(255,255,255);
for (int y = 0; y < sz; y++)
for (int x = 0; x < sz; x++)
im.setPixel(x,y,qr.getModule(x, y) ? black : white );
ui->qrCode->setPixmap( QPixmap::fromImage(im.scaled(256,256,Qt::KeepAspectRatio,Qt::FastTransformation),Qt::MonoOnly) );
}
using the Nayuki library - just the QrCode.cpp and .hpp files from here: https://github.com/nayuki/QR-Code-generator/tree/master/cpp
incorporated in my project with this trivial .pri file (kept in the same folder as the QrCode files):
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/QrCode.hpp
SOURCES += $$PWD/QrCode.cpp
Related
I want to extract raw frames or bitmaps from a video that I'm playing in my C++ console application using C++/WinRT APIs. I'm simply using CopyFrameToVideoSurface to copy the video's frame to a IDirect3DSurface. But, it just crashes my program (which works fine, if I don't set up this frame extracting callback). My goal is to render this frame buffer somewhere else to display the video.
Frame extracting code
(see complete project here: https://github.com/harmonoid/libwinmedia/tree/stackoverflow)
IDirect3DSurface surface = IDirect3DSurface();
Streams::IBuffer buffer = Streams::IBuffer();
DLLEXPORT void PlayerSetFrameEventHandler(
int32_t player_id, void (*callback)(uint8_t* buffer, int32_t size,
int32_t width, int32_t height)) {
g_media_players.at(player_id).IsVideoFrameServerEnabled(true);
g_media_players.at(player_id)
.VideoFrameAvailable([=](auto, const auto& args) -> void {
g_media_players.at(player_id).CopyFrameToVideoSurface(surface);
SoftwareBitmap bitmap =
SoftwareBitmap::CreateCopyFromSurfaceAsync(surface).get();
bitmap.CopyToBuffer(buffer);
(*callback)(buffer.data(), buffer.Length(), bitmap.PixelWidth(),
bitmap.PixelHeight());
});
}
You may simply build this shared library using cmake --build .
For testing the crash, you can compile following example (also present on the link repo):
https://github.com/harmonoid/libwinmedia/blob/stackoverflow/examples/frame_extractor.cpp
#include <cstdio>
#include "../include/internal.hpp"
int32_t main() {
using namespace Internal;
// Create a list of medias.
const char* media_uris[] = {
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/"
"ForBiggerJoyrides.mp4"};
const int media_ids[] = {0};
// Create a player instance.
PlayerCreate(0);
// Set frame callback (comment out the code to prevent crash from happening).
PlayerSetFrameEventHandler(
0, [](uint8_t*, int32_t, int32_t width, int32_t height) {
printf("Video width: %d, Video height: %d.", width, height);
});
// Open list of medias.
PlayerOpen(0, 1, media_uris, media_ids);
// Start playing the player.
PlayerPlay(0);
// Prevent console from closing.
getchar();
return 0;
}
I will be really helped, if I can get help to fix the code or any other working method for extracting the frames or video bitmaps using winrt::Windows::Media::Playback::MediaPlayer.
Thankyou 🙏.
Following is the stacktrace of the crash:
I'm recently new to the c++ world. My background is mainly in python and some application specific scripting languages. Anywho, I wanted to get some general feedback and converting my subclass of QLabel written in pyside and convert it to work with a C++ application in Qt Creator. I'm not looking for someone to do the entire project for me. I just need some guidance on how to add/setup a custom control in my Qt project.
You'll notice in my subclass I've simply just overwritten the paint event of the label in order to create the dotted pattern to fill the empty space to the right of the label as seen here:
Code for my custom label in Pyside:
class QLabelHeader(QtWidgets.QLabel):
def __init__(self, parent=None, **kwargs):
super(QLabelHeader, self).__init__(parent)
# events
def paintEvent(self, event):
# calculate font width
metrics = QtGui.QFontMetrics(self.font())
text_width = metrics.boundingRect(self.text()).width()
# calculate dimensions
y = int(self.height() * 0.5 - 2)
x = text_width + 4
width = self.width() - x
# create pattern
px = QtGui.QPixmap(4,4)
px.fill(QtCore.Qt.transparent)
pattern_painter = QtGui.QPainter(px)
pattern_painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
pattern_painter.setBrush(QtGui.QBrush(QtGui.QColor(200,200,200), QtCore.Qt.SolidPattern))
pattern_painter.drawRect(0,0,1,1)
pattern_painter.drawRect(2,2,1,1)
pattern_painter.end()
# draw tiled pixmap
painter = QtGui.QPainter(self)
painter.drawTiledPixmap(x,y,width,5,px)
painter.end()
super(QLabelHeader, self).paintEvent(event)
Question:
I've seen other sample projects online that include custom controls with a folder structure like seen here, which is a subfolder within a larger project. How do they create this folder structure and it's set of files?
As an added bonus if anyone feels like showing me a preview/psuedo code of what my h and cpp file would look like for overriding the QLabel's paint event like my pyside code.
Solution
Add a new class to your project in Qt creator going to File->New File or Project->C++->C++ Class. Make the class inherit from QWidget from the drop-down menu. Select a subfolder and give the class a name
Note: As a piece of advise, do not name your classes with Q prefix, as it might lead to a confusion.
In the header substitute the base class and the include with QLabel
Right click the name of the base class and select Refactor->Insert Virtual Functions of Base Classes and add paintEvent
Right click paintEvent and select Refactor->Add Definition in xxx.cpp
Go to the definition and put your code there
The translation should be pretty much straightforward, once you know the syntax of both languages.
Example
To help you with the process, I have prepared an example of how your code could be translated into C++:
LabelHeader.h:
#ifndef LABELHEADER_H
#define LABELHEADER_H
#include <QLabel>
class LabelHeader : public QLabel
{
Q_OBJECT
public:
explicit LabelHeader(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
};
#endif // LABELHEADER_H
LabelHeader.cpp:
#include "LabelHeader.h"
#include <QPainter>
LabelHeader::LabelHeader(QWidget *parent) :
QLabel(parent)
{
}
void LabelHeader::paintEvent(QPaintEvent *event)
{
// calculate font width
QFontMetrics metrics(font());
int text_width = metrics.boundingRect(text()).width();
// calculate dimensions
int y = height() * 0.5 - 2;
int x = text_width + 4;
int w = width() - x;
// create pattern
QPixmap px(4, 4);
px.fill(Qt::transparent);
QPainter pattern_painter(&px);
pattern_painter.setPen(Qt::NoPen);
pattern_painter.setBrush(QBrush(QColor(200, 200, 200), Qt::SolidPattern));
pattern_painter.drawRect(0, 0, 1, 1);
pattern_painter.drawRect(2, 2, 1, 1);
// pattern_painter.end();
// draw tiled pixmap
QPainter painter(this);
painter.drawTiledPixmap(x, y, w, 5, px);
// painter.end();
QLabel::paintEvent(event);
}
Note: I also took the liberty to revise the code after it has been translated and omit or commented parts, which are not necessary.
The full code of the example is available on GitHub.
Result
When used in the provided example application, this class produces a similar result:
I want to create a plot chart using visual studio with c++ code. The chart should be based on two axis. "x" axis display the time and "y" axis display the array data. array data have 100 elements and one data read in one second. How do I implement the code using any other graph library?
1) checkout and install Microsoft vcpkg to new folder (see 1-step instruction here: https://github.com/Microsoft/vcpkg)
2) vcpkg.exe install plplot from vcpkg folder
3) vcpkg.exe integrate project will give you instruction to add plplot to your MSVC project
4) paste this instruction to the Nuget Console:
5) after you paste and project reloads you can try this code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <cmath>
#include "plplot\plstream.h"
using namespace std;
const int NSIZE = 101;
int main(int argc, char ** argv) {
PLFLT x[NSIZE], y[NSIZE];
PLFLT xmin = 0., xmax = 1., ymin = 0., ymax = 100.;
int i;
for (i = 0; i < NSIZE; i++) {
x[i] = (PLFLT)(i) / (PLFLT)(NSIZE - 1);
y[i] = ymax * x[i] * x[i];
}
auto pls = new plstream();
plsdev("wingcc");
pls->init();
pls->env(xmin, xmax, ymin, ymax, 0, 0);
pls->lab("x", "y=100 x#u2#d", "Simple PLplot demo of a 2D line plot");
pls->line(NSIZE, x, y);
delete pls;
}
and you get:
tested on MSVC2015
I answered a very similar question a few years ago... there's a simple, straight and compilable example:
Graphical representation - Data Distribution
Obviously, the chart is not the same one that you need. But you can modify it in order to draw anything you want using C++ and then make any chart.
Plotting is a little bit tricky job in C++, as there is no default plotting library available in any C++ IDE. However, there are many libraries available online for making plotting possible in C++. Some plotting tools like Gnuplot, PPlot, Matlab, Python, KoolPlot (May be enough for your requirement).
I have answered a similar question a few days (plotting package for c++). The answer may be helpful.
I am trying to figure out why I get a different behaviour in the simulator (iPhone, Nexus, Nexus5, ... skins ) VS on an Android real device with the following code (my goal is to draw a text over a background image and save the whole in background image resolution) :
Please note that the GUI was done with the Designer.
protected void beforeMain(Form f) {
// The drawing label will contain the whole photo montage
f.setLayout(new LayeredLayout());
final Label drawing = new Label();
f.addComponent(drawing);
String nom = "Hello World";
// Image mutable dans laquelle on va dessiner (fond blancpar défaut)
// synthe is an Image
Image mutableImage = Image.createImage(synthe.getWidth(), synthe.getHeight());
drawing.getUnselectedStyle().setBgImage(mutableImage);
drawing.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
// Draws over the background image and put all together on the mutable image.
paintSyntheOnBackground(mutableImage.getGraphics(),
synthe,
nom,
synthe.getWidth(),
synthe.getHeight());
long time = new Date().getTime();
OutputStream os;
try {
os = Storage.getInstance().createOutputStream("screenshot_" + Long.toString(time) + ".png");
ImageIO.getImageIO().save(mutableImage, os, ImageIO.FORMAT_PNG, 1.0f);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} // end of beforeMain
And here is the method I call to draw a text over an image
public void paintSyntheOnBackground(Graphics g,
Image synthe,
final String pNom,
int width, int height) {
Font myFont = g.getFont();
g.setFont(myFont);
int w = myFont.stringWidth(pNom);
int h = myFont.getHeight();
// Added just to see the background
g.setColor(0x0000FF);
g.fillRect(0, 0, width, height);
g.setColor(0xff0000);
int x = g.getTranslateX() + width / 2 - w / 2;
int y = g.getTranslateY() + height / 2 - h / 2;
g.drawRect(x, y, w, h);
g.drawString(pNom, x, y);
} // end of paintSyntheOnBackground
Here is the outcome on the simulator (GoogleNexus7) :
And here is the outcome on the device (Android 4.4) :
My development system features Eclipse on Linux with Codename One V3-4.
I know the simulator cannot reproduce specific case, but here there is nothing special isn't it ? What can I do to make the behaviour on the simulator reflect the real behaviour since it would be much handier to test in the simulator ?
EDIT : After upgrading each of my CN1 project libs from version 114 to 115 (see this question for details on how to do the upgrade), I am now able to get the same behaviour in both simulator and device! Great bug fixing job CN1 team!
Please note : In my case (Eclipse - Linux) I had to upgrade the project libs in each and every Codename One project.
Any help would be greatly appreciated!
Cheers,
This was a really annoying bug that we just fixed now so it can make it to today's release.
The problem only occurs when drawing on a mutable image in a case where the simulator is in scale mode both of which we don't do often as scale mode is less accurate and mutable images are generally slower.
Thanks for keeping up with this.
I am working with the DevIl library and trying to use it to load a texture to OpenGL to apply to a sprite. The code is directly out of the C# Game Programming for Serious Game Design book (if that helps). The problem I'm having is with the Il.ilLoadImage call. Even when I pass it null, it doesn't throw an image not found error, and the sprite just shows up dark grey (instead of white) when the form pops up.
public void LoadTexture(string textureId, string path)
{
int devilId = 0;
Il.ilGenImages(1, out devilId);
Il.ilBindImage(devilId);
if (!Il.ilLoadImage(path))
{
System.Diagnostics.Debug.Assert(false, "Could not open file [" + path + "].");
}
//Flip the files before passing them to OpenGl
Ilu.iluFlipImage();
int width = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
int height = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
int openGLId = Ilut.ilutGLBindTexImage();
System.Diagnostics.Debug.Assert(openGLId != 0);
Il.ilDeleteImages(1, ref devilId);
_textureDatabase.Add(textureId, new Texture(openGLId, width, height));
}
DevIL is, rather nonsensically, based on OpenGL's API and general structure. As such, the typical way that errors are reported is with ilGetError. If you want to make sure a function succeeded or not, you should use that.