Skip to content

feat: Export XBM Image file #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: main
Choose a base branch
from

Conversation

Vishveshwara
Copy link
Contributor

@Vishveshwara Vishveshwara commented Jul 2, 2025

Fixes #67

Summary by Sourcery

Implement XBM export capabilities and custom e-paper display configuration

New Features:

  • Enable exporting processed images to XBM files using a new XbmEncoder utility and FileSaver integration
  • Introduce ConfigurableEpd class and a custom dialog for users to specify e-paper width, height, and color palette
  • Add export-only mode in ImageEditor with a dedicated “Export XBM” workflow

Enhancements:

  • Refactor MovableBackgroundImageExample to calculate canvas dimensions dynamically and load resized backgrounds asynchronously
  • Improve ImageList layout with aspect ratio constraints and support dynamic filter names for ConfigurableEpd
  • Extend ImageProcessing with custom palette-based dithering methods and add color-plane extraction in Epd

Chores:

  • Enable OnBackInvokedCallback in AndroidManifest to support modern back navigation

Copy link
Contributor

sourcery-ai bot commented Jul 2, 2025

Reviewer's Guide

This PR implements XBM file export by adding an encoder and file-saver integration, introduces a configurable EPD workflow for custom dimensions and color palettes (complete with UI dialog and dynamic dithering), refactors the movable background editor to compute canvas sizing and load images in memory, and updates various UI components and configuration to support these features.

Sequence diagram for XBM export process

sequenceDiagram
    actor User
    participant ImageEditor
    participant XbmEncoder
    participant FileSaver
    participant ScaffoldMessenger
    User->>ImageEditor: Clicks 'Export XBM'
    ImageEditor->>ScaffoldMessenger: Show 'Exporting XBM files...'
    loop For each non-white color
      ImageEditor->>ImageEditor: extractColorPlaneAsImage(color, baseImage)
      ImageEditor->>XbmEncoder: encode(colorPlaneImage, variableName)
      XbmEncoder-->>ImageEditor: XBM string
      ImageEditor->>FileSaver: saveFile(name, bytes, ext, mimeType)
    end
    ImageEditor->>ScaffoldMessenger: Show success/failure message
Loading

ER diagram for Epd and ConfigurableEpd data structure changes

erDiagram
    EPD ||--o{ CONFIGURABLE_EPD : extends
    CONFIGURABLE_EPD {
      int width
      int height
      string name
      list colors
      list namedProcessingMethods
    }
    NAMED_IMAGE_FILTER {
      function filter
      string name
    }
    CONFIGURABLE_EPD ||--o{ NAMED_IMAGE_FILTER : has
    EPD {
      int width
      int height
      string name
      list colors
    }
Loading

Class diagram for ConfigurableEpd and XbmEncoder

classDiagram
    class Epd {
      <<abstract>>
      int width
      int height
      String name
      List<Color> colors
      String modelId
      String imgPath
      Driver controller
      List<Function> processingMethods
      extractColorPlaneAsImage(Color, img.Image)
    }
    class ConfigurableEpd {
      int width
      int height
      String name
      List<Color> colors
      List<NamedImageFilter> namedProcessingMethods
      List<Function> processingMethods
      List<String> processingMethodNames
      _addProcessingMethods()
      _createDynamicPalette()
    }
    class NamedImageFilter {
      Function(img.Image) filter
      String name
    }
    class XbmEncoder {
      static String encode(img.Image, String)
    }
    Epd <|-- ConfigurableEpd
    ConfigurableEpd "1" *-- "*" NamedImageFilter
Loading

File-Level Changes

Change Details Files
Implement XBM export functionality
  • Add XBM encoder utility to generate C-style XBM string
  • Integrate FileSaver to write .xbm files from monochrome planes
  • Add export logic (_exportXbmFiles) with SnackBar feedback
  • Toggle button behavior via isExportOnly flag
lib/view/image_editor.dart
lib/util/xbm_encoder.dart
Add configurable EPD for custom dimensions and palettes
  • Create ConfigurableEpd class with dynamic palette and processing methods
  • Add dialog UI (_CustomEpdDialog) for width/height/colors selection
  • Extend display selection screen to invoke configuration and replace EPD entry
  • Update ImageList to use configurable filter names and pass dimensions
lib/util/epd/configurable_editor.dart
lib/view/display_selection_screen.dart
lib/view/widget/image_list.dart
Refactor movable background editor for dynamic sizing and memory loading
  • Inject width/height into MovableBackgroundImageExample
  • Compute canvas dimensions based on screen constraints
  • Remove static transparent image code and use ui.PictureRecorder cleanup
  • Load and resize board image in memory via FutureBuilder
  • Switch ProImageEditor.asset to ProImageEditor.memory
lib/pro_image_editor/features/movable_background_image.dart
Support custom dithering and color-plane extraction
  • Add custom palette-based dithering methods for configurable EPD
  • Expose extractColorPlaneAsImage in Epd to unify plane extraction
lib/util/image_processing/image_processing.dart
lib/util/epd/epd.dart
Improve UI layout and styling for image lists
  • Wrap preview in ConstrainedBox and AspectRatio to honor aspect ratios
  • Adjust filter card container height, border styling and shadow opacity
  • Ensure high filterQuality and correct antiAlias flags
lib/view/widget/image_list.dart
Enable Android onBackInvoked callback
  • Set android:enableOnBackInvokedCallback="true" in AndroidManifest
android/app/src/main/AndroidManifest.xml

Assessment against linked issues

Issue Objective Addressed Explanation
#67 Provide a tool for Arduino users to automate the process of preparing graphics for e-ink displays.
#67 Export images in a format suitable for Arduino, specifically XBM.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Vishveshwara - I've reviewed your changes and found some issues that need to be addressed.

  • This PR bundles dynamic canvas sizing, configurable EPD support, XBM export, and UI tweaks all in one—consider splitting into smaller focused PRs to make review and future maintenance easier.
  • The image-flipping and export logic is duplicated between _exportXbmFiles and the transfer button handler—extract the flipping/apply calls into a single helper to avoid redundancy.
  • You’re recalculating canvas dimensions on every build; consider moving _calculateCanvasDimensions into didChangeDependencies or using LayoutBuilder constraints so it only runs when the size actually changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- This PR bundles dynamic canvas sizing, configurable EPD support, XBM export, and UI tweaks all in one—consider splitting into smaller focused PRs to make review and future maintenance easier.
- The image-flipping and export logic is duplicated between `_exportXbmFiles` and the transfer button handler—extract the flipping/apply calls into a single helper to avoid redundancy.
- You’re recalculating canvas dimensions on every build; consider moving `_calculateCanvasDimensions` into `didChangeDependencies` or using `LayoutBuilder` constraints so it only runs when the size actually changes.

## Individual Comments

### Comment 1
<location> `lib/view/widget/image_list.dart:207` </location>
<code_context>
               ? [
                   BoxShadow(
-                    color: colorPrimary.withValues(alpha: .2),
+                    color: colorPrimary.withValues(alpha: .4),
                     blurRadius: 8,
                     offset: const Offset(0, 4),
</code_context>

<issue_to_address>
The method 'withValues' does not exist on Color; likely a typo.

Use 'withOpacity' or 'withAlpha' to set the alpha channel, as 'withValues' will cause a runtime error.
</issue_to_address>

### Comment 2
<location> `lib/util/xbm_encoder.dart:33` </location>
<code_context>
+          // Ensure we don't read past the image's width
+          if (x < width) {
+            final pixel = image.getPixel(x, y);
+            // In a monochrome image, a pixel's "on" state is typically white.
+            // We check the red channel, but luminance would also work.
+            if (pixel.r > 128) {
+              // Set the corresponding bit in the byte.
+              // XBM bits are typically ordered from right to left.
</code_context>

<issue_to_address>
XBM 'on' bit is typically black, not white.

The current logic sets bits for white pixels, which may invert the intended output. Please invert the condition so bits are set for black ('on') pixels, as per XBM convention.
</issue_to_address>

### Comment 3
<location> `lib/view/display_selection_screen.dart:33` </location>
<code_context>
   int selectedIndex = -1;

+  void _showConfigurableDialog() async {
+    final configurable = displays.last as ConfigurableEpd;
+    final result = await showDialog<_CustomEpdConfig>(
+      context: context,
</code_context>

<issue_to_address>
Direct cast to ConfigurableEpd may throw if displays is modified.

Consider adding a type check before casting or using a method to reliably identify the ConfigurableEpd instance.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Vishveshwara
Copy link
Contributor Author

@kienvo I have it working now, can you please check the xbm images in this folder
https://drive.google.com/drive/folders/1Z93XLLzAx8WRhrMnS4tcQ-uqlrRcNIG0?usp=drive_link

@Vishveshwara Vishveshwara changed the title WIP: Export XBM Image file feat: Export XBM Image file Jul 7, 2025
@Vishveshwara Vishveshwara requested review from kienvo and Dhruv1797 July 7, 2025 13:02
@@ -2,7 +2,9 @@
<application
android:label="magic_epaper_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is added for the File_saver module to work

@Vishveshwara
Copy link
Contributor Author

xbm.vid.mp4

WhatsApp Image 2025-07-08 at 12 01 07_b4d3c232

@hpdang
Copy link
Member

hpdang commented Jul 9, 2025

@Dhruv1797 please review this

@Vishveshwara
Copy link
Contributor Author

xbm.final.mp4

@Vishveshwara
Copy link
Contributor Author

xbm.final.mp4

@mariobehling I have added the presets like you have asked in the meet

Copy link
Member

@kienvo kienvo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really want a full picture when developing a epaper application and I think others will do the same. Suppose I want to change a part of the screen so how do I generate bitmap code for that part of the screen? and why do I need presets for full screen?.

@Vishveshwara
Copy link
Contributor Author

Vishveshwara commented Jul 11, 2025

I don't really want a full picture when developing a epaper application and I think others will do the same. Suppose I want to change a part of the screen so how do I generate bitmap code for that part of the screen? and why do I need presets for full screen?.

there is a custom option in the end of the presets which will allow you to select the resolution and the colors you want , please check from 13th second of the video. mario had wanted the presets so that people who are using this app to create the xbm images don't need to know their resolution exactly

@Vishveshwara
Copy link
Contributor Author

@kienvo please mention if there are any problems

Copy link
Member

@kienvo kienvo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the UI so that users can select the location to save the files? And create a new folder, then export the files to it would be nice if possible.

@Vishveshwara
Copy link
Contributor Author

@kienvo i have added the path in InternalStorage/MagicEpaper/XBM

xbm.ui.and.path.fixed.mp4

@hpdang
Copy link
Member

hpdang commented Jul 21, 2025

@Vishveshwara please resolve conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exporting processed images
4 participants