mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Use GIF files for effects (#477)
* Add new Effects * add schema file for gif based effects * add background color to snake effect * add background color to snake effect * Update schema file for snake effect * Add function getImage * add function getImage * optimize lights.gif * Add format to GIF schema
This commit is contained in:
parent
838008568a
commit
9cc6c75633
BIN
effects/fire.gif
Normal file
BIN
effects/fire.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 106 KiB |
10
effects/fire.json
Normal file
10
effects/fire.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name" : "Fire",
|
||||||
|
"script" : "gif.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"image" : ":fire.gif",
|
||||||
|
"fps" :25,
|
||||||
|
"reverse" : false
|
||||||
|
}
|
||||||
|
}
|
16
effects/gif.py
Normal file
16
effects/gif.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import os, hyperion, time
|
||||||
|
|
||||||
|
# Get the parameters
|
||||||
|
imageFile = hyperion.args.get('image')
|
||||||
|
framesPerSecond = float(hyperion.args.get('fps', 25))
|
||||||
|
reverse = bool(hyperion.args.get('reverse', False))
|
||||||
|
|
||||||
|
sleepTime = 1./framesPerSecond
|
||||||
|
if imageFile:
|
||||||
|
imageList = list(reversed(hyperion.getImage(imageFile))) if reverse else hyperion.getImage(imageFile)
|
||||||
|
|
||||||
|
# Start the write data loop
|
||||||
|
while not hyperion.abort() and imageList:
|
||||||
|
for image in imageList:
|
||||||
|
hyperion.setImage(image.imageWidth, image.imageHeight, image.imageData)
|
||||||
|
time.sleep(sleepTime)
|
BIN
effects/lights.gif
Normal file
BIN
effects/lights.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 229 KiB |
10
effects/lights.json
Normal file
10
effects/lights.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name" : "Lights",
|
||||||
|
"script" : "gif.py",
|
||||||
|
"args" :
|
||||||
|
{
|
||||||
|
"image" : ":lights.gif",
|
||||||
|
"fps" :25,
|
||||||
|
"reverse" : false
|
||||||
|
}
|
||||||
|
}
|
31
effects/schema/gif.schema.json
Normal file
31
effects/schema/gif.schema.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"script" : "gif.py",
|
||||||
|
"title":"edt_eff_gif_header",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"image": {
|
||||||
|
"type": "string",
|
||||||
|
"title":"edt_eff_image",
|
||||||
|
"format" : "file",
|
||||||
|
"default": "",
|
||||||
|
"propertyOrder" : 1
|
||||||
|
},
|
||||||
|
"fps": {
|
||||||
|
"type": "integer",
|
||||||
|
"title":"edt_eff_fps",
|
||||||
|
"default": 25,
|
||||||
|
"minimum" : 1,
|
||||||
|
"maximum" : 100,
|
||||||
|
"step" : 1,
|
||||||
|
"propertyOrder" : 2
|
||||||
|
},
|
||||||
|
"reverse": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title":"edt_eff_reversedirection",
|
||||||
|
"default": false,
|
||||||
|
"propertyOrder" : 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
@ -18,20 +18,34 @@
|
|||||||
"maxItems": 3,
|
"maxItems": 3,
|
||||||
"propertyOrder" : 1
|
"propertyOrder" : 1
|
||||||
},
|
},
|
||||||
|
"background-color": {
|
||||||
|
"type": "array",
|
||||||
|
"title":"edt_eff_color",
|
||||||
|
"format":"colorpicker",
|
||||||
|
"default": [0,0,0],
|
||||||
|
"items" : {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 255
|
||||||
|
},
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 3,
|
||||||
|
"propertyOrder" : 2
|
||||||
|
},
|
||||||
"rotation-time": {
|
"rotation-time": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"title":"edt_eff_rotationtime",
|
"title":"edt_eff_rotationtime",
|
||||||
"default": 12.0,
|
"default": 12.0,
|
||||||
"minimum" : 0.1,
|
"minimum" : 0.1,
|
||||||
"append" : "edt_append_s",
|
"append" : "edt_append_s",
|
||||||
"propertyOrder" : 2
|
"propertyOrder" : 3
|
||||||
},
|
},
|
||||||
"percentage": {
|
"percentage": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"title":"edt_eff_length",
|
"title":"edt_eff_length",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
"append" : "edt_append_percent",
|
"append" : "edt_append_percent",
|
||||||
"propertyOrder" : 3
|
"propertyOrder" : 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
{
|
{
|
||||||
"rotation-time" : 12.0,
|
"rotation-time" : 12.0,
|
||||||
"color" : [255, 0, 0],
|
"color" : [255, 0, 0],
|
||||||
|
"background-color" : [0, 0, 0],
|
||||||
"percentage" : 10
|
"percentage" : 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import colorsys
|
|||||||
# Get the parameters
|
# Get the parameters
|
||||||
rotationTime = float(hyperion.args.get('rotation-time', 10.0))
|
rotationTime = float(hyperion.args.get('rotation-time', 10.0))
|
||||||
color = hyperion.args.get('color', (255,0,0))
|
color = hyperion.args.get('color', (255,0,0))
|
||||||
|
backgroundColor = hyperion.args.get('background-color', (0,0,0))
|
||||||
percentage = int(hyperion.args.get('percentage', 10))
|
percentage = int(hyperion.args.get('percentage', 10))
|
||||||
|
|
||||||
# Check parameters
|
# Check parameters
|
||||||
@ -13,17 +14,23 @@ percentage = max(1, min(percentage, 100))
|
|||||||
|
|
||||||
# Process parameters
|
# Process parameters
|
||||||
factor = percentage/100.0
|
factor = percentage/100.0
|
||||||
hsv = colorsys.rgb_to_hsv(color[0]/255.0, color[1]/255.0, color[2]/255.0)
|
|
||||||
|
|
||||||
# Initialize the led data
|
# Initialize the led data
|
||||||
snakeLeds = max(1, int(hyperion.ledCount*factor))
|
snakeLeds = max(1, int(hyperion.ledCount*factor))
|
||||||
ledData = bytearray()
|
ledData = bytearray()
|
||||||
|
|
||||||
for i in range(hyperion.ledCount-snakeLeds):
|
color_hsv = colorsys.rgb_to_hsv(color[0]/255.0,color[1]/255.0,color[2]/255.0)
|
||||||
ledData += bytearray((0, 0, 0))
|
backgroundColor_hsv = colorsys.rgb_to_hsv(backgroundColor[0]/255.0,backgroundColor[1]/255.0,backgroundColor[2]/255.0)
|
||||||
|
|
||||||
for i in range(1,snakeLeds+1):
|
for i in range(hyperion.ledCount-snakeLeds):
|
||||||
rgb = colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2]*(snakeLeds-i)/snakeLeds)
|
ledData += bytearray((int(backgroundColor[0]), int(backgroundColor[1]), int(backgroundColor[2])))
|
||||||
|
|
||||||
|
def lerp(a, b, t):
|
||||||
|
return (a[0]*(1-t)+b[0]*t, a[1]*(1-t)+b[1]*t, a[2]*(1-t)+b[2]*t)
|
||||||
|
|
||||||
|
for i in range(0, snakeLeds):
|
||||||
|
hsv = lerp(color_hsv, backgroundColor_hsv, 1.0/(snakeLeds-1)*i)
|
||||||
|
rgb = colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2])
|
||||||
ledData += bytearray((int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255)))
|
ledData += bytearray((int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255)))
|
||||||
|
|
||||||
# Calculate the sleep time and rotation increment
|
# Calculate the sleep time and rotation increment
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include <QConicalGradient>
|
#include <QConicalGradient>
|
||||||
#include <QRadialGradient>
|
#include <QRadialGradient>
|
||||||
#include <QRect>
|
#include <QRect>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QResource>
|
||||||
|
|
||||||
// effect engin eincludes
|
// effect engin eincludes
|
||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
@ -24,6 +26,7 @@
|
|||||||
PyMethodDef Effect::effectMethods[] = {
|
PyMethodDef Effect::effectMethods[] = {
|
||||||
{"setColor" , Effect::wrapSetColor , METH_VARARGS, "Set a new color for the leds."},
|
{"setColor" , Effect::wrapSetColor , METH_VARARGS, "Set a new color for the leds."},
|
||||||
{"setImage" , Effect::wrapSetImage , METH_VARARGS, "Set a new image to process and determine new led colors."},
|
{"setImage" , Effect::wrapSetImage , METH_VARARGS, "Set a new image to process and determine new led colors."},
|
||||||
|
{"getImage" , Effect::wrapGetImage , METH_VARARGS, "get image data from file."},
|
||||||
{"abort" , Effect::wrapAbort , METH_NOARGS, "Check if the effect should abort execution."},
|
{"abort" , Effect::wrapAbort , METH_NOARGS, "Check if the effect should abort execution."},
|
||||||
{"imageShow" , Effect::wrapImageShow , METH_VARARGS, "set current effect image to hyperion core."},
|
{"imageShow" , Effect::wrapImageShow , METH_VARARGS, "set current effect image to hyperion core."},
|
||||||
{"imageLinearGradient" , Effect::wrapImageLinearGradient , METH_VARARGS, ""},
|
{"imageLinearGradient" , Effect::wrapImageLinearGradient , METH_VARARGS, ""},
|
||||||
@ -465,6 +468,85 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* Effect::wrapGetImage(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
Q_INIT_RESOURCE(EffectEngine);
|
||||||
|
|
||||||
|
char *source;
|
||||||
|
if(!PyArg_ParseTuple(args, "s", &source))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "String required");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString file = QString::fromUtf8(source);
|
||||||
|
|
||||||
|
if (file.mid(0, 1) == ":")
|
||||||
|
file = ":/effects/"+file.mid(1);
|
||||||
|
|
||||||
|
QImageReader reader(file);
|
||||||
|
|
||||||
|
PyObject* prop;
|
||||||
|
static PyObject* imageClass = NULL;
|
||||||
|
|
||||||
|
if (imageClass == NULL)
|
||||||
|
imageClass = PyClass_New(NULL, PyDict_New(), PyString_FromString("ImageClass"));
|
||||||
|
|
||||||
|
if (reader.canRead())
|
||||||
|
{
|
||||||
|
PyObject* result = PyList_New(reader.imageCount());
|
||||||
|
|
||||||
|
for (int i = 0; i < reader.imageCount(); ++i)
|
||||||
|
{
|
||||||
|
reader.jumpToImage(i);
|
||||||
|
if (reader.canRead())
|
||||||
|
{
|
||||||
|
QImage qimage = reader.read();
|
||||||
|
PyObject* imageDict = PyDict_New();
|
||||||
|
|
||||||
|
int width = qimage.width();
|
||||||
|
int height = qimage.height();
|
||||||
|
|
||||||
|
prop = Py_BuildValue("i", width);
|
||||||
|
PyDict_SetItemString(imageDict, "imageWidth", prop);
|
||||||
|
Py_XDECREF(prop);
|
||||||
|
prop = Py_BuildValue("i", height);
|
||||||
|
PyDict_SetItemString(imageDict, "imageHeight", prop);
|
||||||
|
Py_XDECREF(prop);
|
||||||
|
|
||||||
|
QByteArray binaryImage;
|
||||||
|
for (int i = 0; i<height; ++i)
|
||||||
|
{
|
||||||
|
const QRgb * scanline = reinterpret_cast<const QRgb *>(qimage.scanLine(i));
|
||||||
|
for (int j = 0; j< width; ++j)
|
||||||
|
{
|
||||||
|
binaryImage.append((char) qRed(scanline[j]));
|
||||||
|
binaryImage.append((char) qGreen(scanline[j]));
|
||||||
|
binaryImage.append((char) qBlue(scanline[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = Py_BuildValue("O", PyByteArray_FromStringAndSize(binaryImage.constData(),binaryImage.size()));
|
||||||
|
PyDict_SetItemString(imageDict, "imageData", prop);
|
||||||
|
Py_XDECREF(prop);
|
||||||
|
|
||||||
|
PyList_SET_ITEM(result, i, Py_BuildValue("O", PyInstance_NewRaw(imageClass, imageDict)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, reader.errorString().toUtf8().constData());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, reader.errorString().toUtf8().constData());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PyObject* Effect::wrapAbort(PyObject *self, PyObject *)
|
PyObject* Effect::wrapAbort(PyObject *self, PyObject *)
|
||||||
{
|
{
|
||||||
Effect * effect = getEffect();
|
Effect * effect = getEffect();
|
||||||
|
@ -46,6 +46,7 @@ private:
|
|||||||
static PyMethodDef effectMethods[];
|
static PyMethodDef effectMethods[];
|
||||||
static PyObject* wrapSetColor (PyObject *self, PyObject *args);
|
static PyObject* wrapSetColor (PyObject *self, PyObject *args);
|
||||||
static PyObject* wrapSetImage (PyObject *self, PyObject *args);
|
static PyObject* wrapSetImage (PyObject *self, PyObject *args);
|
||||||
|
static PyObject* wrapGetImage (PyObject *self, PyObject *args);
|
||||||
static PyObject* wrapAbort (PyObject *self, PyObject *args);
|
static PyObject* wrapAbort (PyObject *self, PyObject *args);
|
||||||
static PyObject* wrapImageShow (PyObject *self, PyObject *args);
|
static PyObject* wrapImageShow (PyObject *self, PyObject *args);
|
||||||
static PyObject* wrapImageLinearGradient (PyObject *self, PyObject *args);
|
static PyObject* wrapImageLinearGradient (PyObject *self, PyObject *args);
|
||||||
|
Loading…
Reference in New Issue
Block a user