forked from thisismypassport/shrinko8
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sdl2_utils.py
135 lines (106 loc) · 3.13 KB
/
sdl2_utils.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from utils import *
# dummy file, without sdl2 dependency
class BlendMode(Enum):
none = blend = ...
class Color(Tuple):
r = g = b = ...; a = 0xff
def set_a(m, a):
return Color(m.r, m.g, m.b, a)
class PixelFormat(Enum):
rgba8 = "RGBA"
bgra8 = ("RGBA", "BGRA")
rgb8 = "RGB"
i8 = "P"
@property
def _pil_fmt(m):
return m.value[0] if isinstance(m.value, tuple) else m.value
@property
def _pil_raw_fmt(m):
return m.value[1] if isinstance(m.value, tuple) else m.value
@property
def bpp(m):
if m == m.i8:
return 8
else:
return 32
def _to_pil_tuple(obj):
if obj is None:
return None
elif len(obj) == 2:
return tuple(obj)
elif len(obj) == 4:
x, y, w, h = obj
return x, y, x + w, y + h
else:
fail(obj)
def _pil_module():
try:
from PIL import Image # type: ignore
except:
throw("ERROR: You need pillow (or PIL) to read/write PNGs (do 'python -m pip install pillow')")
return Image
class Surface:
@staticmethod
def load(f):
return Surface(_pil_module().open(f))
@staticmethod
def create(w, h, fmt=PixelFormat.rgba8):
return Surface(_pil_module().new(fmt._pil_fmt, (w, h)), fmt)
@staticmethod
def from_data(w, h, fmt, data, pitch=None):
return Surface(_pil_module().frombytes(fmt._pil_fmt, (w, h), data, "raw", fmt._pil_raw_fmt, pitch or 0), fmt)
def __init__(m, pil, fmt=None):
m.pil = pil
m.fmt = fmt
def to_data(m, fmt=None, flip=False):
if fmt is None:
fmt = m.format
return m.pil.tobytes("raw", fmt._pil_raw_fmt, 0, -1 if flip else 1)
def save(m, dest=None):
if dest is None:
dest = BytesIO()
m.save(dest)
return dest.getvalue()
m.pil.save(dest, "png")
def convert(m, fmt):
return Surface(m.pil.convert(fmt._pil_fmt))
@property
def width(m):
return m.pil.width
@property
def height(m):
return m.pil.height
@property
def size(m):
return Point(m.width, m.height)
@property
def format(m):
if m.fmt is None:
m.fmt = PixelFormat(m.pil.mode)
return m.fmt
@property
def pixels(m):
return SurfacePixels(m.pil.load())
def draw(m, src, dest=None, srcpos=None):
src = src.pil.crop(_to_pil_tuple(srcpos)) if e(srcpos) else src
m.pil.alpha_composite(src, _to_pil_tuple(dest))
@writeonly_property
def palette(m, pal):
m.pil.putpalette(pal.raw, "RGBA")
class SurfacePixels:
def __init__(m, pa):
m.pa = pa
def __getitem__(m, pos):
return m.pa[pos]
def __setitem__(m, pos, color):
m.pa[pos] = color
class Palette: # (pil's ImagePalette doesn't seem fit for purpose)
@staticmethod
def create(n):
return Palette([0] * (4 * n))
def __init__(m, raw):
m.raw = raw
def __getitem__(m, i):
return m.raw[4 * i : 4 * (i + 1)]
def __setitem__(m, i, v):
m.raw[4 * i : 4 * (i + 1)] = v