mirror of
https://github.com/google/pebble.git
synced 2025-05-27 13:33:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
159
tools/pbi2png.py
Normal file
159
tools/pbi2png.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import os, sys
|
||||
from ctypes import *
|
||||
from PIL import Image
|
||||
|
||||
format_dict = {
|
||||
'GBitmapFormat1Bit': 0,
|
||||
'GBitmapFormat8Bit': 1,
|
||||
'GBitmapFormat1BitPalette': 2,
|
||||
'GBitmapFormat2BitPalette': 3,
|
||||
'GBitmapFormat4BitPalette': 4
|
||||
}
|
||||
|
||||
|
||||
# NOTE: If this changes, please update the GBitmapDump gdb command.
|
||||
class pbi_struct(Structure):
|
||||
_fields_ = [
|
||||
("stride", c_uint16), ("info", c_uint16),
|
||||
("bounds_x", c_uint16), ("bounds_y", c_uint16),
|
||||
("bounds_w", c_uint16), ("bounds_h", c_uint16),
|
||||
]
|
||||
|
||||
def flip_byte(abyte):
|
||||
return int('{:08b}'.format(abyte)[::-1],2)
|
||||
|
||||
#converts from argb8 (2-bits per color channel) to RGBA32 (byte per channel)
|
||||
def argb8_to_rgba32(argb8):
|
||||
return (
|
||||
((argb8 >> 4) & 0x3) * 85, #R
|
||||
((argb8 >> 2) & 0x3) * 85, #G
|
||||
((argb8 ) & 0x3) * 85, #B
|
||||
((argb8 >> 6) & 0x3) * 85) #A
|
||||
|
||||
|
||||
def pbi_format(info):
|
||||
return (info & 0xe) >> 1
|
||||
|
||||
|
||||
def pbi_bitdepth(fmt):
|
||||
bitdepth_list = [1, 8, 1, 2, 4]
|
||||
return bitdepth_list[fmt]
|
||||
|
||||
|
||||
def pbi_is_palettized(fmt):
|
||||
return fmt >= format_dict['GBitmapFormat1BitPalette']
|
||||
|
||||
|
||||
def palette_size(fmt):
|
||||
return 2 ** pbi_bitdepth(fmt)
|
||||
|
||||
|
||||
def pbi_to_png(pbi, pixel_bytearray):
|
||||
gbitmap_version = (pbi.info >> 12) & 0x0F
|
||||
gbitmap_format = pbi_format(pbi.info)
|
||||
# if version is 2 and format is 0x01 (GBitmapFormat8Bit)
|
||||
if gbitmap_version == 1 and gbitmap_format == format_dict['GBitmapFormat8Bit']:
|
||||
print("8-bit ARGB color image")
|
||||
pixel_rgba_array = bytearray()
|
||||
for (idx, abyte) in enumerate(pixel_bytearray):
|
||||
argb8 = pixel_bytearray[idx]
|
||||
pixel_rgba_array.append(((argb8 >> 4) & 0x3) * 85) # r
|
||||
pixel_rgba_array.append(((argb8 >> 2) & 0x3) * 85) # g
|
||||
pixel_rgba_array.append(((argb8 >> 0) & 0x3) * 85) # b
|
||||
pixel_rgba_array.append(((argb8 >> 6) & 0x3) * 85) # a
|
||||
|
||||
png = Image.frombuffer('RGBA', (pbi.bounds_w, pbi.bounds_h),
|
||||
buffer(pixel_rgba_array), 'raw', 'RGBA', pbi.stride * 4, 1)
|
||||
|
||||
elif gbitmap_version == 1 and pbi_is_palettized(gbitmap_format):
|
||||
bitdepth = pbi_bitdepth(gbitmap_format)
|
||||
print("{}-bit palettized color image".format(bitdepth))
|
||||
|
||||
# Create palette colors in format R, G, B, A
|
||||
palette = []
|
||||
palette_offset = pbi.stride * pbi.bounds_h
|
||||
for argb8 in pixel_bytearray[palette_offset:]:
|
||||
palette.append((argb8_to_rgba32(argb8)))
|
||||
|
||||
pixels = []
|
||||
# go through the image data byte by byte, and handle
|
||||
# converting the depth-packed indexes for the palette to an unpacked list
|
||||
idx = 0 # index of actual packed values including padded values
|
||||
for pxl8 in pixel_bytearray[:palette_offset]:
|
||||
for i in xrange(0, 8 / bitdepth):
|
||||
# only append actual pixels, ignoring padding pixels
|
||||
# which is the difference between the width and the stride
|
||||
if (idx % (pbi.stride * (8 / bitdepth)) < pbi.bounds_w):
|
||||
pixels.append(
|
||||
((pxl8 >> (bitdepth * (8 / bitdepth - (i + 1)))) & ~(~0 << bitdepth)))
|
||||
idx = idx + 1
|
||||
|
||||
# Manually convert from paletted to RGBA
|
||||
# as PIL doesn't seem to handle palette with alpha
|
||||
rgba_pixels = []
|
||||
for pal_pxl in pixels:
|
||||
rgba_pixels.append(palette[pal_pxl])
|
||||
|
||||
png = Image.new('RGBA', (pbi.bounds_w, pbi.bounds_h))
|
||||
png.putdata(rgba_pixels)
|
||||
|
||||
# legacy 1-bit format
|
||||
elif gbitmap_version == 0 or \
|
||||
(gbitmap_version == 1 and gbitmap_format == format_dict['GBitmapFormat1Bit']):
|
||||
print("1-bit b&w image")
|
||||
# pbi has bits in bytes reversed, so flip here
|
||||
for (idx, abyte) in enumerate(pixel_bytearray):
|
||||
pixel_bytearray[idx] = flip_byte(pixel_bytearray[idx])
|
||||
|
||||
png = Image.frombuffer('1', (pbi.bounds_w, pbi.bounds_h),
|
||||
buffer(pixel_bytearray), 'raw', '1', pbi.stride, 1)
|
||||
else:
|
||||
print "Bad PBI"
|
||||
png = None
|
||||
|
||||
return png
|
||||
|
||||
|
||||
def main():
|
||||
# arguments, print an example of correct usage.
|
||||
if len(sys.argv) - 1 != 2:
|
||||
print("********************")
|
||||
print("Usage suggestion:")
|
||||
print("python " + sys.argv[0] + " <in_image.pbi> <out_image.png>")
|
||||
print("********************")
|
||||
exit()
|
||||
|
||||
input_filename = sys.argv[1]
|
||||
output_filename = sys.argv[2]
|
||||
|
||||
print("Converting PBI to PNG...")
|
||||
pbi = pbi_struct()
|
||||
pixel_bytearray = bytearray()
|
||||
with open(input_filename, 'rb') as afile:
|
||||
afile.readinto(pbi)
|
||||
print("x:%d y:%d" % (pbi.bounds_x, pbi.bounds_y))
|
||||
print("Width:%d Height:%d" % (pbi.bounds_w, pbi.bounds_h))
|
||||
print("row stride:%d" % (pbi.stride))
|
||||
pixel_bytearray = bytearray(afile.read())
|
||||
|
||||
png = pbi_to_png(pbi, pixel_bytearray)
|
||||
png.save(output_filename)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue