Include above-and-left-of-primary pixels in QR screenshots

`QGuiApplication::primaryScreen()->grabWindow(...)` only includes pixels
below and to the right of the top left corner of the primary screen (at
least in Linux). Consider a screen arrangement like:

                          +-------------+
    +---------++---------+|             |
    +         ||         ||             |
    +    3    || PRIMARY ||      2      |
    +---------++---------++-------------+

With this screen arrangement, the top of screen 2 and all of screen 3
would be left out of the screenshot.

Combining the results of calling `grabWindow(...)` on each `QScreen`
resolves the issue.
This commit is contained in:
Emil Lundberg 2018-01-16 15:41:47 +01:00
parent c219b26cf2
commit 8584c8b3a5
No known key found for this signature in database
GPG Key ID: 5B9688125FF0B636

View File

@ -10,28 +10,46 @@ public:
explicit ScreenShot () : QObject() {}
// Take a screenshot, convert it to a bitarray and return it with some metadata
Q_INVOKABLE QVariantMap capture() {
QScreen *screen = QGuiApplication::primaryScreen();
// Virtual geometry grabs all pixels on the desktop, even with multiple monitors.
QRect g = screen->virtualGeometry();
QPixmap screenShot = screen->grabWindow(0, g.x(), g.y(), g.width(), g.height());
// Monochrome, no dither
QImage image = screenShot.toImage();
image = image.convertToFormat(QImage::Format_Mono, Qt::ThresholdDither);
// Get all pixels as 1 (black) or 0 (white)
QByteArray imageArray;
for (int row = 0; row < image.height(); ++row) {
for (int col = 0; col < image.width(); ++col) {
QRgb px = image.pixel(col, row);
if (px == 0xFF000000) {
imageArray.append((char) 1);
} else {
// Dimensions of output image
int outputHeight = 0;
int outputWidth = 0;
for (QScreen *screen : QGuiApplication::screens()) {
outputWidth = std::max(outputWidth, screen->geometry().width());
}
for (QScreen *screen : QGuiApplication::screens()) {
QRect g = screen->geometry();
QPixmap screenShot = screen->grabWindow(0, 0, 0, g.width(), g.height());
// Monochrome, no dither
QImage image = screenShot.toImage();
image = image.convertToFormat(QImage::Format_Mono, Qt::ThresholdDither);
// Stack screens vertically in output image
outputHeight += image.height();
for (int row = 0; row < image.height(); ++row) {
for (int col = 0; col < image.width(); ++col) {
QRgb px = image.pixel(col, row);
if (px == 0xFF000000) {
imageArray.append((char) 1);
} else {
imageArray.append((char) 0);
}
}
// Pad smaller screens horizontally
for (int col = image.width(); col < outputWidth; ++col) {
imageArray.append((char) 0);
}
}
}
QVariantMap map;
map.insert("width", image.width());
map.insert("height", image.height());
map.insert("width", outputWidth);
map.insert("height", outputHeight);
map.insert("data", QString(imageArray.toBase64()));
return map;
}