pixoo
pixoo copied to clipboard
No GIF animations possible?
First of al, thank you for this great library!
I was wondering how to load a GIF animation. If i use the draw_image function with a GIF animation only the first image is visible, and it's not animated.
According to the Divoom api it should be possible with Json:
{ “Command”:”Device/PlayTFGif”, “FileType”:2, “FileName”:”http://f.divoom-gz.com/64_64.gif“ }
But it seems that this is not integrated?
Cheers.
That's a good point, I'll look into it! I remember testing something similar but crashing my Pixoo over and over. But I did notice there's been quite a few updates to the firmware, so it's worth another shot, surely.
Thanks for the reply!
Before I tried your library I used this piece of javascript. (I dynamically replaced the gif every couple of minutes in the actual script). I didn't encounter any crashes over the course of 4 weeks. Except when I refer a GIF animation link that it does not understand (like a tenor link with no .gif extension).
fetch('http://192.168.178.206:80/post', {
method: 'POST',
body: JSON.stringify(
{
"Command":"Device/PlayTFGif",
"FileType":2,
"FileName": "http://kimchigraphics.com/wp-content/uploads/2022/04/Solar-flag-64x64-1.gif"
})
}).then(res => res.json())
.then(res => console.log(res));
I was kind of hoping I could create small gif-animations and put custom text on top of it. Like those the pre-made examples in the Divoom app. (or they could be full screen GIF animation with text on top of it, I don't know).
Anyhow, the possibility of adding support for GIF animations would be great.
Alright it seems like "PlayTFGif" can only play GIFs that are stored on an internal SD card.
However, I'm looking into the animation call, which theoretically can display a GIF, if I can convert it to some sort of buffered image first. I'll be looking into it!
@SomethingWithComputers Any progress on this one? I'd love to see this feature in your library.
@Phlogi Hey! I've been working on a system to locally load GIFs as a background image basically, and display them with a specific FPS! But I'm currently really occupied with my work.. Real life. But I'll make it work sometime in the near future if somebody else doesn't pick it up first :)!
It'll basically be the same method that loads an image currently, but with some extra in-memory bookkeeping for displaying the correct frame and loop it if needed But in order for that to work correctly there needs to be some sort of internal clock/timer and I'm not a fan of that in the current version. I'd rather it'd be pased on the manual push calls and I want to keep it as light-weight as possible. But we'll see how it works!
maybe i can push my solution for this problem. Currently some refactoring and optimization necessary. :)
Thanks to both of you. In the meantime I'll use pixoo-rest which supports animated GIFS.
Would love to see the current progress here from @SomethingWithComputers - maybe I can pickup and help from where you currently are? Even simple gif-animations with no speed/FPS-control would be awesome!
Kudos and a big thanks for what you've achieved so far!
Agreed! Thank you so much for this awesome API. I am also investigating how to get gifs to work properly. Looking forward to the update.
I've been tinkering with the Pixoo 64, and I believe I've solved this.
The key is to set PicNum
to the number of frames your animation has.
So here's the parameters you need:
PicNum = 10 # The number of frames in your GIF. In this example, my GIF has 10 frames. You can use `Image.open("yourfile.gif").n_frames` to determine this programmatically
PicWidth = 64 # The width of your picture, obviously.
PicOffset = 1 # This is the current frame number you're sending. As you send each frame, you need to increment this
PicId = 1 # You can use `Draw/GetHttpGifId` to get this number, then add 1. Or you can just use `Draw/ResetHttpGifId` to reset it back to 1. You can send more than one GIF at a time, and it'll play each one for a short while, but it'll loop the last one indefinitely instead of looping back to ID 1
PicSpeed = 500 # The duration of the frame. You can use the `.info` property of a PIL image object to get the duration of the frame, like so: `yourimage.info["duration"]`
PicData = "" # Your data here. The data is just a list in the format `[R, G, B, R, G, B, R, G, B]`, repeated for `size * size` times (e.g. 4096 times)
And side note, PIL (or rather, Pillow) has a function, getdata()
, which returns a list of tuples with R, G and B data in it. This means that you can create a base64 string like so:
# Open the GIF
img = Image.open(filename)
# Loop through all the frames in the animation
for frame in range(0, img.n_frames):
# Go the frame in question
img.seek(frame)
# Convert it to RGB because the device expects a list of red, green and blue pixels
imgrgb = img.convert(mode="RGB")
# This line gets all the RGB values from a frame as a list of tuples. The tuples are then just flattened out to a list
# The result will look similar to this: `[255, 0, 0, 255, 0, 0, 255, 0, 0 ...]` for a purely red image
pixels = [item for p in list(imgrgb.getdata()) for item in p]
# Base64 encode the pixels we grabbed from the frame. Turn the list into a bytearray
b64 = base64.b64encode(bytearray(pixels))
# frameData contains the data you need to send to the Pixoo 64
frameData = b64.decode("utf-8")
Much smaller code than what your library currently has, if you want to use it.
Anyway, hopefully this code helps you out. I've spent about a week poking around, writing my own Python library, mostly to just teach myself Python and map out the pretty crappy Divoom API documentation they give us.
@Grayda , I have also been tinkering with the API. That suggestion looks great, I'm still trying to understand how to get it to work. From your code, it looks like you're looping over each frame to encode every pixel of every frame, however at the end of the logic you're overwriting the frameData each frame? How are you passing in all of the frames?
@Grayda , I have also been tinkering with the API. That suggestion looks great, I'm still trying to understand how to get it to work. From your code, it looks like you're looping over each frame to encode every pixel of every frame, however at the end of the logic you're overwriting the frameData each frame? How are you passing in all of the frames?
What I forgot to add to my reply is, at the end of every iteration, I'm POSTing that data to the Pixoo.
So yeah, I'm overwriting frameData
every time, because I'm sending every frame of the animation separately. It's a horrible way to do it, but that's how the Pixoo expects the data, as individual API calls of individual frames
@Grayda , ahh gotcha. thanks for the response! I'm curious. Have you tried the play gif API command? It looks like loading gifs is a first-class command and may alleviate the need for processing each frame.
@Grayda , ahh gotcha. thanks for the response! I'm curious. Have you tried the play gif API command? It looks like loading gifs is a first-class command and may alleviate the need for processing each frame.
Yep, but unfortunately you can't display text on the screen with that, only when you send individual frames. That's fine if you want to just show images, but my end goal is to use it to show Home Assistant notifications on there, plus write my own clock face to display stats like upcoming calendar events.
It is now possible to load gifs from the internet and display them on the device, or load them from the local TF card.
Supported GIF sizes are: 16 x 16, 32 x 32, 64 x 64
- Added
play_net_gif
to loop the GIF from a URL on the device - Added
play_local_gif
to play a GIF from the TF-card in the device (untested) - Added
play_local_gif_directory
to play the GIFs in a directory on the TF-card in the device (untested)