Systemd changes | root script | URL support for gif effects (#1319)

* Systemd changes and URL option for Gif Effects
* Add grayscale to gif effect
* WebUI adjustments
* Rename version to .version
* Copy runHyperionAsRoot.sh to rpi packages
* Pack script into all unix packages
* Start hyperion only after network is available
* Snap builds removed due to poor server connection
* Flexible updateHyperionUser.sh
* updateHyperionUser script entered in the package
* Print help on none sudo execute
* Corrected embedded Python location
* Replacement for the QWindowsScreen grabWindow function
* Updated to latest 2.x mbedtls version 2.27

Co-authored-by: LordGrey <lordgrey.emmel@gmail.com>
This commit is contained in:
Markus
2021-10-02 18:02:52 +02:00
committed by GitHub
parent f269268def
commit eb96553975
37 changed files with 776 additions and 573 deletions

View File

@@ -70,9 +70,9 @@ QString EffectFileHandler::deleteEffect(const QString& effectName)
{
if (effectConfigurationFile.exists())
{
if ((it->script == ":/effects/gif.py") && !it->args.value("image").toString("").isEmpty())
if ((it->script == ":/effects/gif.py") && !it->args.value("file").toString("").isEmpty())
{
QFileInfo effectImageFile(it->args.value("image").toString());
QFileInfo effectImageFile(it->args.value("file").toString());
if (effectImageFile.exists())
{
QFile::remove(effectImageFile.absoluteFilePath());
@@ -159,19 +159,26 @@ QString EffectFileHandler::saveEffect(const QJsonObject& message)
newFileName.setFile(f);
}
if (!message["imageData"].toString("").isEmpty() && !message["args"].toObject().value("image").toString("").isEmpty())
if (!message["imageData"].toString("").isEmpty() && !message["args"].toObject().value("file").toString("").isEmpty())
{
QJsonObject args = message["args"].toObject();
QString imageFilePath = effectArray[0].toString().replace("$ROOT", _rootPath) + '/' + args.value("image").toString();
QString imageFilePath = effectArray[0].toString().replace("$ROOT", _rootPath) + '/' + args.value("file").toString();
QFileInfo imageFileName(imageFilePath);
if (!FileUtils::writeFile(imageFileName.absoluteFilePath(), QByteArray::fromBase64(message["imageData"].toString("").toUtf8()), _log))
{
return "Error while saving image file '" + message["args"].toObject().value("image").toString() + ", please check the Hyperion Log";
return "Error while saving image file '" + message["args"].toObject().value("file").toString() + ", please check the Hyperion Log";
}
//Update json with image file location
args["image"] = imageFilePath;
args["file"] = imageFilePath;
effectJson["args"] = args;
}
if (message["args"].toObject().value("imageSource").toString("") == "url" || message["args"].toObject().value("imageSource").toString("") == "file")
{
QJsonObject args = message["args"].toObject();
args.remove(args.value("imageSource").toString("") == "url" ? "file" : "url");
effectJson["args"] = args;
}

View File

@@ -12,6 +12,10 @@
#include <QDateTime>
#include <QImageReader>
#include <QBuffer>
#include <QUrl>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QEventLoop>
// Get the effect from the capsule
#define getEffect() static_cast<Effect*>((Effect*)PyCapsule_Import("hyperion.__effectObj", 0))
@@ -219,31 +223,57 @@ PyObject* EffectModule::wrapSetImage(PyObject *self, PyObject *args)
PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
{
QString file;
QBuffer buffer;
QImageReader reader;
char *source;
int cropLeft = 0, cropTop = 0, cropRight = 0, cropBottom = 0;
bool grayscale = false;
if (getEffect()->_imageData.isEmpty())
{
Q_INIT_RESOURCE(EffectEngine);
char *source;
if(!PyArg_ParseTuple(args, "s", &source))
if(!PyArg_ParseTuple(args, "s|iiiii", &source, &cropLeft, &cropTop, &cropRight, &cropBottom, &grayscale))
{
PyErr_SetString(PyExc_TypeError, "String required");
return nullptr;
}
file = QString::fromUtf8(source);
const QUrl url = QUrl(source);
if (url.isValid())
{
QNetworkAccessManager *networkManager = new QNetworkAccessManager();
QNetworkReply * networkReply = networkManager->get(QNetworkRequest(url));
if (file.mid(0, 1) == ":")
file = ":/effects/"+file.mid(1);
QEventLoop eventLoop;
connect(networkReply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
reader.setDecideFormatFromContent(true);
reader.setFileName(file);
if (networkReply->error() == QNetworkReply::NoError)
{
buffer.setData(networkReply->readAll());
buffer.open(QBuffer::ReadOnly);
reader.setDecideFormatFromContent(true);
reader.setDevice(&buffer);
}
delete networkReply;
delete networkManager;
}
else
{
QString file = QString::fromUtf8(source);
if (file.mid(0, 1) == ":")
file = ":/effects/"+file.mid(1);
reader.setDecideFormatFromContent(true);
reader.setFileName(file);
}
}
else
{
PyArg_ParseTuple(args, "|siiiii", &source, &cropLeft, &cropTop, &cropRight, &cropBottom, &grayscale);
buffer.setData(QByteArray::fromBase64(getEffect()->_imageData.toUtf8()));
buffer.open(QBuffer::ReadOnly);
reader.setDecideFormatFromContent(true);
@@ -260,19 +290,33 @@ PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
if (reader.canRead())
{
QImage qimage = reader.read();
int width = qimage.width();
int height = qimage.height();
if (cropLeft > 0 || cropTop > 0 || cropRight > 0 || cropBottom > 0)
{
if (cropLeft + cropRight >= width || cropTop + cropBottom >= height)
{
QString errorStr = QString("Rejecting invalid crop values: left: %1, right: %2, top: %3, bottom: %4, higher than height/width %5/%6").arg(cropLeft).arg(cropRight).arg(cropTop).arg(cropBottom).arg(height).arg(width);
PyErr_SetString(PyExc_RuntimeError, qPrintable(errorStr));
return nullptr;
}
qimage = qimage.copy(cropLeft, cropTop, width - cropLeft - cropRight, height - cropTop - cropBottom);
width = qimage.width();
height = qimage.height();
}
QByteArray binaryImage;
for (int i = 0; i<height; ++i)
for (int i = 0; i<height; i++)
{
const QRgb *scanline = reinterpret_cast<const QRgb *>(qimage.scanLine(i));
for (int j = 0; j< width; ++j)
const QRgb *end = scanline + qimage.width();
for (; scanline != end; scanline++)
{
binaryImage.append((char) qRed(scanline[j]));
binaryImage.append((char) qGreen(scanline[j]));
binaryImage.append((char) qBlue(scanline[j]));
binaryImage.append(!grayscale ? (char) qRed(scanline[0]) : (char) qGray(scanline[0]));
binaryImage.append(!grayscale ? (char) qGreen(scanline[1]) : (char) qGray(scanline[1]));
binaryImage.append(!grayscale ? (char) qBlue(scanline[2]) : (char) qGray(scanline[2]));
}
}
PyList_SET_ITEM(result, i, Py_BuildValue("{s:i,s:i,s:O}", "imageWidth", width, "imageHeight", height, "imageData", PyByteArray_FromStringAndSize(binaryImage.constData(),binaryImage.size())));
@@ -283,6 +327,7 @@ PyObject* EffectModule::wrapGetImage(PyObject *self, PyObject *args)
return nullptr;
}
}
return result;
}
else