Files
pif-control-py/script.py
2025-11-22 12:31:58 +00:00

253 lines
8.8 KiB
Python

# TENTO SKRIPT NENÍ URČEN PRO ŘEŠENÍ, SLOUŽÍ POUZE JAKO KONTROLA
# AUTOR SKRIPTU NERUČÍ ZA POUŽITÍ SKRIPTU ČI NESPRÁVNOST JEHO VÝSTUPU
import os
from PIL import Image # PACKAGE 'pillow' REQUIRED
color_map_types = {
"00": "soubor s obrázkem neobsahuje mapu barev",
"01": "je přítomna mapa barev"
}
image_types = {
"00": "nejsou přítomna žádná obrazová data",
"01": "nekomprimovaný obraz s barevným mapováním",
"02": "nekomprimovaný obraz v True Color",
"03": "nekomprimovaný černobílý obraz (ve stupních šedi)"
}
start_pixel_locations = {
"00": "Dole vlevo",
"01": "Nahoře vlevo",
"10": "Dole vpravo",
"11": "Nahoře vpravo"
}
class Header:
COLOR_MAP_TYPE = 0
IMAGE_TYPE = 1
MAP_START_INDEX = (2, 3+1)
MAP_SIZE = (4, 5+1)
MAP_OTHER = 6
WIDTH = (7, 8+1)
HEIGHT = (9, 10+1)
BITS_PER_PIXEL = 11
DESCRIPTOR = 12
ALPHA_DEPTH = (0, 3+1)
START_PIXEL_LOCATION = (4, 5+1)
DATA_OFFSET = 13
def raw2hex(input_raw: str) -> str:
if len(input_raw) % 2 != 0:
raise ValueError("Raw bajty nejsou v sudém počtu: " + input_raw)
byte_list = [input_raw[j:j + 2] for j in range(0, len(input_raw), 2)]
output_hex = ''.join(reversed(byte_list))
return output_hex
def hex2dec(input_hex: str) -> str:
return str(int(input_hex, 16))
def hex2bin(input_hex: str) -> list[str]:
value = int(input_hex, 16)
bin_str = format(value, f'0{len(input_hex) * 4}b')
bin_arr = [str(bit) for bit in bin_str]
bin_arr.reverse()
return bin_arr
def bin2dec(input_bin: str) -> str:
dec = int(input_bin.strip(), 2)
return str(dec)
def hex2ascii(input_hex: str) -> str:
return bytes.fromhex(input_hex).decode("ascii")
def hex2date(input_hex: str) -> str:
def read_field(start: int) -> int:
field_hex = input_hex[start:start + 4]
return int.from_bytes(bytes.fromhex(field_hex), byteorder="little")
month = read_field(0)
day = read_field(4)
year = read_field(8)
hour = read_field(12)
minute = read_field(16)
second = read_field(20)
return f"{day:02d}. {month:02d}. {year}, {hour:02d}:{minute:02d}:{second:02d}"
def hex2ansi(input_hex: str) -> str:
if len(input_hex) != 6:
raise ValueError("Barvy raw bajtů nejsou ve skupinách 3 bajtů: " + input_hex)
r = int(input_hex[0:2], 16)
g = int(input_hex[2:4], 16)
b = int(input_hex[4:6], 16)
return f"\033[38;2;{r};{g};{b}m"
def get_color_map_type(input_hex: str) -> str:
return color_map_types.get(input_hex, "vyhrazeno pro jiné účely")
def get_image_type(input_hex: str) -> str:
return image_types.get(input_hex, "vyhrazeno pro jiné účely")
def get_start_pixel_location(input_bin: str) -> str:
return start_pixel_locations.get(input_bin, "Neznámá lokace prvního pixel")
def write_png(output_path, width, height, input_bytes, data_offset):
pixel_data = []
for i in range(width * height):
base = data_offset + i * 3
b = int(input_bytes[base + 0], 16)
g = int(input_bytes[base + 1], 16)
r = int(input_bytes[base + 2], 16)
pixel_data.extend([r, g, b])
pixel_bytes = bytes(pixel_data)
img = Image.frombytes("RGB", (width, height), pixel_bytes)
img.save(output_path)
print("Obrázek uložen do: " + output_path)
choice = input("1: Zadat raw bajty (Doporuečno)\n2: Zadat název souboru s raw bajty\n3: Zadat název souboru .pif (papulastic-image-format)\n")
input_bytes = []
data = ""
if choice == 1:
user_input = input("Zadjete raw bajty: ")
data = user_input.replace(" ", "")
elif choice == 2:
user_input = input("Cesta k souboru s raw batjy: ")
input_path = os.path.expanduser(user_input)
with open(input_path, "r") as f:
data = f.read().strip().replace(" ", "")
else:
user_input = input("Cesta k souboru .pif: ")
input_path = os.path.expanduser(user_input)
with open(input_path, "rb") as f:
raw_bytes = f.read().strip()
input_bytes = [f"{b:02x}" for b in raw_bytes]
if choice == 1 or choice == 2:
for i in range(0, len(data), 2):
input_bytes.append(data[i:i + 2])
if len(input_bytes) > 0:
# COLOR MAP TYPE
color_map_type = input_bytes[Header.COLOR_MAP_TYPE]
print("Typ barevné mapy: " + get_color_map_type(raw2hex(color_map_type)) + " (0x" + raw2hex(color_map_type) + ")")
# IMAGE TYPE
image_type = input_bytes[Header.IMAGE_TYPE]
print("Komprese a typ obrázku: " + get_image_type(raw2hex(image_type)) + " (0x" + raw2hex(image_type) + ")\n")
# COLOR MAP SPECS
print("specifikace barevné palety: (Pokud je pole Color map type nastaveno na nulu (žádná mapa barev neexistuje), pak by těchto 5 bajtů mělo být nastaveno na nulu.)")
if color_map_type == "00":
print("Žádná mapa neexistuje, bajty by měly být nula")
else:
print("Mapa existuje")
# MAP START INDEX
start, end = Header.MAP_START_INDEX
map_start_index = "".join(input_bytes[start:end])
print("\tIndex první položky barevné mapy: " + hex2dec(raw2hex(map_start_index)) + " (0x" + raw2hex(map_start_index) + ")")
# MAP SIZE
start, end = Header.MAP_SIZE
map_size = "".join(input_bytes[start:end])
print("\tDélka barevné mapy: " + hex2dec(raw2hex(map_size)) + " (0x" + raw2hex(map_size) + ")")
# MAP OTHER
map_other = input_bytes[Header.MAP_OTHER]
print("\tDoplňkové údaje k barevné mapě: Není definováno (0x" + raw2hex(map_other) + ")\n")
# IMAGE SPECS
print("Specifikace rozměrů obrázku:")
# WIDTH
start, end = Header.WIDTH
width = "".join(input_bytes[start:end])
print("\tŠířka obrázku v pixelech: " + hex2dec(raw2hex(width)) + "px (0x" + raw2hex(width) + ")")
# HEIGHT
start, end = Header.HEIGHT
height = "".join(input_bytes[start:end])
print("\tVýška obrázku v pixelech: " + hex2dec(raw2hex(height)) + "px (0x" + raw2hex(height) + ")")
size = int(hex2dec(raw2hex(width))) * int(hex2dec(raw2hex(height)))
# BITS/PIXEL
bits_per_pixel = input_bytes[Header.BITS_PER_PIXEL]
print("\tHloubka pixelu (bity na pixel): " + hex2dec(raw2hex(bits_per_pixel)) + " bitů na pixel (0x" + raw2hex(bits_per_pixel) + ")")
# DESCRIPTOR
descriptor_bits = hex2bin(raw2hex(input_bytes[Header.DESCRIPTOR]))
print("\tDeskriptor obrazu: (0b" + "".join(descriptor_bits) + ")")
# ALPHA DEPTH
start, end = Header.ALPHA_DEPTH
alpha_depth = "".join(descriptor_bits[start:end])
print("\t\tHloubka alfa kanálu: " + bin2dec(alpha_depth) + " (0b" + alpha_depth + ")")
# START PIXEL LOCATION
start, end = Header.START_PIXEL_LOCATION
start_pixel_location = "".join(descriptor_bits[start:end])
print("\t\tPočátek obrazu (kde leží první pixel): " + get_start_pixel_location(start_pixel_location) + " (0b" + start_pixel_location + ")")
# UNUSED
print("\t\tBity 6 a 7 nejsou definovány")
# DATA
choice = input("1: Vypsat data do konzole (Doporučeno pouze pro malé obrázky)\n2: Uložit obrázek do PNG souboru\n")
if choice == 1:
print("Data:")
data = ""
for i in range(0, int(hex2dec(raw2hex(height)))):
for j in range(0, int(hex2dec(raw2hex(width)))):
byte_list = input_bytes[Header.DATA_OFFSET + (i * width + j) * 3 : Header.DATA_OFFSET + (i * width + j) * 3 + 3]
data += hex2ansi(raw2hex("".join(byte_list)))
data += "#" + raw2hex("".join(byte_list)) + " \033[0m"
data += "\n"
print(data)
else:
user_input = input("Zadejte cestu pro výsledný soubor PNG obrázku: ")
output_path = os.path.expanduser(user_input)
write_png(output_path, int(hex2dec(raw2hex(width))), int(hex2dec(raw2hex(height))), input_bytes, Header.DATA_OFFSET)
offset = Header.DATA_OFFSET + size * 3
# OTHER DATA
print("Rozšiřující data:")
# INITIALS
start, end = (offset, offset + 2)
print("\tIniciály autora: " + hex2ascii("".join(input_bytes[start:end])) + " (0x" + "".join(input_bytes[start:end]) + ")")
# DATE
start, end = (offset + 3, offset + 15)
date = input_bytes[start:end]
print("\t\033[31mDatum (čas pořízení): " + hex2date("".join(input_bytes[start:end])) + " (0b" + "".join(date) + ")\033[0m\n")
# FOOTER
print("Patička:")
# SIGNATURE
start, end = (offset + 15, offset + 31)
signature = input_bytes[start:end]
print("\t\033[31mPodpis: " + hex2ascii("".join(signature)) + " (0x" + "".join(signature) + ")\033[0m")
# ALWAYS DOT
always_dot = input_bytes[end]
print("\tRezervovaný znak: " + hex2ascii(always_dot) + " (0x" + always_dot + ")")
always_zero = input_bytes[end + 1]
print("\tBinární nula: 0x" + always_zero)
print("\n\nDůležité informace zaznačeny barevně")