Academy · Lesson 4Academy · Lekcja 4

Images & GIFs with PillowObrazy i GIF-y z Pillow

This is the heart of GiphyFy: drawing images in code and sending them as GIFs — without ever saving a file. Let's recreate the idea. To serce GiphyFy: rysowanie obrazów w kodzie i wysyłanie ich jako GIF-y — bez zapisywania pliku. Odtwórzmy ten pomysł.

English / Polski IntermediateŚrednio zaawansowany 6 min

01 Install PillowInstalacja Pillow

Pillow is Python's go-to image library. GiphyFy uses it to render messages into pictures.

Pillow to podstawowa biblioteka Pythona do obrazów. GiphyFy używa jej, by zamieniać wiadomości w obrazki.

bash
python -m pip install -U Pillow

02 Draw an imageNarysuj obraz

Create a blank canvas, then draw text on it. Here we use Discord's dark background colour and light text — the same look GiphyFy's screenshots have.

Utwórz pusty obszar roboczy, a potem narysuj na nim tekst. Tutaj używamy ciemnego tła Discorda i jasnego tekstu — tak samo wyglądają zrzuty GiphyFy.

python
from PIL import Image, ImageDraw

img = Image.new("RGB", (400, 120), (43, 45, 49))   # Discord dark
draw = ImageDraw.Draw(img)
draw.text((16, 16), "mochi: energy-saving mode", fill=(219, 222, 225))
img.save("message.png")

03 Make an animated GIFZrób animowany GIF

A GIF is just a list of frames. Save the first frame with save_all=True and hand it the rest with append_images. duration is milliseconds per frame; loop=0 loops forever.

GIF to po prostu lista klatek. Zapisz pierwszą klatkę z save_all=True i przekaż resztę przez append_images. duration to milisekundy na klatkę; loop=0 zapętla w nieskończoność.

python
frames = [frame1, frame2, frame3]    # a list of PIL Images

frames[0].save(
    "out.gif",
    save_all=True,
    append_images=frames[1:],
    duration=125,    # ms per frame  -> 8 fps
    loop=0,          # loop forever
)

04 Send it from memoryWyślij z pamięci

Instead of saving to disk, write the image into an in-memory buffer with io.BytesIO and wrap it in discord.File. This is how GiphyFy stays "stateless" — nothing is stored.

Zamiast zapisywać na dysk, zapisz obraz do bufora w pamięci za pomocą io.BytesIO i opakuj go w discord.File. Tak GiphyFy pozostaje „bezstanowe” — nic nie jest przechowywane.

python
import io
import discord

buffer = io.BytesIO()
img.save(buffer, format="GIF")
buffer.seek(0)                       # rewind to the start
file = discord.File(buffer, filename="out.gif")
await interaction.response.send_message(file=file)

That's GiphyFy in a nutshell: render with Pillow, build a GIF, send it straight from memory — no files left behind.

To GiphyFy w pigułce: renderuj w Pillow, zbuduj GIF, wyślij go prosto z pamięci — bez pozostawiania plików.

05 Test yourselfSprawdź się

Q1. Which argument makes .save() write all frames of a GIF?Który argument sprawia, że .save() zapisuje wszystkie klatki GIF-a?
save_all=True tells Pillow to save every frame, not just the first.save_all=True mówi Pillow, by zapisał każdą klatkę, a nie tylko pierwszą.
Q2. What lets you send an image without saving a file?Co pozwala wysłać obraz bez zapisywania pliku?
An in-memory BytesIO buffer holds the image so you never touch the disk.Bufor BytesIO w pamięci przechowuje obraz, więc nie dotykasz dysku.