Py.Cafe

jonathanperret/

dbj-color-sorter

Test DBJ color ordering constraints

DocsPricing
  • 860.png
  • app.py
  • cassiopee.png
  • fractale-1.png
  • popcorn-cga.png
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from __future__ import annotations
import streamlit as st
import argparse
import math
from PIL import Image
from io import BytesIO
from permutation import Permutation
from pathlib import Path
import base64

def colorsort(image, permutation):
  result = image.copy()
  pixels = result.load()
  swapcount = 0
  for y in range(0, result.height-1, 2):
    for x in range(result.width):
      a, b = pixels[x, y], pixels[x, y+1]
      if permutation(a+1) < permutation(b+1):
        swapcount += 1
        pixels[x, y], pixels[x, y+1] = b, a

  return result, swapcount

def process(img):
  imagecolors = img.getcolors()
  colorcount = len(imagecolors)
  permutations = math.factorial(colorcount)
  permutation_index = st.slider(f"Image has {len(imagecolors)} colors ({permutations} permutations). Pick color order:", min_value = 0, max_value = permutations - 1)
  selected_permutation = Permutation.from_lehmer(permutation_index, colorcount)

  colorsorted, swapcount = colorsort(img, selected_permutation)
  col1, col2 = st.columns(2)
  col1.markdown(f"Selected color order: {selected_permutation.to_image(colorcount)}")
  col1.image(img, use_container_width=True)
  col2.markdown(f"Wrong pixels: {swapcount*2} ({int(swapcount*2*100/img.width/img.height)}%)")
  col2.image(colorsorted, use_container_width=True)

print("\x1b[1;92mStreamlit script running...\x1b[0m")
st.title("DBJ color sorter")
st.markdown("""An experiment to see how an image would be transformed if knit in DBJ with the minimal number of passes
""")
col1, col2 = st.columns(2)
col2.markdown("Or pick an example:")

def tob64(filename):
  return base64.b64encode(Path(filename).read_bytes()).decode()

if 'selected_example' not in st.session_state:
    st.session_state.selected_example = -1

examples = ["fractale-1.png", "popcorn-cga.png", "cassiopee.png", "860.png"]

examples_row = col2.columns(len(examples))
for i, ex in enumerate(examples):
  if col2.button(f"![](data:image/png;base64,{tob64(ex)}) {ex}", key=f"example{i}"):
    st.session_state.selected_example = i

uploaded_file = col1.file_uploader("Upload an image (PNG)", key=f"uploader_${st.session_state.selected_example}")

if uploaded_file is not None:
    st.session_state.selected_example = -1
    bytes_data = uploaded_file.getvalue()
    img = Image.open(BytesIO(bytes_data)).convert("RGBA").convert("P")
    if img.width > 1000 or img.height > 1000:
        st.markdown(f"## Image is too big! ({img.width}x{img.height})")
    elif len(img.getcolors()) > 16:
        st.markdown(f"## Image has too many colors! ({len(img.getcolors())})")
    else:
        process(img)
elif st.session_state.selected_example >= 0:
  img = Image.open(examples[st.session_state.selected_example]).convert("RGBA").convert("P")
  process(img)

        

st.markdown(
    """
<style>
    img {
        border: 1px solid black;
        image-rendering: pixelated;
    }
</style>
""",
    unsafe_allow_html=True,
)