diff --git a/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py b/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py index 28d001c2..ac6165d2 100644 --- a/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py +++ b/internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py @@ -20,8 +20,8 @@ import mpos.time class CameraApp(Activity): - button_width = 40 - button_height = 40 + button_width = 60 + button_height = 45 width = 320 height = 240 @@ -82,7 +82,7 @@ class CameraApp(Activity): # Settings button settings_button = lv.button(self.main_screen) settings_button.set_size(self.button_width, self.button_height) - settings_button.align(lv.ALIGN.TOP_RIGHT, 0, self.button_height + 10) + settings_button.align(lv.ALIGN.TOP_RIGHT, 0, self.button_height + 5) settings_label = lv.label(settings_button) settings_label.set_text(lv.SYMBOL.SETTINGS) settings_label.center() @@ -98,8 +98,7 @@ class CameraApp(Activity): snap_label.center() self.zoom_button = lv.button(self.main_screen) self.zoom_button.set_size(self.button_width, self.button_height) - self.zoom_button.align(lv.ALIGN.RIGHT_MID, 0, self.button_height + 10) - #self.zoom_button.add_flag(lv.obj.FLAG.HIDDEN) + self.zoom_button.align(lv.ALIGN.RIGHT_MID, 0, self.button_height + 5) self.zoom_button.add_event_cb(self.zoom_button_click,lv.EVENT.CLICKED,None) zoom_label = lv.label(self.zoom_button) zoom_label.set_text("Z") @@ -135,7 +134,7 @@ class CameraApp(Activity): self.cam = init_internal_cam(self.width, self.height) if self.cam: self.image.set_rotation(900) # internal camera is rotated 90 degrees - # Apply saved camera settings + # Apply saved camera settings, only for internal camera for now: apply_camera_settings(self.cam, self.use_webcam) else: print("camera app: no internal camera found, trying webcam on /dev/video0") @@ -294,9 +293,26 @@ class CameraApp(Activity): def zoom_button_click(self, e): print("zooming...") + if self.use_webcam: + print("zoom_button_click is not supported for webcam") + return if self.cam: - # This might work as it's what works in the C code: - self.cam.set_res_raw(startX=0,startY=0,endX=2623,endY=1951,offsetX=992,offsetY=736,totalX=2844,totalY=2844,outputX=640,outputY=480,scale=False,binning=False) + prefs = SharedPreferences("com.micropythonos.camera") + startX = prefs.get_int("startX", CameraSettingsActivity.startX_default) + startY = prefs.get_int("startX", CameraSettingsActivity.startY_default) + endX = prefs.get_int("startX", CameraSettingsActivity.endX_default) + endY = prefs.get_int("startX", CameraSettingsActivity.endY_default) + offsetX = prefs.get_int("startX", CameraSettingsActivity.offsetX_default) + offsetY = prefs.get_int("startX", CameraSettingsActivity.offsetY_default) + totalX = prefs.get_int("startX", CameraSettingsActivity.totalX_default) + totalY = prefs.get_int("startX", CameraSettingsActivity.totalY_default) + outputX = prefs.get_int("startX", CameraSettingsActivity.outputX_default) + outputY = prefs.get_int("startX", CameraSettingsActivity.outputY_default) + scale = prefs.get_bool("scale", CameraSettingsActivity.scale_default) + binning = prefs.get_bool("binning", CameraSettingsActivity.binning_default) + # This works as it's what works in the C code: + result = self.cam.set_res_raw(startX,startY,endX,endY,offsetX,offsetY,totalX,totalY,outputX,outputY,scale,binning) + print(f"self.cam.set_res_raw returned {result}") def open_settings(self): self.image_dsc.data = None @@ -401,7 +417,7 @@ def init_internal_cam(width, height): resolution_map = { (96, 96): FrameSize.R96X96, (160, 120): FrameSize.QQVGA, - #(128, 128): FrameSize.R128X128, it's actually FrameSize.R128x128 but let's ignore it to be safe + (128, 128): FrameSize.R128X128, (176, 144): FrameSize.QCIF, (240, 176): FrameSize.HQVGA, (240, 240): FrameSize.R240X240, @@ -409,7 +425,9 @@ def init_internal_cam(width, height): (320, 320): FrameSize.R320X320, (400, 296): FrameSize.CIF, (480, 320): FrameSize.HVGA, + (480, 480): FrameSize.R480X480, (640, 480): FrameSize.VGA, + (640, 640): FrameSize.R640X640, (800, 600): FrameSize.SVGA, (1024, 768): FrameSize.XGA, (1280, 720): FrameSize.HD, @@ -595,6 +613,21 @@ def apply_camera_settings(cam, use_webcam): class CameraSettingsActivity(Activity): """Settings activity for comprehensive camera configuration.""" + # Original: { 2560, 1920, 0, 0, 2623, 1951, 32, 16, 2844, 1968 } + # Worked for digital zoom in C: { 2560, 1920, 0, 0, 2623, 1951, 992, 736, 2844, 1968 } + startX_default=0 + startY_default=0 + endX_default=2623 + endY_default=1951 + offsetX_default=32 + offsetY_default=16 + totalX_default=2844 + totalY_default=1968 + outputX_default=640 + outputY_default=480 + scale_default=False + binning_default=False + # Resolution options for desktop/webcam WEBCAM_RESOLUTIONS = [ ("160x120", "160x120"), @@ -618,10 +651,12 @@ class CameraSettingsActivity(Activity): ("320x320", "320x320"), ("400x296", "400x296"), ("480x320", "480x320"), + ("480x480", "480x480"), ("640x480", "640x480"), + ("640x640", "640x640"), ("800x600", "800x600"), ("1024x768", "1024x768"), - ("1280x720", "1280x720"), + ("1280x720", "1280x720"), # binned 2x2 ("1280x1024", "1280x1024"), ("1600x1200", "1600x1200"), ("1920x1080", "1920x1080"), @@ -659,8 +694,8 @@ class CameraSettingsActivity(Activity): # Create tabview tabview = lv.tabview(screen) - tabview.set_tab_bar_size(mpos.ui.pct_of_display_height(10)) - tabview.set_size(lv.pct(100), mpos.ui.pct_of_display_height(80)) + tabview.set_tab_bar_size(mpos.ui.pct_of_display_height(15)) + #tabview.set_size(lv.pct(100), mpos.ui.pct_of_display_height(80)) # Create Basic tab (always) basic_tab = tabview.add_tab("Basic") @@ -677,38 +712,6 @@ class CameraSettingsActivity(Activity): raw_tab = tabview.add_tab("Raw") self.create_raw_tab(raw_tab, prefs) - # Save/Cancel buttons at bottom - self.button_cont = lv.obj(screen) - self.button_cont.set_size(lv.pct(100), mpos.ui.pct_of_display_height(20)) - self.button_cont.remove_flag(lv.obj.FLAG.SCROLLABLE) - self.button_cont.align(lv.ALIGN.BOTTOM_MID, 0, 0) - self.button_cont.set_style_border_width(0, 0) - self.button_cont.set_style_bg_opa(0, 0) - - save_button = lv.button(self.button_cont) - save_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) - save_button.align(lv.ALIGN.BOTTOM_LEFT, 0, 0) - save_button.add_event_cb(lambda e: self.save_and_close(), lv.EVENT.CLICKED, None) - save_label = lv.label(save_button) - save_label.set_text("Save") - save_label.center() - - cancel_button = lv.button(self.button_cont) - cancel_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) - cancel_button.align(lv.ALIGN.BOTTOM_MID, 0, 0) - cancel_button.add_event_cb(lambda e: self.finish(), lv.EVENT.CLICKED, None) - cancel_label = lv.label(cancel_button) - cancel_label.set_text("Cancel") - cancel_label.center() - - erase_button = lv.button(self.button_cont) - erase_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) - erase_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0) - erase_button.add_event_cb(lambda e: self.erase_and_close(), lv.EVENT.CLICKED, None) - erase_label = lv.label(erase_button) - erase_label.set_text("Erase") - erase_label.center() - self.setContentView(screen) def create_slider(self, parent, label_text, min_val, max_val, default_val, pref_key): @@ -779,17 +782,18 @@ class CameraSettingsActivity(Activity): def create_textarea(self, parent, label_text, min_val, max_val, default_val, pref_key): cont = lv.obj(parent) - cont.set_size(lv.pct(100), 60) + cont.set_size(lv.pct(100), lv.SIZE_CONTENT) cont.set_style_pad_all(3, 0) label = lv.label(cont) - label.set_text(f"{label_text}: {default_val}") + label.set_text(f"{label_text}:") label.align(lv.ALIGN.TOP_LEFT, 0, 0) - textarea = lv.textarea(parent) - textarea.set_width(lv.pct(90)) + textarea = lv.textarea(cont) + textarea.set_width(lv.pct(50)) textarea.set_one_line(True) # might not be good for all settings but it's good for most textarea.set_text(str(default_val)) + textarea.align(lv.ALIGN.TOP_RIGHT, 0, 0) # Initialize keyboard (hidden initially) keyboard = MposKeyboard(parent) @@ -803,7 +807,7 @@ class CameraSettingsActivity(Activity): return textarea, cont def show_keyboard(self, kbd): - self.button_cont.add_flag(lv.obj.FLAG.HIDDEN) + #self.button_cont.add_flag(lv.obj.FLAG.HIDDEN) mpos.ui.anim.smooth_show(kbd) focusgroup = lv.group_get_default() if focusgroup: @@ -815,7 +819,41 @@ class CameraSettingsActivity(Activity): def hide_keyboard(self, kbd): mpos.ui.anim.smooth_hide(kbd) - self.button_cont.remove_flag(lv.obj.FLAG.HIDDEN) + #self.button_cont.remove_flag(lv.obj.FLAG.HIDDEN) + + def add_buttons(self, parent): + # Save/Cancel buttons at bottom + button_cont = lv.obj(parent) + button_cont.set_size(lv.pct(100), mpos.ui.pct_of_display_height(20)) + button_cont.remove_flag(lv.obj.FLAG.SCROLLABLE) + button_cont.align(lv.ALIGN.BOTTOM_MID, 0, 0) + button_cont.set_style_border_width(0, 0) + button_cont.set_style_bg_opa(0, 0) + + save_button = lv.button(button_cont) + save_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) + save_button.align(lv.ALIGN.BOTTOM_LEFT, 0, 0) + save_button.add_event_cb(lambda e: self.save_and_close(), lv.EVENT.CLICKED, None) + save_label = lv.label(save_button) + save_label.set_text("Save") + save_label.center() + + cancel_button = lv.button(button_cont) + cancel_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) + cancel_button.align(lv.ALIGN.BOTTOM_MID, 0, 0) + cancel_button.add_event_cb(lambda e: self.finish(), lv.EVENT.CLICKED, None) + cancel_label = lv.label(cancel_button) + cancel_label.set_text("Cancel") + cancel_label.center() + + erase_button = lv.button(button_cont) + erase_button.set_size(mpos.ui.pct_of_display_width(25), lv.SIZE_CONTENT) + erase_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0) + erase_button.add_event_cb(lambda e: self.erase_and_close(), lv.EVENT.CLICKED, None) + erase_label = lv.label(erase_button) + erase_label.set_text("Erase") + erase_label.center() + def create_basic_tab(self, tab, prefs): """Create Basic settings tab.""" @@ -869,6 +907,8 @@ class CameraSettingsActivity(Activity): special_effect, "special_effect") self.ui_controls["special_effect"] = dropdown + self.add_buttons(tab) + def create_advanced_tab(self, tab, prefs): """Create Advanced settings tab.""" #tab.set_scrollbar_mode(lv.SCROLLBAR_MODE.AUTO) @@ -979,6 +1019,8 @@ class CameraSettingsActivity(Activity): checkbox, cont = self.create_checkbox(tab, "AWB Gain", awb_gain, "awb_gain") self.ui_controls["awb_gain"] = checkbox + self.add_buttons(tab) + def create_expert_tab(self, tab, prefs): """Create Expert settings tab.""" #tab.set_scrollbar_mode(lv.SCROLLBAR_MODE.AUTO) @@ -1051,11 +1093,64 @@ class CameraSettingsActivity(Activity): checkbox, cont = self.create_checkbox(tab, "Lens Correction", lenc, "lenc") self.ui_controls["lenc"] = checkbox + self.add_buttons(tab) + def create_raw_tab(self, tab, prefs): - startX = prefs.get_int("startX", 0) + tab.set_flex_flow(lv.FLEX_FLOW.COLUMN) + tab.set_style_pad_all(0, 0) + + # This would be nice but does not provide adequate resolution: #startX, label, cont = self.create_slider(tab, "startX", 0, 2844, startX, "startX") + + startX = prefs.get_int("startX", self.startX_default) textarea, cont = self.create_textarea(tab, "startX", 0, 2844, startX, "startX") - self.ui_controls["startX"] = startX + self.ui_controls["startX"] = textarea + + startY = prefs.get_int("startY", self.startY_default) + textarea, cont = self.create_textarea(tab, "startY", 0, 2844, startY, "startY") + self.ui_controls["startY"] = textarea + + endX = prefs.get_int("endX", self.endX_default) + textarea, cont = self.create_textarea(tab, "endX", 0, 2844, endX, "endX") + self.ui_controls["endX"] = textarea + + endY = prefs.get_int("endY", self.endY_default) + textarea, cont = self.create_textarea(tab, "endY", 0, 2844, endY, "endY") + self.ui_controls["endY"] = textarea + + offsetX = prefs.get_int("offsetX", self.offsetX_default) + textarea, cont = self.create_textarea(tab, "offsetX", 0, 2844, offsetX, "offsetX") + self.ui_controls["offsetX"] = textarea + + offsetY = prefs.get_int("offsetY", self.offsetY_default) + textarea, cont = self.create_textarea(tab, "offsetY", 0, 2844, offsetY, "offsetY") + self.ui_controls["offsetY"] = textarea + + totalX = prefs.get_int("totalX", self.totalX_default) + textarea, cont = self.create_textarea(tab, "totalX", 0, 2844, totalX, "totalX") + self.ui_controls["totalX"] = textarea + + totalY = prefs.get_int("totalY", self.totalY_default) + textarea, cont = self.create_textarea(tab, "totalY", 0, 2844, totalY, "totalY") + self.ui_controls["totalY"] = textarea + + outputX = prefs.get_int("outputX", self.outputX_default) + textarea, cont = self.create_textarea(tab, "outputX", 0, 2844, outputX, "outputX") + self.ui_controls["outputX"] = textarea + + outputY = prefs.get_int("outputY", self.outputY_default) + textarea, cont = self.create_textarea(tab, "outputY", 0, 2844, outputY, "outputY") + self.ui_controls["outputY"] = textarea + + scale = prefs.get_bool("scale", self.scale_default) + checkbox, cont = self.create_checkbox(tab, "Scale?", scale, "scale") + self.ui_controls["scale"] = checkbox + + binning = prefs.get_bool("binning", self.binning_default) + checkbox, cont = self.create_checkbox(tab, "Binning?", binning, "binning") + self.ui_controls["binning"] = checkbox + + self.add_buttons(tab) def erase_and_close(self): SharedPreferences("com.micropythonos.camera").edit().remove_all().commit() @@ -1069,6 +1164,7 @@ class CameraSettingsActivity(Activity): # Save all UI control values for pref_key, control in self.ui_controls.items(): + print(f"saving {pref_key} with {control}") control_id = id(control) metadata = self.control_metadata.get(control_id, {}) @@ -1079,8 +1175,11 @@ class CameraSettingsActivity(Activity): is_checked = control.get_state() & lv.STATE.CHECKED editor.put_bool(pref_key, bool(is_checked)) elif isinstance(control, lv.textarea): - value = int(control.get_value()) - editor.put_int(pref_key, value) + try: + value = int(control.get_text()) + editor.put_int(pref_key, value) + except Exception as e: + print(f"Error while trying to save {pref_key}: {e}") elif isinstance(control, lv.dropdown): selected_idx = control.get_selected() option_values = metadata.get("option_values", [])