// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN # include # include #endif // Q_OS_WIN // Timeout values: // A valid screen grab requires the scene to not change // for SCENE_STABLE_TIME ms #define SCENE_STABLE_TIME 200 // Give up after SCENE_TIMEOUT ms #define SCENE_TIMEOUT 6000 //#define GRABBERDEBUG static const QSize DefaultGrabSize(400, 400); class GrabbingView : public QQuickView { Q_OBJECT public: GrabbingView(const QString &outputFile) : ofile(outputFile), grabNo(0), isGrabbing(false), initDone(false), justShow(outputFile.isEmpty()) { if (justShow) return; grabTimer = new QTimer(this); grabTimer->setSingleShot(true); grabTimer->setInterval(SCENE_STABLE_TIME); connect(grabTimer, SIGNAL(timeout()), SLOT(grab())); connect(this, SIGNAL(afterRendering()), SLOT(startGrabbing())); int sceneTimeout = qEnvironmentVariableIntValue("LANCELOT_SCENE_TIMEOUT"); if (!sceneTimeout) sceneTimeout = SCENE_TIMEOUT; QTimer::singleShot(sceneTimeout, this, SLOT(timedOut())); } private slots: void startGrabbing() { if (!initDone) { initDone = true; grabTimer->start(); } } void grab() { if (isGrabbing) return; isGrabbing = true; grabNo++; #ifdef GRABBERDEBUG printf("grab no. %i\n", grabNo); #endif QImage img = grabWindow(); if (!img.isNull() && img == lastGrab) { sceneStabilized(); } else { lastGrab = img; grabTimer->start(); } isGrabbing = false; } void sceneStabilized() { #ifdef GRABBERDEBUG printf("...sceneStabilized IN\n"); #endif if (QGuiApplication::platformName() == QLatin1String("eglfs")) { QSize grabSize = initialSize().isEmpty() ? DefaultGrabSize : initialSize(); lastGrab = lastGrab.copy(QRect(QPoint(0, 0), grabSize)); } if (ofile == "-") { // Write to stdout QFile of; #ifdef Q_OS_WIN // Make sure write to stdout doesn't do LF->CRLF _setmode(_fileno(stdout), _O_BINARY); #endif // Q_OS_WIN if (!of.open(1, QIODevice::WriteOnly) || !lastGrab.save(&of, "ppm")) { qWarning() << "Error: failed to write grabbed image to stdout."; QGuiApplication::exit(2); return; } } else { if (!lastGrab.save(ofile)) { qWarning() << "Error: failed to store grabbed image to" << ofile; QGuiApplication::exit(2); return; } } QGuiApplication::exit(0); #ifdef GRABBERDEBUG printf("...sceneStabilized OUT\n"); #endif } void timedOut() { qWarning() << "Error: timed out waiting for scene to stabilize." << grabNo << "grab(s) done. Last grab was" << (lastGrab.isNull() ? "invalid." : "valid."); QGuiApplication::exit(3); } private: QImage lastGrab; QTimer *grabTimer = nullptr; QString ofile; int grabNo; bool isGrabbing; bool initDone; bool justShow; }; int main(int argc, char *argv[]) { QHashSeed::setDeterministicGlobalSeed(); QGuiApplication a(argc, argv); QFontDatabase::addApplicationFont(":/trim.ttf"); QFont commonFont("Trim"); commonFont.setHintingPreference(QFont::PreferNoHinting); a.setFont(commonFont); QUnifiedTimer::instance()->setConsistentTiming(true); QSurfaceFormat::setDefaultFormat(QQuick3D::idealSurfaceFormat(4)); // Parse command line QString ifile, ofile; bool noText = false; bool justShow = false; QStringList args = a.arguments(); int i = 0; bool argError = false; while (++i < args.size()) { QString arg = args.at(i); if ((arg == "-o") && (i < args.size()-1)) { ofile = args.at(++i); } else if (arg == "-notext") { noText = true; } else if (arg == "--cache-distance-fields") { ; } else if (arg == "-viewonly") { justShow = true; } else if (ifile.isEmpty()) { ifile = arg; } else { argError = true; break; } } if (argError || ifile.isEmpty() || (ofile.isEmpty() && !justShow)) { qWarning() << "Usage:" << args.at(0).toLatin1().constData() << "[-notext] {-o |-viewonly}"; return 1; } QFileInfo ifi(ifile); if (!ifi.exists() || !ifi.isReadable() || !ifi.isFile()) { qWarning() << args.at(0).toLatin1().constData() << " error: unreadable input file" << ifile; return 1; } // End parsing GrabbingView v(ofile); v.setTextRenderType(QQuickWindow::QtTextRendering); v.setSource(QUrl::fromLocalFile(ifile)); if (noText) { const QList items = v.rootObject()->findChildren(); for (QQuickItem *item : items) { if (QByteArray(item->metaObject()->className()).contains("Text")) item->setVisible(false); } } if (v.initialSize().isEmpty()) v.resize(DefaultGrabSize); v.show(); int retVal = a.exec(); #ifdef GRABBERDEBUG printf("...retVal=%i\n", retVal); #endif return retVal; } #include "main.moc"