Initial commit
This commit is contained in:
commit
d057c6bf02
10 changed files with 167 additions and 0 deletions
24
README.md
Executable file
24
README.md
Executable file
|
@ -0,0 +1,24 @@
|
|||
![an autogenerated 10print pattern in blue](examples/palette_1.png)
|
||||
|
||||
# Generative Banner
|
||||
#### a little fun thing i made back in early 2023
|
||||
A bit of code that generates a 10 print pattern in one on the specified color palettes and sets the result as the banner on a Pleroma account. I made it run as a cronjob every day at midnight.
|
||||
|
||||
You can see some generated examples in the [examples](examples) folder.
|
||||
|
||||
## Usage
|
||||
|
||||
In [generate_set_banner.py](generate_set_banner.py):
|
||||
1. Set the OAuth token used to access the Pleroma API with privileges to edit your account. I used [this site](https://tinysubversions.com/notes/mastodon-bot/).
|
||||
2. Set the base url of the Pleroma instance.
|
||||
```py
|
||||
OAUTH_TOKEN = 'OAUTH_TOKEN'
|
||||
base_url = 'https://example.com'
|
||||
```
|
||||
|
||||
Run
|
||||
```
|
||||
python3 generate_set_banner.py
|
||||
```
|
||||
|
||||
This will generate a banner using a randomly picked color palette from a list in the code and set it as the banner on your fedi account.
|
BIN
examples/palette_0.png
Executable file
BIN
examples/palette_0.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
BIN
examples/palette_1.png
Executable file
BIN
examples/palette_1.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
BIN
examples/palette_2.png
Executable file
BIN
examples/palette_2.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
BIN
examples/palette_3.png
Executable file
BIN
examples/palette_3.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
BIN
examples/palette_4.png
Executable file
BIN
examples/palette_4.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
BIN
examples/palette_5.png
Executable file
BIN
examples/palette_5.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
63
generate_set_banner.py
Executable file
63
generate_set_banner.py
Executable file
|
@ -0,0 +1,63 @@
|
|||
import requests
|
||||
import tenprint_gradient
|
||||
from io import BytesIO
|
||||
|
||||
OAUTH_TOKEN = 'OAUTH_TOKEN' # OAuth token to access your account through the Pleroma API
|
||||
|
||||
base_url = 'https://example.com' # The base URL of the Pleroma instance
|
||||
|
||||
# The list of color palettes. It contains tuples, where the first two elements
|
||||
# of each tuple are the colors for the background gradient and the last two are
|
||||
# the foreground (slashes) gradient colors.
|
||||
# I put them in separate lists grouped by the 4 colors they use so that there is an equal
|
||||
# probability of getting each 4-color scheme. And only then the color tuple is picked,
|
||||
# determining the orientations of the gradients.
|
||||
palettes = [
|
||||
[
|
||||
(0xef5d60,0xec4067,0xa01a7d,0x311847),
|
||||
],
|
||||
[
|
||||
(0x0a1128,0x001f54,0x034078,0x1282a2),
|
||||
],
|
||||
[
|
||||
(0x212d40,0x11151c,0xb9314f,0xedddd4),
|
||||
],
|
||||
[
|
||||
(0x191d32,0x282f44,0x453a49,0x6d3b47),
|
||||
],
|
||||
[
|
||||
(0x0b3c49,0x731963,0xfffdfd,0xcbd2d0),
|
||||
(0x0b3c49,0x731963,0xcbd2d0,0xfffdfd),
|
||||
(0x731963,0x0b3c49,0xcbd2d0,0xfffdfd),
|
||||
(0x731963,0x0b3c49,0xfffdfd,0xcbd2d0)
|
||||
],
|
||||
[
|
||||
(0xfffdfd,0xcbd2d0,0x0b3c49,0x731963),
|
||||
(0xcbd2d0,0xfffdfd,0x0b3c49,0x731963),
|
||||
(0xcbd2d0,0xfffdfd,0x731963,0x0b3c49),
|
||||
(0xfffdfd,0xcbd2d0,0x731963,0x0b3c49)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
print('Picking palette')
|
||||
palette_index, palette_orientation, palette = tenprint_gradient.get_random_palette(palettes)
|
||||
print(f'Using palette {palette_index}/{palette_orientation} - {palette}')
|
||||
|
||||
print('Generating banner')
|
||||
# This will generate a banner 31 cells wide, 11 cells tall, with each cell being 100 by 100 pixels, and with 0 margin
|
||||
banner_image = tenprint_gradient.generate_gradiented_10print(31, 11, 100, 0, palette)
|
||||
|
||||
print('Getting banner bytes')
|
||||
banner_bytes = None
|
||||
with BytesIO() as output:
|
||||
banner_image.save(output, 'PNG')
|
||||
banner_bytes = output.getvalue()
|
||||
|
||||
print(f'Requesting banner update at {base_url}')
|
||||
response = requests.patch(f'{base_url}/api/v1/accounts/update_credentials', files={
|
||||
'header': banner_bytes
|
||||
}, headers={'Authorization': f'Bearer {OAUTH_TOKEN}'})
|
||||
|
||||
print('Response')
|
||||
print(response.text)
|
35
tenprint.py
Executable file
35
tenprint.py
Executable file
|
@ -0,0 +1,35 @@
|
|||
from PIL import Image, ImageDraw
|
||||
import random
|
||||
|
||||
bgcolor = (255,255,255)
|
||||
fgcolor = (0,0,0)
|
||||
|
||||
def draw_slash(d, x, y, cellsize, flip, thickness=0.16):
|
||||
if flip:
|
||||
slash = [
|
||||
(x+cellsize*(1-thickness), y),
|
||||
(x+cellsize, y),
|
||||
(x+cellsize, y+cellsize*thickness),
|
||||
(x+cellsize*thickness, y+cellsize),
|
||||
(x, y+cellsize),
|
||||
(x, y+cellsize*(1-thickness))
|
||||
]
|
||||
else:
|
||||
slash = [
|
||||
(x, y),
|
||||
(x+cellsize*thickness, y),
|
||||
(x+cellsize, y+cellsize*(1-thickness)),
|
||||
(x+cellsize, y+cellsize),
|
||||
(x+cellsize*(1-thickness), y+cellsize),
|
||||
(x, y+cellsize*thickness)
|
||||
]
|
||||
d.polygon(slash, fill=fgcolor)
|
||||
|
||||
def make_image(width, height, cellsize_px, margin=0):
|
||||
image = Image.new("RGB", (int(cellsize_px*margin + width*(cellsize_px*(1+margin))), int(cellsize_px*margin + height*(cellsize_px*(1+margin)))), bgcolor)
|
||||
draw = ImageDraw.Draw(image)
|
||||
for x in range(width):
|
||||
for y in range(height):
|
||||
draw_slash(draw, cellsize_px*margin + x*(cellsize_px+margin*cellsize_px), cellsize_px*margin + y*(cellsize_px+margin*cellsize_px), cellsize_px, random.random() > 0.5)
|
||||
return image
|
||||
|
45
tenprint_gradient.py
Executable file
45
tenprint_gradient.py
Executable file
|
@ -0,0 +1,45 @@
|
|||
import tenprint
|
||||
import random
|
||||
|
||||
def get_rgb_from_int(color):
|
||||
r = (color>>16) & 255
|
||||
g = (color>>8) & 255
|
||||
b = color & 255
|
||||
return (r,g,b)
|
||||
|
||||
def get_gradient(color1, color2, between):
|
||||
new_color = []
|
||||
for p1, p2 in zip(color1, color2):
|
||||
new_color.append(int(p1*between + p2*(1-between)))
|
||||
return tuple(new_color)
|
||||
|
||||
def get_palette_rgb_from_palette_int(palette_raw):
|
||||
return [
|
||||
get_rgb_from_int(c) for c in
|
||||
palette_raw
|
||||
]
|
||||
|
||||
|
||||
def generate_gradiented_10print(width, height, cellsize, margin, palette):
|
||||
image = tenprint.make_image(width, height, cellsize, margin)
|
||||
pixels = image.load()
|
||||
|
||||
width_px = image.size[0]
|
||||
height_px = image.size[1]
|
||||
|
||||
bg_gradient = palette[0:2]
|
||||
fg_gradient = palette[2:4]
|
||||
|
||||
for x in range(width_px):
|
||||
for y in range(height_px):
|
||||
if pixels[x,y] == tenprint.bgcolor:
|
||||
pixels[x,y] = get_gradient(bg_gradient[0], bg_gradient[1], y/height_px)
|
||||
if pixels[x,y] == tenprint.fgcolor:
|
||||
pixels[x,y] = get_gradient(fg_gradient[0], fg_gradient[1], y/height_px)
|
||||
|
||||
return image
|
||||
|
||||
def get_random_palette(palettes):
|
||||
palette_index, palette_rotations = random.choice(tuple(enumerate(palettes)))
|
||||
palette_rotation, palette = random.choice(tuple(enumerate(palette_rotations)))
|
||||
return palette_index, palette_rotation, get_palette_rgb_from_palette_int(palette)
|
Loading…
Reference in a new issue