Persistent camera rotation support

This commit is contained in:
kdmukai
2021-09-17 18:36:53 -05:00
parent 293ec3b23e
commit 98a5d17f71
10 changed files with 76 additions and 39 deletions
+1
View File
@@ -5,6 +5,7 @@ persistent_settings = False
[display]
text_color = ORANGE
camera_rotation = 0
[wallet]
network = main
+12 -27
View File
@@ -10,6 +10,16 @@ from seedsigner.helpers import PiVideoStream, Singleton
class Camera(Singleton):
_video_stream = None
_picamera = None
_camera_rotation = None
@classmethod
def get_instance(cls):
# This is the only way to access the one and only Controller
from seedsigner.models import Settings
if cls._instance is None:
cls._instance = cls.__new__(cls)
cls._instance._camera_rotation = Settings.get_instance().camera_rotation
return cls._instance
def start_video_stream_mode(self, resolution=(512, 384), framerate=12, format="bgr"):
@@ -28,7 +38,7 @@ class Camera(Singleton):
return frame
else:
if frame is not None:
return Image.fromarray(frame.astype('uint8'), 'RGB').rotate(90)
return Image.fromarray(frame.astype('uint8'), 'RGB').rotate(90 + self._camera_rotation)
return None
@@ -59,37 +69,12 @@ class Camera(Singleton):
self._picamera.awb_mode = 'off'
self._picamera.awb_gains = g
"""
When outputting to unencoded formats, the camera rounds the requested resolution.
The horizontal resolution is rounded up to the nearest multiple of 32 pixels,
while the vertical resolution is rounded up to the nearest multiple of 16 pixels.
"""
# resolution = self._picamera.resolution
# if resolution.width % 32 == 0:
# raw_width = resolution.width
# else:
# raw_width = resolution.width - (resolution.width % 32) + 32
# if resolution.height % 16 == 0:
# raw_height = resolution.height
# else:
# raw_height = resolution.height + 16
# print(resolution)
# print(raw_width, raw_height)
# np_array = numpy.empty((raw_width, raw_height, 3), dtype=numpy.uint8)
# self._picamera.capture(np_array, format='rgb')
# np_array.reshape((raw_width, raw_height, 3))
# return Image.fromarray(np_array[:resolution.width, :resolution.height, :].astype('uint8'), 'RGB')
stream = io.BytesIO()
self._picamera.capture(stream, format='jpeg')
# "Rewind" the stream to the beginning so we can read its content
stream.seek(0)
return Image.open(stream)
return Image.open(stream).rotate(90 + self._camera_rotation)
def stop_single_frame_mode(self):
+11 -2
View File
@@ -73,7 +73,8 @@ class Controller(Singleton):
controller.settings_tools_view = SettingsToolsView()
controller.screensaver = ScreensaverView(controller.buttons)
controller.screensaver_activation_ms = 60 * 1000
controller.screensaver_activation_ms = 120 * 1000
@property
def camera(self):
@@ -153,6 +154,8 @@ class Controller(Singleton):
ret_val = self.show_qr_density_tool()
elif ret_val == Path.PERSISTENT_SETTINGS:
ret_val = self.show_persistent_settings_tool()
elif ret_val == Path.CAMERA_ROTATION:
ret_val = self.show_camera_rotation_tool()
elif ret_val == Path.DONATE:
ret_val = self.show_donate_tool()
elif ret_val == Path.RESET:
@@ -830,7 +833,13 @@ class Controller(Singleton):
return Path.SETTINGS_SUB_MENU
### Show Donate Screen and QR
def show_camera_rotation_tool(self):
r = self.settings_tools_view.display_camera_rotation()
if r is not None:
self.settings.camera_rotation = r
return Path.SETTINGS_SUB_MENU ### Show Donate Screen and QR
def show_donate_tool(self):
self.settings_tools_view.display_donate_info_screen()
+1
View File
@@ -28,6 +28,7 @@ class Path:
WALLET = 64
QR_DENSITY_SETTING = 65
PERSISTENT_SETTINGS = 67
CAMERA_ROTATION = 69
RESET = 68
# Seed Slots
+17 -1
View File
@@ -5,6 +5,8 @@ from .encode_qr_density import EncodeQRDensity
import configparser
from embit import bip39
class Settings(Singleton):
@classmethod
@@ -13,7 +15,7 @@ class Settings(Singleton):
if cls._instance:
raise Exception("Instance already configured")
# Instantiate the one and only Controller instance
# Instantiate the one and only instance
settings = cls.__new__(cls)
cls._instance = settings
@@ -27,6 +29,7 @@ class Settings(Singleton):
},
'display': {
'text_color': "ORANGE",
'camera_rotation': 0,
},
'wallet': {
'network': "main",
@@ -49,6 +52,7 @@ class Settings(Singleton):
self._data["system"]["debug"] = config.getboolean("system", "debug")
self._data["system"]["default_language"] = config["system"]["default_language"]
self._data["display"]["text_color"] = config["display"]["text_color"]
self._data["display"]["camera_rotation"] = int(config["display"]["camera_rotation"])
self.network = config["wallet"]["network"]
self.software = config["wallet"]["software"]
self.qr_density = int(config["wallet"]["qr_density"])
@@ -125,6 +129,18 @@ class Settings(Singleton):
def text_color(self):
return self._data["display"]["text_color"]
@property
def camera_rotation(self):
return self._data["display"]["camera_rotation"]
@camera_rotation.setter
def camera_rotation(self, value):
if value in [0, 90, 180, 270]:
self._data["display"]["camera_rotation"] = value
self.__writeConfig()
else:
raise Exception("Unexpected display.camera_rotation settings.ini value")
### wallet
@property
+5 -3
View File
@@ -124,7 +124,7 @@ class MenuView(View):
### Settings Menu
def display_settings_menu(self) -> int:
lines = ["... [ Return to Main ]", "Wallet: <wallet>", "Network: <network>", "QR Density: <density>", "Input / Output Tests", "Persistent Settings: <persistent>", "Version Info", "Donate to SeedSigner", "Reset SeedSigner"]
lines = ["... [ Return to Main ]", "Wallet: <wallet>", "Network: <network>", "QR Density: <density>", "Input / Output Tests", "Persistent Settings: <persistent>", "Camera Rotation", "Version Info", "Donate to SeedSigner", "Reset SeedSigner"]
input = 0
lines[1] = lines[1].replace("<wallet>", Settings.get_instance().software)
@@ -157,10 +157,12 @@ class MenuView(View):
elif self.selected_menu_num == 6:
return Path.PERSISTENT_SETTINGS
elif self.selected_menu_num == 7:
return Path.VERSION_INFO
return Path.CAMERA_ROTATION
elif self.selected_menu_num == 8:
return Path.DONATE
return Path.VERSION_INFO
elif self.selected_menu_num == 9:
return Path.DONATE
elif self.selected_menu_num == 10:
return Path.RESET
raise Exception("Unhandled case")
+4 -4
View File
@@ -1064,10 +1064,12 @@ class SeedToolsView(View):
draw.rectangle((mask_width, 0, View.canvas_width - mask_width, pixels_per_block), fill=View.color)
draw.rectangle((0, mask_height, pixels_per_block, View.canvas_height - mask_height), fill=View.color)
label_font = View.COURIERNEW24
label_font = View.ASSISTANT26
x_label = block_labels_x[cur_block_x]
tw, th = draw.textsize(x_label, font=label_font)
draw.text(((View.canvas_width - tw) / 2, (pixels_per_block - th) / 2), x_label, fill="BLACK", font=label_font)
# note: have to nudge the y-coord up (the extra "- 4") for some reason
draw.text(((View.canvas_width - tw) / 2, ((pixels_per_block - th) / 2) - 4), x_label, fill="BLACK", font=label_font)
y_label = block_labels_y[cur_block_y]
tw, th = draw.textsize(y_label, font=label_font)
@@ -1209,8 +1211,6 @@ class SeedToolsView(View):
display_version = autocontrast(
seed_entropy_image,
cutoff=2
).rotate(
90
).crop(
(120, 0, 600, 480)
).resize(
@@ -79,6 +79,28 @@ class SettingsToolsView(View):
else:
return None
def display_camera_rotation(self) -> int:
lines = ["... [ Return to Settings ]"]
lines.append("0 (default)")
lines.append("90")
lines.append("180")
lines.append("270")
r = self.controller.menu_view.display_generic_selection_menu(lines, "Camera Rotation")
if r == 1:
return None
elif r == 2:
return 0
elif r == 3:
return 90
elif r == 4:
return 180
elif r == 5:
return 270
else:
return None
###
### Version Info
###
+1 -1
View File
@@ -158,7 +158,7 @@ class View:
text_overlay = Image.new("RGBA", (View.canvas_width, View.canvas_height), (255,255,255,0))
text_overlay_draw = ImageDraw.Draw(text_overlay)
if not font:
font = View.COURIERNEW14
font = View.ASSISTANT18
tw, th = text_overlay_draw.textsize(text, font=font)
if text_background:
text_overlay_draw.rectangle(((240 - tw) / 2 - 3, 240 - th, (240 - tw) / 2 + tw + 3, 240), fill=text_background)
+2 -1
View File
@@ -5,9 +5,10 @@ persistent_settings = False
[display]
text_color = ORANGE
camera_rotation = 180
[wallet]
network = main
software = Prompt
qr_density = 2
custom_derivation = m/0
custom_derivation = m/0/0