503 lines
16 KiB
Python
503 lines
16 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Generate period-accurate decorative GIFs for 90s retro websites.
|
||
|
|
Creates pixel art icons, bullet points, animated badges, etc.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import struct
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
|
||
|
|
|
||
|
|
def create_gif(width, height, frames=None, loop=0):
|
||
|
|
"""Create a GIF89a image with optional animation frames.
|
||
|
|
frames: list of [[(r,g,b), ...], ...] where each frame is pixel colour array
|
||
|
|
If frames is None, creates a simple solid colour image at 1x1"""
|
||
|
|
|
||
|
|
if frames is None:
|
||
|
|
# Default to simple solid colour
|
||
|
|
frames = [[(255, 255, 255)]]
|
||
|
|
|
||
|
|
if len(frames[0]) == 0:
|
||
|
|
frames = [[(0, 0, 0)]]
|
||
|
|
|
||
|
|
# Build a master frame for header dimensions
|
||
|
|
fh, fw = len(frames[0]), len(frames[0][0]) if frames[0] else 1
|
||
|
|
|
||
|
|
# GIF Header
|
||
|
|
header = b'GIF89a'
|
||
|
|
|
||
|
|
# Logical Screen Descriptor
|
||
|
|
lsd = struct.pack('<HH', fw, fh)
|
||
|
|
lsd += b'\x00' # No GCT, 8-bit colour resolution
|
||
|
|
lsd += b'\x00' # Background colour index
|
||
|
|
lsd += b'\x00' # Pixel aspect ratio
|
||
|
|
|
||
|
|
# Image Descriptor for each frame
|
||
|
|
all_img_data = b''
|
||
|
|
for frame_data in frames:
|
||
|
|
fheight = len(frame_data)
|
||
|
|
fwidth = len(frame_data[0]) if frame_data else 1
|
||
|
|
|
||
|
|
img = b'\x2C' # Image Separator
|
||
|
|
img += struct.pack('<HHHH', 0, 0, fwidth, fheight)
|
||
|
|
img += b'\x00' # no local colour table
|
||
|
|
|
||
|
|
# LZW minimum code size
|
||
|
|
img += bytes([2])
|
||
|
|
|
||
|
|
col_index = 1 # use colour index 1 (2 colours = 2-bit codes)
|
||
|
|
|
||
|
|
# Build data for each pixel
|
||
|
|
for row in frame_data:
|
||
|
|
for pixel in row:
|
||
|
|
total_pixels = fwidth * fheight
|
||
|
|
raw_bits = 1
|
||
|
|
|
||
|
|
bits = []
|
||
|
|
for _ in range(total_pixels):
|
||
|
|
bits.append(1)
|
||
|
|
|
||
|
|
bitstream = ''.join(str(b) for b in bits)
|
||
|
|
data_bytes = bytearray()
|
||
|
|
for i in range(0, len(bitstream), 8):
|
||
|
|
byte = bitstream[i:i+8]
|
||
|
|
if len(byte) < 8:
|
||
|
|
byte = byte.ljust(8, '0')
|
||
|
|
data_bytes.append(int(byte, 2))
|
||
|
|
|
||
|
|
clear_code = 4
|
||
|
|
eoi_code = 5
|
||
|
|
|
||
|
|
sub_data = bytes([clear_code]) + bytes(data_bytes) + bytes([eoi_code])
|
||
|
|
|
||
|
|
i = 0
|
||
|
|
while i < len(sub_data):
|
||
|
|
block_size = min(255, len(sub_data) - i)
|
||
|
|
img += bytes([block_size])
|
||
|
|
img += sub_data[i:i+block_size]
|
||
|
|
i += block_size
|
||
|
|
|
||
|
|
img += b'\x00' # sub-block terminator
|
||
|
|
img += b'\x3B' # trailer
|
||
|
|
|
||
|
|
return header + lsd + all_img_data
|
||
|
|
|
||
|
|
|
||
|
|
def write_single_pixel_gif(filepath, r, g, b, ext=''):
|
||
|
|
"""Create a minimal single-pixel GIF with a given colour, using raw bytes.
|
||
|
|
More reliable than the complex LZW encoder above."""
|
||
|
|
|
||
|
|
# Minimal valid GIF89a: 1x1 pixel, single colour
|
||
|
|
gif = bytearray()
|
||
|
|
gif.extend(b'GIF89a')
|
||
|
|
|
||
|
|
# Logical Screen Descriptor
|
||
|
|
gif += struct.pack('<HH', 1, 1)
|
||
|
|
gif += b'\x80' # GCT present, 1-bit colour resolution, 2^1=2 colours
|
||
|
|
gif += b'\x00' # background
|
||
|
|
gif += b'\x00' # aspect ratio
|
||
|
|
|
||
|
|
# Global Color Table: 2 entries (index 0 = black, index 1 = target colour)
|
||
|
|
gif += b'\x00\x00\x00' # index 0: black
|
||
|
|
gif += struct.pack('BBB', r, g, b) # index 1: target colour
|
||
|
|
|
||
|
|
# Image Descriptor
|
||
|
|
gif += b'\x2C' # image separator
|
||
|
|
gif += struct.pack('<HHHH', 0, 0, 1, 1)
|
||
|
|
gif += b'\x00' # no local colour table
|
||
|
|
|
||
|
|
# LZW minimum code size
|
||
|
|
gif.append(2)
|
||
|
|
|
||
|
|
# Image data sub-block
|
||
|
|
gif += bytes([4, 2, 0x02, 0x00, 5, 0x00]) # clear, data, eoi in compact form
|
||
|
|
gif += b'\x3B' # trailer
|
||
|
|
|
||
|
|
with open(filepath, 'wb') as f:
|
||
|
|
f.write(bytes(gif))
|
||
|
|
|
||
|
|
|
||
|
|
def write_pixel_image_gif(filepath, pixels, fg=(255,255,255), bg=(0,0,0)):
|
||
|
|
"""Write a small pixel-art GIF. pixels = 2D array of 0 (bg) or 1 (fg)"""
|
||
|
|
w = len(pixels[0])
|
||
|
|
h = len(pixels)
|
||
|
|
|
||
|
|
gif = bytearray()
|
||
|
|
gif.extend(b'GIF89a')
|
||
|
|
gif += struct.pack('<HH', w, h)
|
||
|
|
gif += b'\x80' # GCT present, 1-bit
|
||
|
|
gif += b'\x00\x00'
|
||
|
|
|
||
|
|
# GCT: index 0 = bg, index 1 = fg
|
||
|
|
gif += struct.pack('BBB', *bg)
|
||
|
|
gif += struct.pack('BBB', *fg)
|
||
|
|
|
||
|
|
# Image Descriptor
|
||
|
|
gif += b'\x2C'
|
||
|
|
gif += struct.pack('<HHHH', 0, 0, w, h)
|
||
|
|
gif += b'\x00'
|
||
|
|
|
||
|
|
# LZW code size
|
||
|
|
gif.append(2)
|
||
|
|
|
||
|
|
# Create pixel data as bit stream
|
||
|
|
bits = bytearray()
|
||
|
|
for y in range(h):
|
||
|
|
for x in range(w):
|
||
|
|
bits.append(pixels[y][x])
|
||
|
|
|
||
|
|
# Pack into bytes (MSB first)
|
||
|
|
data = bytearray()
|
||
|
|
for i in range(0, len(bits), 8):
|
||
|
|
byte = 0
|
||
|
|
for j in range(8):
|
||
|
|
if i + j < len(bits):
|
||
|
|
byte |= (bits[i+j] << (7-j))
|
||
|
|
data.append(byte)
|
||
|
|
|
||
|
|
# Encode: clear + data + eoi
|
||
|
|
sub_data = bytearray()
|
||
|
|
sub_data.append(4) # clear code (100 in binary for 2-bit)
|
||
|
|
|
||
|
|
# Add pixel runs
|
||
|
|
for i, b in enumerate(bits):
|
||
|
|
sub_data.append(b)
|
||
|
|
|
||
|
|
sub_data.append(5) # EOI
|
||
|
|
sub_data.append(0) # terminator for last byte
|
||
|
|
|
||
|
|
# Write sub-blocks
|
||
|
|
offset = 0
|
||
|
|
while offset < len(sub_data):
|
||
|
|
block_size = min(255, len(sub_data) - offset)
|
||
|
|
gif.append(block_size)
|
||
|
|
gif.extend(sub_data[offset:offset+block_size])
|
||
|
|
offset += block_size
|
||
|
|
|
||
|
|
gif.append(0) # sub-block terminator
|
||
|
|
gif.append(0x3B) # trailer
|
||
|
|
|
||
|
|
with open(filepath, 'wb') as f:
|
||
|
|
f.write(bytes(gif))
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
outdir = sys.argv[1] if len(sys.argv) > 1 else './retro-images'
|
||
|
|
os.makedirs(outdir, exist_ok=True)
|
||
|
|
|
||
|
|
created = 0
|
||
|
|
|
||
|
|
# ========== SPACER GIFS (simple single-pixel) ==========
|
||
|
|
spacers = [
|
||
|
|
('blue.gif', 0, 0, 200),
|
||
|
|
('navy.gif', 0, 0, 128),
|
||
|
|
('white.gif', 255, 255, 255),
|
||
|
|
('grey.gif', 192, 192, 192),
|
||
|
|
('light_grey.gif', 220, 220, 220),
|
||
|
|
('dark_grey.gif', 100, 100, 100),
|
||
|
|
('red.gif', 200, 0, 0),
|
||
|
|
('yellow.gif', 255, 255, 0),
|
||
|
|
('green.gif', 0, 255, 0),
|
||
|
|
('orange.gif', 255, 165, 0),
|
||
|
|
('cyan.gif', 0, 255, 255),
|
||
|
|
('magenta.gif', 255, 0, 255),
|
||
|
|
('gold.gif', 255, 215, 0),
|
||
|
|
('transparent.gif', 0, 0, 0), # special handling
|
||
|
|
]
|
||
|
|
|
||
|
|
for fname, r, g, b in spacers:
|
||
|
|
if fname == 'transparent.gif':
|
||
|
|
# Transparent 1x1 GIF
|
||
|
|
gif = bytearray(b'GIF89a')
|
||
|
|
gif += struct.pack('<HH', 1, 1)
|
||
|
|
gif += b'\x80\x00\x00\x00' # GCT, 1-bit
|
||
|
|
gif += b'\x00\x00\x00' # transparent (index 0)
|
||
|
|
gif += b'\x00\xFF\x00' # solid (index 1, arbitrary colour)
|
||
|
|
gif += b'\x21\xF9\x04\x01\x00\x00\x00\x00' # graphics control extension for transparency
|
||
|
|
gif += b'\x2C' # image separator
|
||
|
|
gif += struct.pack('<HHHH', 0, 0, 1, 1)
|
||
|
|
gif += b'\x00'
|
||
|
|
gif.append(2) # min code size
|
||
|
|
gif += bytes([4, 1, 1, 2, 0x02, 0x00, 5, 0x00])
|
||
|
|
gif += b'\x3B'
|
||
|
|
with open(os.path.join(outdir, fname), 'wb') as f:
|
||
|
|
f.write(bytes(gif))
|
||
|
|
print(f" OK {fname:20s} (1x1 transparent)")
|
||
|
|
else:
|
||
|
|
write_single_pixel_gif(os.path.join(outdir, fname), r, g, b)
|
||
|
|
print(f" OK {fname:20s} ({r},{g},{b})")
|
||
|
|
|
||
|
|
created += len(spacers)
|
||
|
|
|
||
|
|
# ========== BULLET DOT ==========
|
||
|
|
# Small 8x8 diamond bullet
|
||
|
|
bullet = [
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
[0,0,1,1,1,1,0,0],
|
||
|
|
[0,1,1,1,1,1,1,0],
|
||
|
|
[1,1,1,1,1,1,1,1],
|
||
|
|
[1,1,1,1,1,1,1,1],
|
||
|
|
[0,1,1,1,1,1,1,0],
|
||
|
|
[0,0,1,1,1,1,0,0],
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'bullet.gif'), bullet, fg=(0,0,200), bg=(0,0,0))
|
||
|
|
print(" OK bullet.gif (8x8 blue diamond bullet)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== NEW! BADGE ==========
|
||
|
|
new_badge = [
|
||
|
|
[1,1,1,1,1,1,1,1,1,1,1,1],
|
||
|
|
[1,0,0,0,0,0,0,0,0,0,0,1],
|
||
|
|
[1,0,1,1,1,0,0,1,1,1,0,1],
|
||
|
|
[1,0,1,0,1,0,0,0,1,0,0,1],
|
||
|
|
[1,0,1,1,1,0,0,1,1,0,0,1],
|
||
|
|
[1,0,1,0,1,0,0,0,0,0,0,1],
|
||
|
|
[1,0,1,1,1,0,0,1,1,1,1,1],
|
||
|
|
[1,0,0,0,0,0,0,0,0,0,0,1],
|
||
|
|
[1,1,1,1,1,1,1,1,1,1,1,1],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'new.gif'), new_badge, fg=(255, 0, 0), bg=(255, 255, 0))
|
||
|
|
print(" OK new.gif (9x12 red 'NEW!' badge on yellow)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== STAR ==========
|
||
|
|
star = [
|
||
|
|
[0,0,0,1,0,0,0],
|
||
|
|
[0,0,1,1,1,0,0],
|
||
|
|
[0,1,1,1,1,1,0],
|
||
|
|
[1,1,0,1,0,1,1],
|
||
|
|
[1,0,0,0,0,0,1],
|
||
|
|
[0,1,1,1,1,1,0],
|
||
|
|
[0,0,1,1,1,0,0],
|
||
|
|
[0,1,1,0,1,1,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'star.gif'), star, fg=(255, 215, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK star.gif (7x8 gold star)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== SPARKLE ==========
|
||
|
|
sparkle = [
|
||
|
|
[0,0,1,0,0],
|
||
|
|
[0,0,1,0,0],
|
||
|
|
[1,1,1,1,1],
|
||
|
|
[0,0,1,0,0],
|
||
|
|
[0,0,1,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'sparkle.gif'), sparkle, fg=(0, 255, 255), bg=(0, 0, 0))
|
||
|
|
print(" OK sparkle.gif (5x5 cyan sparkle)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== MAILTO ENVELOPE ==========
|
||
|
|
mail = [
|
||
|
|
[1,1,1,1,1,1,1,1],
|
||
|
|
[1,0,0,0,0,0,0,1],
|
||
|
|
[1,0,0,1,0,0,0,1],
|
||
|
|
[1,0,1,0,0,1,0,1],
|
||
|
|
[1,0,0,0,0,0,0,1],
|
||
|
|
[1,0,0,0,0,0,0,1],
|
||
|
|
[1,1,1,1,1,1,1,1],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'mailto.gif'), mail, fg=(255, 255, 0), bg=(0, 50, 0))
|
||
|
|
print(" OK mailto.gif (7x8 yellow envelope on dark green)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== CONSTRUCTION SIGN ==========
|
||
|
|
construction = [
|
||
|
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||
|
|
[1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1],
|
||
|
|
[1,1,0,0,1,0,1,0,1,0,1,0,0,0,1,1],
|
||
|
|
[1,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1],
|
||
|
|
[1,1,0,0,1,0,1,0,1,0,1,0,0,0,1,1],
|
||
|
|
[1,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1],
|
||
|
|
[1,1,0,0,1,0,1,0,1,0,1,0,0,0,1,1],
|
||
|
|
[1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1],
|
||
|
|
[1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1],
|
||
|
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'construction.gif'), construction, fg=(255, 165, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK construction.gif (9x16 orange construction icon)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== EMAIL ICON ==========
|
||
|
|
email_icon = [
|
||
|
|
[0,1,1,1,1,1,1,0],
|
||
|
|
[1,1,0,0,0,0,1,1],
|
||
|
|
[1,0,1,0,0,1,0,1],
|
||
|
|
[1,0,0,1,1,0,0,1],
|
||
|
|
[1,0,0,0,0,0,0,1],
|
||
|
|
[1,1,0,0,0,0,1,1],
|
||
|
|
[0,1,1,1,1,1,1,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'email_icon.gif'), email_icon, fg=(0, 0, 200), bg=(0, 0, 0))
|
||
|
|
print(" OK email_icon.gif (7x8 blue mail icon)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== WEB RING SYMBOL ==========
|
||
|
|
webring = [
|
||
|
|
[0,0,1,1,1,1,1,1,0,0],
|
||
|
|
[0,1,0,0,0,0,0,0,1,0],
|
||
|
|
[1,0,1,0,0,0,0,1,0,1],
|
||
|
|
[1,0,0,1,0,0,1,0,0,1],
|
||
|
|
[1,0,0,0,1,1,0,0,0,1],
|
||
|
|
[1,0,0,0,1,1,0,0,0,1],
|
||
|
|
[1,0,0,1,0,0,1,0,0,1],
|
||
|
|
[1,0,1,0,0,0,0,1,0,1],
|
||
|
|
[0,1,0,0,0,0,0,0,1,0],
|
||
|
|
[0,0,1,1,1,1,1,1,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'webring.gif'), webring, fg=(0, 200, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK webring.gif (10x10 green ring icon)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== FIREFLAME BOTTOM BAR ==========
|
||
|
|
flame = [
|
||
|
|
[0,0,0,0,1,1,0,0,0,0],
|
||
|
|
[0,0,0,1,1,1,1,0,0,0],
|
||
|
|
[0,0,1,1,0,0,1,1,0,0],
|
||
|
|
[0,1,1,0,1,1,0,1,1,0],
|
||
|
|
[1,1,0,1,1,1,1,0,1,1],
|
||
|
|
[1,0,1,0,0,0,0,1,0,1],
|
||
|
|
[1,1,1,1,1,1,1,1,1,1],
|
||
|
|
[0,0,0,0,0,0,0,0,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'flame.gif'), flame, fg=(255, 100, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK flame.gif (8x10 orange flame icon)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== NAV ARROW ==========
|
||
|
|
arrow_right = [
|
||
|
|
[0,0,0,0,1,0,0,0],
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
[1,0,1,1,0,1,0,0],
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
[0,0,0,1,1,0,0,0],
|
||
|
|
[0,0,0,0,1,0,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'arrow_right.gif'), arrow_right, fg=(0, 255, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK arrow_right.gif (7x8 green right arrow)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
arrow_left = [
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,1,0,0,1,0,0],
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,0,1,0,0,0,0],
|
||
|
|
]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'arrow_left.gif'), arrow_left, fg=(0, 255, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK arrow_left.gif (7x8 green left arrow)")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== TILDED STAR (for decorative headings) ==========
|
||
|
|
tstar = []
|
||
|
|
for row_data in [
|
||
|
|
[0,0,0,0,1,0,0,0,0],
|
||
|
|
[0,0,0,1,1,1,0,0,0],
|
||
|
|
[0,0,1,1,1,1,1,0,0],
|
||
|
|
[0,1,1,1,1,1,1,1,0],
|
||
|
|
[1,1,0,1,1,1,0,1,1],
|
||
|
|
[1,0,0,0,1,0,0,0,1],
|
||
|
|
[0,1,1,1,1,1,1,1,0],
|
||
|
|
[0,0,1,0,0,0,1,0,0],
|
||
|
|
[0,0,0,1,0,1,0,0,0],
|
||
|
|
]:
|
||
|
|
tstar.append(row_data)
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'tstar.gif'), tstar, fg=(255, 255, 0), bg=(0, 0, 0))
|
||
|
|
print(" OK tstar.gif (9x9 yellow star")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== COUNTER DIGITS ==========
|
||
|
|
# Simple 5x3 pixel digit glyphs for visitor counter
|
||
|
|
# Digits 0-9 as 5-col, 3-row arrays
|
||
|
|
digits = {
|
||
|
|
0: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,1,0,0],
|
||
|
|
],
|
||
|
|
1: [
|
||
|
|
[0,1,0,0,0],
|
||
|
|
[1,1,0,0,0],
|
||
|
|
[1,1,1,0,0],
|
||
|
|
],
|
||
|
|
2: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[0,0,1,1,0],
|
||
|
|
[1,1,0,1,0],
|
||
|
|
],
|
||
|
|
3: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[0,0,1,1,0],
|
||
|
|
[1,1,1,0,0],
|
||
|
|
],
|
||
|
|
4: [
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,1,1,0],
|
||
|
|
[0,0,0,1,0],
|
||
|
|
],
|
||
|
|
5: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,1,1,0],
|
||
|
|
],
|
||
|
|
6: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,1,1,0],
|
||
|
|
],
|
||
|
|
7: [
|
||
|
|
[0,1,1,1,0],
|
||
|
|
[0,0,0,1,0],
|
||
|
|
[0,0,0,1,0],
|
||
|
|
],
|
||
|
|
8: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,1,0,0],
|
||
|
|
],
|
||
|
|
9: [
|
||
|
|
[1,1,1,0,0],
|
||
|
|
[1,0,0,1,0],
|
||
|
|
[1,1,0,1,0],
|
||
|
|
],
|
||
|
|
}
|
||
|
|
|
||
|
|
for digit_char in '0123450042':
|
||
|
|
d = int(digit_char)
|
||
|
|
digits[d].append([0]*5)
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, f'counter_{digit_char}.gif'), digits[d], fg=(255, 255, 255), bg=(0, 0, 0))
|
||
|
|
print(f" OK counter_{digit_char}.gif")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== VISITOR COUNTER STRING ==========
|
||
|
|
# Make counter.gif as sequence: " 12342"
|
||
|
|
# Build a multi-pixel counter image
|
||
|
|
count_digits = '000000'
|
||
|
|
count_w = 21
|
||
|
|
count_h = 12
|
||
|
|
count_img = [[0]*count_w for _ in range(count_h)]
|
||
|
|
for i, c in enumerate(count_digits):
|
||
|
|
d = digits[int(c)]
|
||
|
|
for row in range(len(d)):
|
||
|
|
for col in range(len(d[row])):
|
||
|
|
count_img[row][i*3+col+1] = d[row][col]
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'counter.gif'), count_img, fg=(255, 255, 150), bg=(0, 0, 0))
|
||
|
|
print(f" OK counter.gif (21x12 '000000')")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
# ========== COUNTER BOTTOM ==========
|
||
|
|
count_bottom_digits = '000000'
|
||
|
|
write_pixel_image_gif(os.path.join(outdir, 'counter_bottom.gif'), count_img, fg=(200, 200, 100), bg=(0, 0, 0))
|
||
|
|
print(f" OK counter_bottom.gif (21x12 '000000')")
|
||
|
|
created += 1
|
||
|
|
|
||
|
|
print(f"\nGenerated {created} GIFs in {outdir}/")
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|