Skip to content

Instantly share code, notes, and snippets.

@ranguli
Created April 13, 2020 23:32
Show Gist options
  • Save ranguli/5885b4bdecf78cc6d7db39826d339826 to your computer and use it in GitHub Desktop.
Save ranguli/5885b4bdecf78cc6d7db39826d339826 to your computer and use it in GitHub Desktop.
import os
from PIL import Image
def generate_palette_table(palette_file):
"""
The palette.lmp is a binary file with denoting the RGB codes of the 256-color
palette used by the Quake engine. It contains no header data. Each byte is one
component of an RGB value.
https://quakewiki.org/wiki/Quake_palette#palette.lmp
Think of the palette as a dictionary or lookup table. Values from 0-255 each
contain an RGB code. Images in the .lmp format do not contain RGB information,
instead for each pixel in the image there is a number from 0-255 that corresponds to
a value in the color palette.
"""
data = []
with open(palette_file, "rb") as f:
for i in range(os.path.getsize(palette_file)):
data.append(int.from_bytes(f.read(1), byteorder='big'))
data = [data[x:x+3] for x in range(0, len(data), 3)]
palette_table = {k:v for k, v in enumerate(data)}
return palette_table
def main(lmp_file, palette_file):
# .lmp files in Quake are of a different structure than those from DOOM.
# They can be one of three types, an image, a palette, or a colormap.
lmp_data = []
with open(lmp_file, "rb") as f:
size = os.path.getsize(lmp_file)
for i in range(size):
byte = int.from_bytes(f.read(1), byteorder='big')
lmp_data.append(byte)
"""
The first 8 bytes comprise the files header data, 4 bytes for the
width of the image and 4 bytes for its height.
TODO: Currently only reading the first byte (of potentially up to 4)
for the width and height values. We need to fix this as it literally
only works for images <= 255x255 in resolution.
"""
header = lmp_data[:8]
width = header[0]
height = header[4]
"""
TODO: Confirm the .lmp is valid by checking that given a width and height from the
header data, (width * height) equals the size of the rest of the file after
the header.
"""
lmp_data = lmp_data[8:]
palette_table = generate_palette_table(palette_file)
# TODO: If this does not divide evenly, the .lmp is bad
#rgb_values = group(data, len(data) // 3)
image_data = []
for table_id in lmp_data:
image_data.extend(palette_table.get(table_id))
image_data = bytes(image_data)
img = Image.frombytes('RGB', (width, height), image_data)
img.show()
img.save(f"{lmp_file}.png")
main("ranking.lmp", "palette.lmp")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment