1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 20:38:10 +00:00

feat(python/trezorctl): better conversion to Trezor homescreen format (fixes #2880)

This commit is contained in:
matejcik 2023-04-24 14:19:02 +02:00
parent 67748f3c94
commit f6534d4220
2 changed files with 29 additions and 34 deletions

View File

@ -0,0 +1 @@
Auto-convert image to Trezor's homescreen format.

View File

@ -14,7 +14,8 @@
# You should have received a copy of the License along with this library. # You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>. # If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
import os import io
from pathlib import Path
from typing import TYPE_CHECKING, Optional, cast from typing import TYPE_CHECKING, Optional, cast
import click import click
@ -39,13 +40,13 @@ SAFETY_LEVELS = {
} }
def image_to_t1(filename: str) -> bytes: def image_to_t1(filename: Path) -> bytes:
if not PIL_AVAILABLE: if not PIL_AVAILABLE:
raise click.ClickException( raise click.ClickException(
"Image library is missing. Please install via 'pip install Pillow'." "Image library is missing. Please install via 'pip install Pillow'."
) )
if filename.endswith(".toif"): if filename.suffix == ".toif":
raise click.ClickException("TOIF images not supported on Trezor One") raise click.ClickException("TOIF images not supported on Trezor One")
try: try:
@ -60,10 +61,10 @@ def image_to_t1(filename: str) -> bytes:
return image.tobytes("raw", "1") return image.tobytes("raw", "1")
def image_to_toif_144x144(filename: str) -> bytes: def image_to_toif_144x144(filename: Path) -> bytes:
if filename.endswith(".toif"): if filename.suffix == ".toif":
try: try:
toif_image = toif.load(filename) toif_image = toif.from_bytes(filename.read_bytes())
except Exception as e: except Exception as e:
raise click.ClickException("TOIF file is corrupted") from e raise click.ClickException("TOIF file is corrupted") from e
@ -90,38 +91,30 @@ def image_to_toif_144x144(filename: str) -> bytes:
return toif_image.to_bytes() return toif_image.to_bytes()
def image_to_jpeg_240x240(filename: str) -> bytes: def image_to_jpeg_240x240(filename: Path) -> bytes:
if not (filename.endswith(".jpg") or filename.endswith(".jpeg")): if filename.suffix in (".jpg", ".jpeg") and not PIL_AVAILABLE:
raise click.ClickException("Please use a jpg image") click.echo("Warning: Image library is missing, skipping image validation.")
return filename.read_bytes()
elif not PIL_AVAILABLE: if not PIL_AVAILABLE:
raise click.ClickException( raise click.ClickException(
"Image library is missing. Please install via 'pip install Pillow'." "Image library is missing. Please install via 'pip install Pillow'."
) )
else: try:
try: image = Image.open(filename)
image = Image.open(filename) except Exception as e:
except Exception as e: raise click.ClickException("Failed to open image") from e
raise click.ClickException("Failed to open image") from e
if "progressive" in image.info:
raise click.ClickException("Progressive JPEG is not supported")
if image.size != (240, 240): if image.size != (240, 240):
raise click.ClickException("Wrong size of image - should be 240x240") raise click.ClickException("Wrong size of image - should be 240x240")
image.close() if image.mode != "RGB":
image = image.convert("RGB")
file_stats = os.stat(filename) buf = io.BytesIO()
image.save(buf, format="jpeg", progressive=False)
if file_stats.st_size > 16384: return buf.getvalue()
raise click.ClickException("File is too big, please use maximum 16kB")
in_file = open(filename, "rb")
bytes = in_file.read()
in_file.close()
return bytes
def _should_remove(enable: Optional[bool], remove: bool) -> bool: def _should_remove(enable: Optional[bool], remove: bool) -> bool:
@ -237,23 +230,24 @@ def homescreen(client: "TrezorClient", filename: str) -> str:
if filename == "default": if filename == "default":
img = b"" img = b""
else: else:
# use Click's facility to validate the path for us path = Path(filename)
param = click.Path(dir_okay=False, readable=True, exists=True) if not path.exists() or not path.is_file():
param.convert(filename, None, None) raise click.ClickException("Cannot open file")
if client.features.model == "1": if client.features.model == "1":
img = image_to_t1(filename) img = image_to_t1(path)
else: else:
if ( if (
client.features.homescreen_format client.features.homescreen_format
== messages.HomescreenFormat.Jpeg240x240 == messages.HomescreenFormat.Jpeg240x240
): ):
img = image_to_jpeg_240x240(filename) img = image_to_jpeg_240x240(path)
elif ( elif (
client.features.homescreen_format client.features.homescreen_format
== messages.HomescreenFormat.Toif144x144 == messages.HomescreenFormat.Toif144x144
or client.features.homescreen_format is None or client.features.homescreen_format is None
): ):
img = image_to_toif_144x144(filename) img = image_to_toif_144x144(path)
else: else:
raise click.ClickException( raise click.ClickException(
"Unknown image format requested by the device." "Unknown image format requested by the device."