Cody Tolene 2 лет назад
Родитель
Сommit
f5d85febc8

+ 4 - 4
src-fap/camera_suite.c

@@ -13,7 +13,7 @@ void camera_suite_tick_event_callback(void* context) {
     scene_manager_handle_tick_event(app->scene_manager);
 }
 
-//leave app if back button pressed
+// Leave app if back button pressed.
 bool camera_suite_navigation_event_callback(void* context) {
     furi_assert(context);
     CameraSuite* app = context;
@@ -25,10 +25,10 @@ CameraSuite* camera_suite_app_alloc() {
     app->gui = furi_record_open(RECORD_GUI);
     app->notification = furi_record_open(RECORD_NOTIFICATION);
 
-    //Turn backlight on, believe me this makes testing your app easier
+    // Turn backlight on.
     notification_message(app->notification, &sequence_display_backlight_on);
 
-    //Scene additions
+    // Scene additions
     app->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(app->view_dispatcher);
 
@@ -92,9 +92,9 @@ void camera_suite_app_free(CameraSuite* app) {
     scene_manager_free(app->scene_manager);
 
     // View Dispatcher
+    view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdStartscreen);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdMenu);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera);
-    view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdCamera);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdGuide);
     view_dispatcher_remove_view(app->view_dispatcher, CameraSuiteViewIdSettings);
     submenu_free(app->submenu);

+ 1 - 1
src-fap/camera_suite.h

@@ -27,7 +27,7 @@ typedef struct {
     SceneManager* scene_manager;
     VariableItemList* variable_item_list;
     CameraSuiteViewStart* camera_suite_view_start;
-    CameraSuiteViewStyle1* camera_suite_view_camera;
+    CameraSuiteViewCamera* camera_suite_view_camera;
     CameraSuiteViewGuide* camera_suite_view_guide;
     uint32_t orientation;
     uint32_t haptic;

+ 6 - 6
src-fap/helpers/camera_suite_custom_event.h

@@ -9,12 +9,12 @@ typedef enum {
     CameraSuiteCustomEventStartOk,
     CameraSuiteCustomEventStartBack,
     // Scene events: Camera
-    CameraSuiteCustomEventSceneStyle1Up,
-    CameraSuiteCustomEventSceneStyle1Down,
-    CameraSuiteCustomEventSceneStyle1Left,
-    CameraSuiteCustomEventSceneStyle1Right,
-    CameraSuiteCustomEventSceneStyle1Ok,
-    CameraSuiteCustomEventSceneStyle1Back,
+    CameraSuiteCustomEventSceneCameraUp,
+    CameraSuiteCustomEventSceneCameraDown,
+    CameraSuiteCustomEventSceneCameraLeft,
+    CameraSuiteCustomEventSceneCameraRight,
+    CameraSuiteCustomEventSceneCameraOk,
+    CameraSuiteCustomEventSceneCameraBack,
     // Scene events: Guide
     CameraSuiteCustomEventSceneGuideUp,
     CameraSuiteCustomEventSceneGuideDown,

+ 7 - 7
src-fap/scenes/camera_suite_scene_camera.c

@@ -2,7 +2,7 @@
 #include "../helpers/camera_suite_custom_event.h"
 #include "../views/camera_suite_view_camera.h"
 
-static void camera_suite_view_camera_callback(CameraSuiteCustomEvent event, void* context) {
+void camera_suite_view_camera_callback(CameraSuiteCustomEvent event, void* context) {
     furi_assert(context);
     CameraSuite* app = context;
     view_dispatcher_send_custom_event(app->view_dispatcher, event);
@@ -22,14 +22,14 @@ bool camera_suite_scene_camera_on_event(void* context, SceneManagerEvent event)
 
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
-        case CameraSuiteCustomEventSceneStyle1Left:
-        case CameraSuiteCustomEventSceneStyle1Right:
-        case CameraSuiteCustomEventSceneStyle1Up:
-        case CameraSuiteCustomEventSceneStyle1Down:
-        case CameraSuiteCustomEventSceneStyle1Ok:
+        case CameraSuiteCustomEventSceneCameraLeft:
+        case CameraSuiteCustomEventSceneCameraRight:
+        case CameraSuiteCustomEventSceneCameraUp:
+        case CameraSuiteCustomEventSceneCameraDown:
+        case CameraSuiteCustomEventSceneCameraOk:
             // Do nothing.
             break;
-        case CameraSuiteCustomEventSceneStyle1Back:
+        case CameraSuiteCustomEventSceneCameraBack:
             notification_message(app->notification, &sequence_reset_red);
             notification_message(app->notification, &sequence_reset_green);
             notification_message(app->notification, &sequence_reset_blue);

+ 4 - 4
src-fap/scenes/camera_suite_scene_menu.c

@@ -2,7 +2,7 @@
 
 enum SubmenuIndex {
     /** Camera. */
-    SubmenuIndexSceneStyle1 = 10,
+    SubmenuIndexSceneCamera = 10,
     /** Guide/how-to. */
     SubmenuIndexGuide,
     /** Settings menu. */
@@ -20,7 +20,7 @@ void camera_suite_scene_menu_on_enter(void* context) {
     submenu_add_item(
         app->submenu,
         "Open Camera",
-        SubmenuIndexSceneStyle1,
+        SubmenuIndexSceneCamera,
         camera_suite_scene_menu_submenu_callback,
         app);
     submenu_add_item(
@@ -47,9 +47,9 @@ bool camera_suite_scene_menu_on_event(void* context, SceneManagerEvent event) {
         view_dispatcher_stop(app->view_dispatcher);
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubmenuIndexSceneStyle1) {
+        if(event.event == SubmenuIndexSceneCamera) {
             scene_manager_set_scene_state(
-                app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneStyle1);
+                app->scene_manager, CameraSuiteSceneMenu, SubmenuIndexSceneCamera);
             scene_manager_next_scene(app->scene_manager, CameraSuiteSceneCamera);
             return true;
         } else if(event.event == SubmenuIndexGuide) {

+ 28 - 34
src-fap/views/camera_suite_view_camera.c

@@ -8,14 +8,10 @@
 #include "../helpers/camera_suite_speaker.h"
 #include "../helpers/camera_suite_led.h"
 
-static CameraSuiteViewStyle1* current_instance = NULL;
-// Dithering type:
-//    0 = Floyd Steinberg (default)
-//    1 = Atkinson
-static int current_dithering = 0;
-
-struct CameraSuiteViewStyle1 {
-    CameraSuiteViewStyle1Callback callback;
+static CameraSuiteViewCamera* current_instance = NULL;
+
+struct CameraSuiteViewCamera {
+    CameraSuiteViewCameraCallback callback;
     FuriStreamBuffer* rx_stream;
     FuriThread* worker_thread;
     View* view;
@@ -23,8 +19,8 @@ struct CameraSuiteViewStyle1 {
 };
 
 void camera_suite_view_camera_set_callback(
-    CameraSuiteViewStyle1* instance,
-    CameraSuiteViewStyle1Callback callback,
+    CameraSuiteViewCamera* instance,
+    CameraSuiteViewCameraCallback callback,
     void* context) {
     furi_assert(instance);
     furi_assert(callback);
@@ -115,7 +111,7 @@ static void camera_suite_view_camera_model_init(UartDumpModel* const model) {
 
 static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
     furi_assert(context);
-    CameraSuiteViewStyle1* instance = context;
+    CameraSuiteViewCamera* instance = context;
     if(event->type == InputTypeRelease) {
         switch(event->key) {
         default: // Stop all sounds, reset the LED.
@@ -144,7 +140,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                 UartDumpModel * model,
                 {
                     UNUSED(model);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Back, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraBack, instance->context);
                 },
                 true);
             break;
@@ -159,7 +155,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Left, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraLeft, instance->context);
                 },
                 true);
             break;
@@ -174,7 +170,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Right, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraRight, instance->context);
                 },
                 true);
             break;
@@ -189,7 +185,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Up, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraUp, instance->context);
                 },
                 true);
             break;
@@ -204,18 +200,13 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Down, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraDown, instance->context);
                 },
                 true);
             break;
         case InputKeyOk:
-            if(current_dithering == 0) {
-                data[0] = 'd'; // Update to Floyd Steinberg dithering.
-                current_dithering = 1;
-            } else {
-                data[0] = 'D'; // Update to Atkinson dithering.
-                current_dithering = 0;
-            }
+            // Switch dithering types.
+            data[0] = 'D';
             with_view_model(
                 instance->view,
                 UartDumpModel * model,
@@ -224,7 +215,7 @@ static bool camera_suite_view_camera_input(InputEvent* event, void* context) {
                     camera_suite_play_happy_bump(instance->context);
                     camera_suite_play_input_sound(instance->context);
                     camera_suite_led_set_rgb(instance->context, 0, 0, 255);
-                    instance->callback(CameraSuiteCustomEventSceneStyle1Ok, instance->context);
+                    instance->callback(CameraSuiteCustomEventSceneCameraOk, instance->context);
                 },
                 true);
             break;
@@ -245,8 +236,8 @@ static void camera_suite_view_camera_enter(void* context) {
     // Check `context` for null. If it is null, abort program, else continue.
     furi_assert(context);
 
-    // Cast `context` to `CameraSuiteViewStyle1*` and store it in `instance`.
-    CameraSuiteViewStyle1* instance = (CameraSuiteViewStyle1*)context;
+    // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
+    CameraSuiteViewCamera* instance = (CameraSuiteViewCamera*)context;
 
     // Assign the current instance to the global variable
     current_instance = instance;
@@ -267,8 +258,8 @@ static void camera_on_irq_cb(UartIrqEvent uartIrqEvent, uint8_t data, void* cont
     // Check `context` for null. If it is null, abort program, else continue.
     furi_assert(context);
 
-    // Cast `context` to `CameraSuiteViewStyle1*` and store it in `instance`.
-    CameraSuiteViewStyle1* instance = context;
+    // Cast `context` to `CameraSuiteViewCamera*` and store it in `instance`.
+    CameraSuiteViewCamera* instance = context;
 
     // If `uartIrqEvent` is `UartIrqEventRXNE`, send the data to the
     // `rx_stream` and set the `WorkerEventRx` flag.
@@ -319,7 +310,7 @@ static void process_ringbuffer(UartDumpModel* model, uint8_t byte) {
 
 static int32_t camera_worker(void* context) {
     furi_assert(context);
-    CameraSuiteViewStyle1* instance = context;
+    CameraSuiteViewCamera* instance = context;
 
     while(1) {
         uint32_t events =
@@ -348,14 +339,17 @@ static int32_t camera_worker(void* context) {
                         false);
                 }
             } while(length > 0);
+
+            with_view_model(
+                instance->view, UartDumpModel * model, { UNUSED(model); }, true);
         }
     }
 
     return 0;
 }
 
-CameraSuiteViewStyle1* camera_suite_view_camera_alloc() {
-    CameraSuiteViewStyle1* instance = malloc(sizeof(CameraSuiteViewStyle1));
+CameraSuiteViewCamera* camera_suite_view_camera_alloc() {
+    CameraSuiteViewCamera* instance = malloc(sizeof(CameraSuiteViewCamera));
 
     instance->view = view_alloc();
 
@@ -386,7 +380,7 @@ CameraSuiteViewStyle1* camera_suite_view_camera_alloc() {
     return instance;
 }
 
-void camera_suite_view_camera_free(CameraSuiteViewStyle1* instance) {
+void camera_suite_view_camera_free(CameraSuiteViewCamera* instance) {
     furi_assert(instance);
 
     with_view_model(
@@ -395,7 +389,7 @@ void camera_suite_view_camera_free(CameraSuiteViewStyle1* instance) {
     free(instance);
 }
 
-View* camera_suite_view_camera_get_view(CameraSuiteViewStyle1* instance) {
+View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* instance) {
     furi_assert(instance);
     return instance->view;
-}
+}

+ 12 - 13
src-fap/views/camera_suite_view_camera.h

@@ -16,14 +16,13 @@
 
 #pragma once
 
-#define FRAME_WIDTH 128
+#define FRAME_WIDTH 129
 #define FRAME_HEIGHT 64
 #define FRAME_BIT_DEPTH 1
-#define FRAME_BUFFER_LENGTH \
-    (FRAME_WIDTH * FRAME_HEIGHT * FRAME_BIT_DEPTH / 8) // 128*64*1 / 8 = 1024
-#define ROW_BUFFER_LENGTH (FRAME_WIDTH / 8) // 128/8 = 16
-#define RING_BUFFER_LENGTH (ROW_BUFFER_LENGTH + 3) // ROW_BUFFER_LENGTH + Header => 16 + 3 = 19
-#define LAST_ROW_INDEX (FRAME_BUFFER_LENGTH - ROW_BUFFER_LENGTH) // 1024 - 16 = 1008
+#define FRAME_BUFFER_LENGTH 1024
+#define ROW_BUFFER_LENGTH 16
+#define RING_BUFFER_LENGTH 19
+#define LAST_ROW_INDEX 1008
 
 extern const Icon I_DolphinCommon_56x48;
 
@@ -37,20 +36,20 @@ struct UartDumpModel {
     uint8_t row_ringbuffer[RING_BUFFER_LENGTH];
 };
 
-typedef struct CameraSuiteViewStyle1 CameraSuiteViewStyle1;
+typedef struct CameraSuiteViewCamera CameraSuiteViewCamera;
 
-typedef void (*CameraSuiteViewStyle1Callback)(CameraSuiteCustomEvent event, void* context);
+typedef void (*CameraSuiteViewCameraCallback)(CameraSuiteCustomEvent event, void* context);
 
 void camera_suite_view_camera_set_callback(
-    CameraSuiteViewStyle1* camera_suite_view_camera,
-    CameraSuiteViewStyle1Callback callback,
+    CameraSuiteViewCamera* camera_suite_view_camera,
+    CameraSuiteViewCameraCallback callback,
     void* context);
 
-CameraSuiteViewStyle1* camera_suite_view_camera_alloc();
+CameraSuiteViewCamera* camera_suite_view_camera_alloc();
 
-void camera_suite_view_camera_free(CameraSuiteViewStyle1* camera_suite_static);
+void camera_suite_view_camera_free(CameraSuiteViewCamera* camera_suite_static);
 
-View* camera_suite_view_camera_get_view(CameraSuiteViewStyle1* camera_suite_static);
+View* camera_suite_view_camera_get_view(CameraSuiteViewCamera* camera_suite_static);
 
 typedef enum {
     // Reserved for StreamBuffer internal event

+ 80 - 86
src-firmware/esp32_cam_uart_stream/esp32_cam_uart_stream.ino

@@ -26,19 +26,24 @@ camera_config_t config;
 void handleSerialInput();
 void initializeCamera();
 void processImage(camera_fb_t* fb);
-void ditherImage(camera_fb_t* fb, int dt);
+void ditherImage(camera_fb_t* fb);
 bool isDarkBit(uint8_t bit);
 
+// Dithering algorithm options
+enum DitheringAlgorithm {
+  FLOYD_STEINBERG,
+  JARVIS_JUDICE_NINKE,
+  STUCKI
+};
+
+// Default dithering algorithm
+DitheringAlgorithm ditherAlgorithm = FLOYD_STEINBERG;
+
 // Serial input flags
 bool disableDithering = false;
 bool invert = false;
 bool rotated = false;
 bool stopStream = false;
-// Dithering type:
-//    0 = Floyd Steinberg (default)
-//    1 = Atkinson
-int dtType = 0;
-
 
 void setup() {
   Serial.begin(230400);
@@ -46,24 +51,17 @@ void setup() {
 }
 
 void loop() {
-  handleSerialInput();
-
-  if (stopStream) {
-    return;
-  }
-
-  // Frame buffer.
-  camera_fb_t* fb = esp_camera_fb_get();
-
-  if (!fb) {
-    return;
+  if (!stopStream) {
+    // Frame buffer capture and processing
+    camera_fb_t* fb = esp_camera_fb_get();
+    if (fb) {
+      processImage(fb);
+      esp_camera_fb_return(fb);
+    }
+    delay(50);
   }
 
-  processImage(fb);
-
-  esp_camera_fb_return(fb);
-  fb = NULL;
-  delay(50);
+  handleSerialInput(); // Process serial input commands
 }
 
 void handleSerialInput() {
@@ -72,40 +70,37 @@ void handleSerialInput() {
     sensor_t* cameraSensor = esp_camera_sensor_get();
 
     switch (input) {
-      case '>': // Toggle dithering.
+      case '>': // Toggle dithering
         disableDithering = !disableDithering;
         break;
-      case '<': // Toggle invert.
+      case '<': // Toggle invert
         invert = !invert;
         break;
-      case 'B': // Add brightness.
+      case 'B': // Add brightness
         cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness + 1);
         break;
-      case 'b': // Remove brightness.
+      case 'b': // Remove brightness
         cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness - 1);
         break;
-      case 'C': // Add contrast.
+      case 'C': // Add contrast
         cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast + 1);
         break;
-      case 'c': // Remove contrast.
+      case 'c': // Remove contrast
         cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast - 1);
         break;
-      case 'D': // Use Floyd Steinberg dithering.
-        dtType = 0;
-        break;
-      case 'd': // Use Atkinson dithering.
-        dtType = 1;
+      case 'P': // TODO: Take a picture
         break;
       case 'M': // Toggle Mirror
         cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
         break;
-      case 'S': // Start stream.
+      case 'S': // Start stream
         stopStream = false;
         break;
-      case 's': // Stop stream.
+      case 's': // Stop stream
         stopStream = true;
         break;
-      default:
+      case 'D': // Change dithering algorithm.
+        ditherAlgorithm = static_cast<DitheringAlgorithm>((ditherAlgorithm + 1) % 3);
         break;
     }
   }
@@ -147,14 +142,14 @@ void initializeCamera() {
   sensor_t* s = esp_camera_sensor_get();
   s->set_contrast(s, 2);
 
-  // Set rotation (added lines)
+  // Set rotation
   s->set_vflip(s, true);  // Vertical flip
   s->set_hmirror(s, true);  // Horizontal mirror
 }
 
 void processImage(camera_fb_t* frameBuffer) {
   if (!disableDithering) {
-    ditherImage(frameBuffer, dtType);
+    ditherImage(frameBuffer);
   }
 
   uint8_t flipper_y = 0;
@@ -190,56 +185,55 @@ void processImage(camera_fb_t* frameBuffer) {
   }
 }
 
-// Dither image.
-// @param fb Frame buffer
-// @param dt Dithering type:
-//    0 = Floyd Steinberg (default)
-//    1 = Atkinson
-void ditherImage(camera_fb_t* fb, int dt) {
-  switch (dt) {
-    default:
-    case 0: // Floyd Steinberg dithering
-      for (int y = 0; y < fb->height - 1; ++y) {
-        for (int x = 1; x < fb->width - 1; ++x) {
-          int current = y * fb->width + x;
-          // Convert to black or white
-          uint8_t oldpixel = fb->buf[current];
-          uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
-          fb->buf[current] = newpixel;
-          // Compute quantization error
-          int quant_error = oldpixel - newpixel;
-          // Propagate the error
-          fb->buf[current + 1] += quant_error * 7 / 16;
+void ditherImage(camera_fb_t* fb) {
+  for (uint8_t y = 0; y < fb->height; ++y) {
+    for (uint8_t x = 0; x < fb->width; ++x) {
+      size_t current = (y * fb->width) + x;
+      uint8_t oldpixel = fb->buf[current];
+      uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
+      fb->buf[current] = newpixel;
+      int8_t quant_error = oldpixel - newpixel;
+
+      // Apply error diffusion based on the selected algorithm
+      switch (ditherAlgorithm) {
+        case JARVIS_JUDICE_NINKE:
+          fb->buf[(y * fb->width) + x + 1] += quant_error * 7 / 48;
+          fb->buf[(y * fb->width) + x + 2] += quant_error * 5 / 48;
+          fb->buf[(y + 1) * fb->width + x - 2] += quant_error * 3 / 48;
+          fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 5 / 48;
+          fb->buf[(y + 1) * fb->width + x] += quant_error * 7 / 48;
+          fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 5 / 48;
+          fb->buf[(y + 1) * fb->width + x + 2] += quant_error * 3 / 48;
+          fb->buf[(y + 2) * fb->width + x - 2] += quant_error * 1 / 48;
+          fb->buf[(y + 2) * fb->width + x - 1] += quant_error * 3 / 48;
+          fb->buf[(y + 2) * fb->width + x] += quant_error * 5 / 48;
+          fb->buf[(y + 2) * fb->width + x + 1] += quant_error * 3 / 48;
+          fb->buf[(y + 2) * fb->width + x + 2] += quant_error * 1 / 48;
+          break;
+        case STUCKI:
+          fb->buf[(y * fb->width) + x + 1] += quant_error * 8 / 42;
+          fb->buf[(y * fb->width) + x + 2] += quant_error * 4 / 42;
+          fb->buf[(y + 1) * fb->width + x - 2] += quant_error * 2 / 42;
+          fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 4 / 42;
+          fb->buf[(y + 1) * fb->width + x] += quant_error * 8 / 42;
+          fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 4 / 42;
+          fb->buf[(y + 1) * fb->width + x + 2] += quant_error * 2 / 42;
+          fb->buf[(y + 2) * fb->width + x - 2] += quant_error * 1 / 42;
+          fb->buf[(y + 2) * fb->width + x - 1] += quant_error * 2 / 42;
+          fb->buf[(y + 2) * fb->width + x] += quant_error * 4 / 42;
+          fb->buf[(y + 2) * fb->width + x + 1] += quant_error * 2 / 42;
+          fb->buf[(y + 2) * fb->width + x + 2] += quant_error * 1 / 42;
+          break;
+        case FLOYD_STEINBERG:
+        default:
+          // Default to Floyd-Steinberg dithering if an invalid algorithm is selected
+          fb->buf[(y * fb->width) + x + 1] += quant_error * 7 / 16;
           fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 3 / 16;
           fb->buf[(y + 1) * fb->width + x] += quant_error * 5 / 16;
-          fb->buf[(y + 1) * fb->width + x + 1] += quant_error / 16;
-        }
+          fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 1 / 16;
+          break;
       }
-      break;
-    case 1: // Atkinson dithering
-      for (int y = 0; y < fb->height; ++y) {
-        for (int x = 0; x < fb->width; ++x) {
-          int current = y * fb->width + x;
-          uint8_t oldpixel = fb->buf[current];
-          uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
-          fb->buf[current] = newpixel;
-          int quant_error = oldpixel - newpixel;
-
-          if (x + 1 < fb->width)
-            fb->buf[current + 1] += quant_error * 1 / 8;
-          if (x + 2 < fb->width)
-            fb->buf[current + 2] += quant_error * 1 / 8;
-          if (x > 0 && y + 1 < fb->height)
-            fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 1 / 8;
-          if (y + 1 < fb->height)
-            fb->buf[(y + 1) * fb->width + x] += quant_error * 1 / 8;
-          if (y + 1 < fb->height && x + 1 < fb->width)
-            fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 1 / 8;
-          if (y + 2 < fb->height)
-            fb->buf[(y + 2) * fb->width + x] += quant_error * 1 / 8;
-        }
-      }
-      break;
+    }
   }
 }
 
@@ -250,4 +244,4 @@ bool isDarkBit(uint8_t bit) {
   } else {
     return bit < 128;
   }
-}
+}