logo_gen_py3/logo_gen_decoder.py

125 lines
4.2 KiB
Python

'''
An utility to decode the splash.img for Snapdragon devices, encoded using logo_gen.py, available at the CAF here:
https://source.codeaurora.org/quic/la/device/qcom/common/tree/display/logo?h=LA.BR.1.2.7_rb1.1
Created by Gokul NC @ XDA-Developers
Contact me @ http://about.me/GokulNC
'''
import os
import sys
from PIL import Image
HEADER_TEXT = "SPLASH!!"
BLOCK_SIZE = 512
def decodeRLE24(encoded_img, resolution, payload_dims=None):
rgb_img = Image.new("RGB", resolution, (0, 0, 0))
rows, columns = resolution
# print("Resolution "+str(resolution))
pixelsNew = rgb_img.load()
i = j = 0
'''
How decoding works:
The run-length encoding is column-wise, and is of format: list of (count, RGB_pixels)
If count>127, it means all values in it are repeated, so fill all (255-count)+1 no. of pixels with same BGR value.
Else, values are different. Fill (count)+1 no. of pixels with subsequent BGR values.
'''
byte = encoded_img.read(1)
while byte:
pixel_count = byte[0] + 1
if pixel_count > 128:
b = (encoded_img.read(1)[0])
g = (encoded_img.read(1)[0])
r = (encoded_img.read(1)[0])
color = (r, g, b)
for _ in range(pixel_count - 128):
pixelsNew[i, j] = color
i = (i + 1) % rows
if i == 0: j += 1
else:
for _ in range(pixel_count):
b = (encoded_img.read(1)[0])
g = (encoded_img.read(1)[0])
r = (encoded_img.read(1)[0])
pixelsNew[i, j] = (r, g, b)
i = (i + 1) % rows
if i == 0: j += 1
if j == columns and i == 0:
# print("Decoded successfully at %d"%encoded_img.tell())
break
byte = encoded_img.read(1)
if payload_dims is not None and type(payload_dims) is tuple and len(payload_dims) == 2:
encoded_img.seek(payload_dims[0] + payload_dims[1] - encoded_img.tell(), 1)
# print("Stopped processing the file at %d"%encoded_img.tell())
return rgb_img
def int_to_rgb24(val):
r = (val >> 16) & 0xFF
g = (val >> 8) & 0xFF
b = val & 0xFF
return r, g, b
def read_int32(bytes):
assert len(bytes) == 4, "Incorrect no. of bytes passed for read_int32(). Pass an array of 4 bytes only."
# Parse from little endian to integer
value = bytes[3]
for i in range(2, -1, -1):
value = (value << 8) | bytes[i]
return value
def process_splashimg(input_file, output_file):
f = open(input_file, "rb")
f.seek(1024) # add by affggh for skip empty bytes
i = 1
while True:
# Read HEADER_TEXT chunk. Ref: https://stackoverflow.com/a/1035419/5002496
hdr_txt = f.read(len(HEADER_TEXT))
# Check if they match. Ref: https://stackoverflow.com/a/606199/5002496
if HEADER_TEXT != hdr_txt.decode("utf-8"):
if i == 1: print("This file is not supported.")
return
width = read_int32(f.read(4))
height = read_int32(f.read(4))
is_encoded = read_int32(f.read(4))
assert is_encoded == 1, "The file is already not encoded"
payload_size = read_int32(f.read(4)) * BLOCK_SIZE
# Skip the remaining bytes in header
f.seek(BLOCK_SIZE - (f.tell() % BLOCK_SIZE), 1)
# print("Decoding from %d" % f.tell())
decoded_img = decodeRLE24(f, (width, height), (f.tell(), payload_size))
# Save the file now
pos = output_file.rfind('.')
if pos == -1:
filename = output_file + str(i)
else:
filename = output_file[0:pos] + str(i) + output_file[pos:]
print("Saving decoded image %d to %s" % (i, filename))
decoded_img.save(filename)
i += 1
# Skip zeros if present at end
byte = f.read(1)
while byte and (byte[0]) == 0: byte = f.read(1)
f.seek(-1, 1)
f.close()
def main():
assert len(sys.argv) >= 3, "Usage: python %s input_file output_file" % sys.argv[0]
assert os.path.exists(sys.argv[1]), "Unable to access the file %s" % sys.argv[1]
process_splashimg(sys.argv[1], sys.argv[2])
main()