Add files via upload
commit
ee6c160663
|
@ -0,0 +1,297 @@
|
|||
# Copyright (c) 2013,2015, The Linux Foundation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of The Linux Foundation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# ===========================================================================
|
||||
|
||||
# This script read the logo png and creates the logo.img
|
||||
|
||||
# when who what, where, why
|
||||
# -------- --- -------------------------------------------------------
|
||||
# 2013-04 QRD init
|
||||
# 2015-04 QRD support the RLE24 compression
|
||||
|
||||
# Environment requirement:
|
||||
# Python + PIL
|
||||
# PIL install:
|
||||
# (ubuntu) sudo apt-get install python-imaging
|
||||
# (windows) (http://www.pythonware.com/products/pil/)
|
||||
|
||||
# limit:
|
||||
# a This script only support Python 2.7.x, 2.6.x,
|
||||
# Can't use in py3x for StringIO module
|
||||
# b This script's input can be a png, jpeg, bmp, gif file.
|
||||
# But if it is a gif, only get the first frame by default.
|
||||
#
|
||||
# description:
|
||||
# struct logo_header {
|
||||
# unsigned char[8]; // "SPLASH!!"
|
||||
# unsigned width; // logo's width, little endian
|
||||
# unsigned height; // logo's height, little endian
|
||||
# unsigned type; // 0, Raw Image; 1, RLE24 Compressed Image
|
||||
# unsigned blocks; // block number, real size / 512
|
||||
# ......
|
||||
# };
|
||||
|
||||
# the logo Image layout:
|
||||
# logo_header + Payload data
|
||||
|
||||
# ===========================================================================*/
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
from PIL import Image
|
||||
|
||||
SUPPORT_RLE24_COMPRESSIONT = 1
|
||||
bodyLength = 0
|
||||
payloadLimit = 0 # 0 means no limit
|
||||
|
||||
|
||||
## get header
|
||||
def GetImgHeader(size, compressed=0, real_bytes=0):
|
||||
SECTOR_SIZE_IN_BYTES = 512 # Header size
|
||||
header = [0 for i in range(SECTOR_SIZE_IN_BYTES)]
|
||||
|
||||
width, height = size
|
||||
|
||||
if SUPPORT_RLE24_COMPRESSIONT == 1:
|
||||
real_size = (bodyLength + 511) / 512
|
||||
else:
|
||||
real_size = (real_bytes + 511) / 512
|
||||
|
||||
# magic
|
||||
header[:8] = [ord('S'), ord('P'), ord('L'), ord('A'),
|
||||
ord('S'), ord('H'), ord('!'), ord('!')]
|
||||
|
||||
# width
|
||||
header[8] = (width & 0xFF)
|
||||
header[9] = ((width >> 8) & 0xFF)
|
||||
header[10] = ((width >> 16) & 0xFF)
|
||||
header[11] = ((width >> 24) & 0xFF)
|
||||
|
||||
# height
|
||||
header[12] = (height & 0xFF)
|
||||
header[13] = ((height >> 8) & 0xFF)
|
||||
header[14] = ((height >> 16) & 0xFF)
|
||||
header[15] = ((height >> 24) & 0xFF)
|
||||
|
||||
# type
|
||||
header[16] = (compressed & 0xFF)
|
||||
# header[17]= 0
|
||||
# header[18]= 0
|
||||
# header[19]= 0
|
||||
|
||||
# block number
|
||||
header[20] = (int(real_size) & 0xFF)
|
||||
header[21] = ((int(real_size) >> 8) & 0xFF)
|
||||
header[22] = ((int(real_size) >> 16) & 0xFF)
|
||||
header[23] = ((int(real_size) >> 24) & 0xFF)
|
||||
|
||||
output = StringIO()
|
||||
for i in header:
|
||||
output.write(struct.pack("B", i))
|
||||
content = output.getvalue()
|
||||
output.close()
|
||||
return content
|
||||
|
||||
|
||||
def encode(line):
|
||||
count = 0
|
||||
lst = []
|
||||
repeat = -1
|
||||
run = []
|
||||
total = len(line) - 1
|
||||
for index, current in enumerate(line[:-1]):
|
||||
if current != line[index + 1]:
|
||||
run.append(current)
|
||||
count += 1
|
||||
if repeat == 1:
|
||||
entry = (count + 128, run)
|
||||
lst.append(entry)
|
||||
count = 0
|
||||
run = []
|
||||
repeat = -1
|
||||
if index == total - 1:
|
||||
run = [line[index + 1]]
|
||||
entry = (1, run)
|
||||
lst.append(entry)
|
||||
else:
|
||||
repeat = 0
|
||||
|
||||
if count == 128:
|
||||
entry = (128, run)
|
||||
lst.append(entry)
|
||||
count = 0
|
||||
run = []
|
||||
repeat = -1
|
||||
if index == total - 1:
|
||||
run.append(line[index + 1])
|
||||
entry = (count + 1, run)
|
||||
lst.append(entry)
|
||||
else:
|
||||
if repeat == 0:
|
||||
entry = (count, run)
|
||||
lst.append(entry)
|
||||
count = 0
|
||||
run = []
|
||||
repeat = -1
|
||||
if index == total - 1:
|
||||
run.append(line[index + 1])
|
||||
run.append(line[index + 1])
|
||||
entry = (2 + 128, run)
|
||||
lst.append(entry)
|
||||
break
|
||||
run.append(current)
|
||||
repeat = 1
|
||||
count += 1
|
||||
if count == 128:
|
||||
entry = (256, run)
|
||||
lst.append(entry)
|
||||
count = 0
|
||||
run = []
|
||||
repeat = -1
|
||||
if index == total - 1:
|
||||
if count == 0:
|
||||
run = [line[index + 1]]
|
||||
entry = (1, run)
|
||||
lst.append(entry)
|
||||
else:
|
||||
run.append(current)
|
||||
entry = (count + 1 + 128, run)
|
||||
lst.append(entry)
|
||||
return lst
|
||||
|
||||
|
||||
def encodeRLE24(img):
|
||||
width, height = img.size
|
||||
output = StringIO()
|
||||
bytesProcessedInBody = 0
|
||||
global bodyLength
|
||||
global payloadLimit
|
||||
|
||||
for h in range(height):
|
||||
line = []
|
||||
result = []
|
||||
for w in range(width):
|
||||
(r, g, b) = img.getpixel((w, h))
|
||||
line.append((r << 16) + (g << 8) + b)
|
||||
result = encode(line)
|
||||
for count, pixel in result:
|
||||
output.write(struct.pack("B", count - 1))
|
||||
bytesProcessedInBody += 1
|
||||
if count > 128:
|
||||
output.write(struct.pack("B", (pixel[0]) & 0xFF))
|
||||
output.write(struct.pack("B", ((pixel[0]) >> 8) & 0xFF))
|
||||
output.write(struct.pack("B", ((pixel[0]) >> 16) & 0xFF))
|
||||
bytesProcessedInBody += 3
|
||||
else:
|
||||
for item in pixel:
|
||||
output.write(struct.pack("B", item & 0xFF))
|
||||
output.write(struct.pack("B", (item >> 8) & 0xFF))
|
||||
output.write(struct.pack("B", (item >> 16) & 0xFF))
|
||||
bytesProcessedInBody += 3
|
||||
|
||||
bodyLength = len(output.getvalue())
|
||||
|
||||
if payloadLimit != 0:
|
||||
assert bytesProcessedInBody <= payloadLimit, "\n\n\nPICTURE IS LARGE IN SIZE..\nQuitting..."
|
||||
while bytesProcessedInBody < payloadLimit:
|
||||
output.write(struct.pack("B", 0x00))
|
||||
bytesProcessedInBody += 1
|
||||
content = output.getvalue()
|
||||
output.close()
|
||||
return content
|
||||
|
||||
|
||||
## get payload data : BGR Interleaved
|
||||
def GetImageBody(img, compressed=0):
|
||||
color = (0, 0, 0)
|
||||
if img.mode == "RGB":
|
||||
background = img
|
||||
elif img.mode == "RGBA":
|
||||
background = Image.new("RGB", img.size, color)
|
||||
img.load()
|
||||
background.paste(img, mask=img.split()[3]) # alpha channel
|
||||
elif img.mode == "P" or img.mode == "L":
|
||||
background = Image.new("RGB", img.size, color)
|
||||
img.load()
|
||||
background.paste(img)
|
||||
# background.save("splash.png")
|
||||
else:
|
||||
print("sorry, can't support this format")
|
||||
sys.exit()
|
||||
|
||||
background.load()
|
||||
|
||||
if compressed == 1:
|
||||
return encodeRLE24(background)
|
||||
else:
|
||||
r, g, b = background.split()
|
||||
return Image.merge("RGB", (b, g, r)).tostring()
|
||||
|
||||
|
||||
## make a image
|
||||
|
||||
def MakeLogoImage(logo, out):
|
||||
img = Image.open(logo)
|
||||
file = open(out, "wb")
|
||||
body = GetImageBody(img, SUPPORT_RLE24_COMPRESSIONT)
|
||||
file.write(GetImgHeader(img.size, SUPPORT_RLE24_COMPRESSIONT, len(body)))
|
||||
file.write(body)
|
||||
file.close()
|
||||
|
||||
|
||||
## mian
|
||||
|
||||
def ShowUsage():
|
||||
print(" usage: python logo_gen.py [logo.png] payload_max_size")
|
||||
|
||||
|
||||
def GetPNGFile():
|
||||
global payloadLimit
|
||||
infile = "logo.png" # default file name
|
||||
num = len(sys.argv)
|
||||
|
||||
if num < 2:
|
||||
ShowUsage()
|
||||
sys.exit(); # error arg
|
||||
|
||||
infile = sys.argv[1]
|
||||
if SUPPORT_RLE24_COMPRESSIONT == 1 and num == 3:
|
||||
payloadLimit = int(sys.argv[2])
|
||||
|
||||
if not os.access(infile, os.R_OK):
|
||||
ShowUsage()
|
||||
sys.exit(); # error file
|
||||
return infile
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
MakeLogoImage(GetPNGFile(), "output.img")
|
|
@ -0,0 +1,124 @@
|
|||
'''
|
||||
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()
|
Loading…
Reference in New Issue