diff --git a/effects/fire.gif b/effects/fire.gif new file mode 100644 index 00000000..ce8a4731 Binary files /dev/null and b/effects/fire.gif differ diff --git a/effects/fire.json b/effects/fire.json new file mode 100644 index 00000000..c0109e3f --- /dev/null +++ b/effects/fire.json @@ -0,0 +1,10 @@ +{ + "name" : "Fire", + "script" : "gif.py", + "args" : + { + "image" : ":fire.gif", + "fps" :25, + "reverse" : false + } +} diff --git a/effects/gif.py b/effects/gif.py new file mode 100644 index 00000000..e89621a0 --- /dev/null +++ b/effects/gif.py @@ -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) diff --git a/effects/lights.gif b/effects/lights.gif new file mode 100644 index 00000000..b1d83a7e Binary files /dev/null and b/effects/lights.gif differ diff --git a/effects/lights.json b/effects/lights.json new file mode 100644 index 00000000..898e76b9 --- /dev/null +++ b/effects/lights.json @@ -0,0 +1,10 @@ +{ + "name" : "Lights", + "script" : "gif.py", + "args" : + { + "image" : ":lights.gif", + "fps" :25, + "reverse" : false + } +} diff --git a/effects/schema/gif.schema.json b/effects/schema/gif.schema.json new file mode 100644 index 00000000..0a61dc11 --- /dev/null +++ b/effects/schema/gif.schema.json @@ -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 +} diff --git a/effects/schema/snake.schema.json b/effects/schema/snake.schema.json index f7135468..f78a47fe 100644 --- a/effects/schema/snake.schema.json +++ b/effects/schema/snake.schema.json @@ -18,20 +18,34 @@ "maxItems": 3, "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": { "type": "number", "title":"edt_eff_rotationtime", "default": 12.0, "minimum" : 0.1, "append" : "edt_append_s", - "propertyOrder" : 2 + "propertyOrder" : 3 }, "percentage": { "type": "integer", "title":"edt_eff_length", "default": 10, "append" : "edt_append_percent", - "propertyOrder" : 3 + "propertyOrder" : 4 } }, "additionalProperties": false diff --git a/effects/snake.json b/effects/snake.json index d5a7674f..2babadd0 100644 --- a/effects/snake.json +++ b/effects/snake.json @@ -5,6 +5,7 @@ { "rotation-time" : 12.0, "color" : [255, 0, 0], + "background-color" : [0, 0, 0], "percentage" : 10 } } diff --git a/effects/snake.py b/effects/snake.py index d8d16561..d7b3729b 100644 --- a/effects/snake.py +++ b/effects/snake.py @@ -5,6 +5,7 @@ import colorsys # Get the parameters rotationTime = float(hyperion.args.get('rotation-time', 10.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)) # Check parameters @@ -13,17 +14,23 @@ percentage = max(1, min(percentage, 100)) # Process parameters 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 snakeLeds = max(1, int(hyperion.ledCount*factor)) ledData = bytearray() -for i in range(hyperion.ledCount-snakeLeds): - ledData += bytearray((0, 0, 0)) +color_hsv = colorsys.rgb_to_hsv(color[0]/255.0,color[1]/255.0,color[2]/255.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): - rgb = colorsys.hsv_to_rgb(hsv[0], hsv[1], hsv[2]*(snakeLeds-i)/snakeLeds) +for i in range(hyperion.ledCount-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))) # Calculate the sleep time and rotation increment diff --git a/libsrc/effectengine/Effect.cpp b/libsrc/effectengine/Effect.cpp index a29dd951..c15a0c29 100644 --- a/libsrc/effectengine/Effect.cpp +++ b/libsrc/effectengine/Effect.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include // effect engin eincludes #include "Effect.h" @@ -24,6 +26,7 @@ PyMethodDef Effect::effectMethods[] = { {"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."}, + {"getImage" , Effect::wrapGetImage , METH_VARARGS, "get image data from file."}, {"abort" , Effect::wrapAbort , METH_NOARGS, "Check if the effect should abort execution."}, {"imageShow" , Effect::wrapImageShow , METH_VARARGS, "set current effect image to hyperion core."}, {"imageLinearGradient" , Effect::wrapImageLinearGradient , METH_VARARGS, ""}, @@ -465,6 +468,85 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args) 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(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 *) { Effect * effect = getEffect(); diff --git a/libsrc/effectengine/Effect.h b/libsrc/effectengine/Effect.h index ce4aa8b0..088c6d06 100644 --- a/libsrc/effectengine/Effect.h +++ b/libsrc/effectengine/Effect.h @@ -46,6 +46,7 @@ private: static PyMethodDef effectMethods[]; static PyObject* wrapSetColor (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* wrapImageShow (PyObject *self, PyObject *args); static PyObject* wrapImageLinearGradient (PyObject *self, PyObject *args);