diff --git a/core/docs/toif.md b/core/docs/toif.md index 1b7499e8f..bd7493421 100644 --- a/core/docs/toif.md +++ b/core/docs/toif.md @@ -17,8 +17,8 @@ All multibyte integer values are little endian! TOI currently supports 2 variants: -* `f`: full-color, file extension `.toif` -* `g`: gray-scale, file extension `.toig` +* `f`: full-color +* `g`: gray-scale ### Full-color @@ -55,5 +55,4 @@ zdata = zdata[2:-4] # strip header and checksum ## Tools -* [png2toi](../tools/png2toi) - tool for converting PNG into TOI format -* [toi2png](../tools/toi2png) - tool for converting TOI into PNG +* [toif_convert](../tools/toif_convert) - tool for converting PNGs into TOI format and back diff --git a/core/src/apps/management/res/small-arrow.toig b/core/src/apps/management/res/small-arrow.toif similarity index 100% rename from core/src/apps/management/res/small-arrow.toig rename to core/src/apps/management/res/small-arrow.toif diff --git a/core/src/trezor/res/cancel.toig b/core/src/trezor/res/cancel.toif similarity index 100% rename from core/src/trezor/res/cancel.toig rename to core/src/trezor/res/cancel.toif diff --git a/core/src/trezor/res/check.toig b/core/src/trezor/res/check.toif similarity index 100% rename from core/src/trezor/res/check.toig rename to core/src/trezor/res/check.toif diff --git a/core/src/trezor/res/click.toig b/core/src/trezor/res/click.toif similarity index 100% rename from core/src/trezor/res/click.toig rename to core/src/trezor/res/click.toif diff --git a/core/src/trezor/res/confirm.toig b/core/src/trezor/res/confirm.toif similarity index 100% rename from core/src/trezor/res/confirm.toig rename to core/src/trezor/res/confirm.toif diff --git a/core/src/trezor/res/header_icons/cog.toig b/core/src/trezor/res/header_icons/cog.toif similarity index 100% rename from core/src/trezor/res/header_icons/cog.toig rename to core/src/trezor/res/header_icons/cog.toif diff --git a/core/src/trezor/res/header_icons/nocopy.toig b/core/src/trezor/res/header_icons/nocopy.toif similarity index 100% rename from core/src/trezor/res/header_icons/nocopy.toig rename to core/src/trezor/res/header_icons/nocopy.toif diff --git a/core/src/trezor/res/header_icons/receive.toig b/core/src/trezor/res/header_icons/receive.toif similarity index 100% rename from core/src/trezor/res/header_icons/receive.toig rename to core/src/trezor/res/header_icons/receive.toif diff --git a/core/src/trezor/res/header_icons/recovery.toig b/core/src/trezor/res/header_icons/recovery.toif similarity index 100% rename from core/src/trezor/res/header_icons/recovery.toig rename to core/src/trezor/res/header_icons/recovery.toif diff --git a/core/src/trezor/res/header_icons/reset.toig b/core/src/trezor/res/header_icons/reset.toif similarity index 100% rename from core/src/trezor/res/header_icons/reset.toig rename to core/src/trezor/res/header_icons/reset.toif diff --git a/core/src/trezor/res/header_icons/send.toig b/core/src/trezor/res/header_icons/send.toif similarity index 100% rename from core/src/trezor/res/header_icons/send.toig rename to core/src/trezor/res/header_icons/send.toif diff --git a/core/src/trezor/res/header_icons/wipe.toig b/core/src/trezor/res/header_icons/wipe.toif similarity index 100% rename from core/src/trezor/res/header_icons/wipe.toig rename to core/src/trezor/res/header_icons/wipe.toif diff --git a/core/src/trezor/res/header_icons/wrong.toig b/core/src/trezor/res/header_icons/wrong.toif similarity index 100% rename from core/src/trezor/res/header_icons/wrong.toig rename to core/src/trezor/res/header_icons/wrong.toif diff --git a/core/src/trezor/res/left.toig b/core/src/trezor/res/left.toif similarity index 100% rename from core/src/trezor/res/left.toig rename to core/src/trezor/res/left.toif diff --git a/core/src/trezor/res/lock.toig b/core/src/trezor/res/lock.toif similarity index 100% rename from core/src/trezor/res/lock.toig rename to core/src/trezor/res/lock.toif diff --git a/core/src/trezor/res/pin_close.toig b/core/src/trezor/res/pin_close.toif similarity index 100% rename from core/src/trezor/res/pin_close.toig rename to core/src/trezor/res/pin_close.toif diff --git a/core/src/trezor/res/recovery.toig b/core/src/trezor/res/recovery.toif similarity index 100% rename from core/src/trezor/res/recovery.toig rename to core/src/trezor/res/recovery.toif diff --git a/core/src/trezor/res/space.toig b/core/src/trezor/res/space.toif similarity index 100% rename from core/src/trezor/res/space.toig rename to core/src/trezor/res/space.toif diff --git a/core/src/trezor/res/swipe.toig b/core/src/trezor/res/swipe.toif similarity index 100% rename from core/src/trezor/res/swipe.toig rename to core/src/trezor/res/swipe.toif diff --git a/core/src/trezor/ui/style.py b/core/src/trezor/ui/style.py index 38e73efac..420819f79 100644 --- a/core/src/trezor/ui/style.py +++ b/core/src/trezor/ui/style.py @@ -47,22 +47,22 @@ BG = BLACK FG = WHITE # icons -ICON_RESET = "trezor/res/header_icons/reset.toig" -ICON_WIPE = "trezor/res/header_icons/wipe.toig" -ICON_RECOVERY = "trezor/res/header_icons/recovery.toig" -ICON_NOCOPY = "trezor/res/header_icons/nocopy.toig" -ICON_WRONG = "trezor/res/header_icons/wrong.toig" -ICON_CONFIG = "trezor/res/header_icons/cog.toig" -ICON_RECEIVE = "trezor/res/header_icons/receive.toig" -ICON_SEND = "trezor/res/header_icons/send.toig" +ICON_RESET = "trezor/res/header_icons/reset.toif" +ICON_WIPE = "trezor/res/header_icons/wipe.toif" +ICON_RECOVERY = "trezor/res/header_icons/recovery.toif" +ICON_NOCOPY = "trezor/res/header_icons/nocopy.toif" +ICON_WRONG = "trezor/res/header_icons/wrong.toif" +ICON_CONFIG = "trezor/res/header_icons/cog.toif" +ICON_RECEIVE = "trezor/res/header_icons/receive.toif" +ICON_SEND = "trezor/res/header_icons/send.toif" ICON_DEFAULT = ICON_CONFIG -ICON_CANCEL = "trezor/res/cancel.toig" -ICON_CONFIRM = "trezor/res/confirm.toig" -ICON_LOCK = "trezor/res/lock.toig" -ICON_CLICK = "trezor/res/click.toig" -ICON_BACK = "trezor/res/left.toig" -ICON_SWIPE = "trezor/res/swipe.toig" -ICON_CHECK = "trezor/res/check.toig" -ICON_SPACE = "trezor/res/space.toig" +ICON_CANCEL = "trezor/res/cancel.toif" +ICON_CONFIRM = "trezor/res/confirm.toif" +ICON_LOCK = "trezor/res/lock.toif" +ICON_CLICK = "trezor/res/click.toif" +ICON_BACK = "trezor/res/left.toif" +ICON_SWIPE = "trezor/res/swipe.toif" +ICON_CHECK = "trezor/res/check.toif" +ICON_SPACE = "trezor/res/space.toif" diff --git a/core/tools/png2toi b/core/tools/png2toi deleted file mode 100755 index e9be14170..000000000 --- a/core/tools/png2toi +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python3 -from PIL import Image -import sys -import struct -import zlib -from os.path import basename - - -def process_rgb(w, h, pix): - data = bytes() - for j in range(h): - for i in range(w): - r, g, b = pix[i, j] - c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3) - data += struct.pack(">H", c) - return data - - -def process_grayscale(w, h, pix): - data = bytes() - for j in range(h): - for i in range(w // 2): - l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j] - c = (l1 & 0xF0) | (l2 >> 4) - data += struct.pack(">B", c) - return data - - -def process_image(ifn, savefiles=False): - im = Image.open(ifn) - w, h = im.size - print("Opened %s ... %d x %d @ %s" % (ifn, w, h, im.mode)) - - if im.mode == "RGB": - print("Detected RGB mode") - elif im.mode == "L": - if w % 2 > 0: - print("PNG file must have width divisible by 2") - return 3 - print("Detected GRAYSCALE mode") - else: - print("Unknown mode:", im.mode) - return 4 - - pix = im.load() - - bname = basename(ifn[:-4]) - ofn_h = "%s.h" % bname - ofn_py = "%s.py" % bname - - if im.mode == "RGB": - ofn = "%s.toif" % bname - pixeldata = process_rgb(w, h, pix) - else: - ofn = "%s.toig" % bname - pixeldata = process_grayscale(w, h, pix) - z = zlib.compressobj(level=9, wbits=10) - zdata = z.compress(pixeldata) + z.flush() - zdata = zdata[2:-4] # strip header and checksum - - data = b"" - if im.mode == "RGB": - data += b"TOIf" - else: - data += b"TOIg" - data += struct.pack("> 8, h & 0xFF, h >> 8) - ) - l = len(zdata) - f.write(" // compressed data length (32-bit)\n") - f.write( - " 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n" - % (l & 0xFF, (l >> 8) & 0xFF, (l >> 16) & 0xFF, l >> 24) - ) - f.write(" // compressed data\n") - f.write(" ") - for b in zdata: - f.write(" 0x%02x," % b) - f.write("\n};\n") - print("Written %s ... done" % ofn_py) - - return data - - -def main(): - if len(sys.argv) < 2: - print("Usage png2toi image.png") - return 1 - - ifn = sys.argv[1] - if not ifn.endswith(".png"): - print("Must provide PNG file") - return 2 - - process_image(ifn, savefiles=True) - - -main() diff --git a/core/tools/toi2png b/core/tools/toi2png deleted file mode 100755 index d6d17521d..000000000 --- a/core/tools/toi2png +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python3 -from PIL import Image -import sys -import struct -import zlib - - -def process_rgb(w, h, data): - pix = bytearray(w * h * 3) - for i in range(w * h): - c = (data[i * 2] << 8) + data[i * 2 + 1] - pix[i * 3 + 0] = (c & 0xF800) >> 8 - pix[i * 3 + 1] = (c & 0x07C0) >> 3 - pix[i * 3 + 2] = (c & 0x001F) << 3 - return bytes(pix) - - -def process_grayscale(w, h, data): - pix = bytearray(w * h) - for i in range(w * h // 2): - pix[i * 2 + 0] = data[i] & 0xF0 - pix[i * 2 + 1] = (data[i] & 0x0F) << 4 - return bytes(pix) - - -def process_image(ifn, ofn): - - data = open(ifn, "rb").read() - - if ifn.endswith(".toif"): - if data[:4] != b"TOIf": - print("Unknown TOIF header") - return 1 - elif ifn.endswith(".toig"): - if data[:4] != b"TOIg": - print("Unknown TOIG header") - return 2 - else: - print("Unsupported format") - return 3 - if ofn is None: - ofn = "%s.png" % ifn[:-5] - - w, h = struct.unpack(" 2 else None - process_image(ifn, ofn) - - -main() diff --git a/core/tools/toif_convert b/core/tools/toif_convert new file mode 100755 index 000000000..824d325df --- /dev/null +++ b/core/tools/toif_convert @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +from PIL import Image +import io +import sys +import struct +import zlib +from os.path import basename + + +def png2toif(input_data): + + def process_rgb(w, h, pix): + data = bytes() + for j in range(h): + for i in range(w): + r, g, b = pix[i, j] + c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3) + data += struct.pack(">H", c) + return data + + def process_grayscale(w, h, pix): + data = bytes() + for j in range(h): + for i in range(w // 2): + l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j] + c = (l1 & 0xF0) | (l2 >> 4) + data += struct.pack(">B", c) + return data + + im = Image.open(io.BytesIO(input_data)) + w, h = im.size + if im.mode not in ["RGB", "L"]: + raise ValueError("Unknown mode:", im.mode) + if im.mode == "L": + if w % 2 > 0: + raise ValueError("PNG file must have width divisible by 2") + + pix = im.load() + if im.mode == "RGB": + pixeldata = process_rgb(w, h, pix) + else: + pixeldata = process_grayscale(w, h, pix) + z = zlib.compressobj(level=9, wbits=10) + zdata = z.compress(pixeldata) + z.flush() + zdata = zdata[2:-4] # strip header and checksum + + data = b"" + if im.mode == "RGB": + data += b"TOIf" + else: + data += b"TOIg" + data += struct.pack("> 8, h & 0xFF, h >> 8) + ) + l = len(zdata) + f.write(" // compressed data length (32-bit)\n") + f.write( + " 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n" + % (l & 0xFF, (l >> 8) & 0xFF, (l >> 16) & 0xFF, l >> 24) + ) + f.write(" // compressed data\n") + f.write(" ") + for b in zdata: + f.write(" 0x%02x," % b) + f.write("\n};\n") + """ + + + +def toif2png(data): + + def process_rgb(w, h, data): + pix = bytearray(w * h * 3) + for i in range(w * h): + c = (data[i * 2] << 8) + data[i * 2 + 1] + pix[i * 3 + 0] = (c & 0xF800) >> 8 + pix[i * 3 + 1] = (c & 0x07C0) >> 3 + pix[i * 3 + 2] = (c & 0x001F) << 3 + return bytes(pix) + + + def process_grayscale(w, h, data): + pix = bytearray(w * h) + for i in range(w * h // 2): + pix[i * 2 + 0] = data[i] & 0xF0 + pix[i * 2 + 1] = (data[i] & 0x0F) << 4 + return bytes(pix) + + if data[:4] != b"TOIf" and data[:4] != b"TOIg": + raise ValueError("Unknown TOIF header") + format = data[:4].decode().lower() + w, h = struct.unpack("