60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
|
#!/usr/bin/python3
|
||
|
import sys
|
||
|
import struct
|
||
|
import PIL.Image
|
||
|
_, inpath, outpath = sys.argv
|
||
|
|
||
|
image = PIL.Image.open(inpath)
|
||
|
assert image.mode == "RGBA", "image mode is "+image.mode
|
||
|
|
||
|
# We measure width and height prior to the rotation
|
||
|
width, height = image.width, image.height
|
||
|
|
||
|
image = image.transpose(PIL.Image.Transpose.ROTATE_270)
|
||
|
|
||
|
with open(outpath, "wb") as out:
|
||
|
out.write(struct.pack("=HH", width, height))
|
||
|
for channel in "BGRA":
|
||
|
pixelbytes = image.getchannel(channel).tobytes()
|
||
|
def rlegroups():
|
||
|
curpixel=None
|
||
|
count=0
|
||
|
litrun = b""
|
||
|
for pixel in pixelbytes:
|
||
|
if curpixel is None:
|
||
|
curpixel = pixel
|
||
|
count = 1
|
||
|
elif curpixel != pixel:
|
||
|
assert count > 0
|
||
|
if count <= 2:
|
||
|
if len(litrun)+count > 127:
|
||
|
assert len(litrun) > 0
|
||
|
yield litrun
|
||
|
litrun = b""
|
||
|
litrun += bytes([curpixel]) * count
|
||
|
else:
|
||
|
if litrun != b"":
|
||
|
assert len(litrun) > 0
|
||
|
yield litrun
|
||
|
litrun = b""
|
||
|
yield (curpixel, count)
|
||
|
curpixel = pixel
|
||
|
count = 1
|
||
|
else:
|
||
|
count += 1
|
||
|
if litrun != b"":
|
||
|
assert len(litrun) > 0
|
||
|
yield litrun
|
||
|
if count > 0:
|
||
|
yield (curpixel, count)
|
||
|
for group in rlegroups():
|
||
|
if type(group) == bytes:
|
||
|
out.write(struct.pack("=B", len(group)+128) + group)
|
||
|
else:
|
||
|
pixel, count = group
|
||
|
assert count > 0
|
||
|
if count >= 128:
|
||
|
out.write(struct.pack("=BIB", 0, count, pixel))
|
||
|
else:
|
||
|
out.write(struct.pack("=BB", count, pixel))
|