Skip to content

Conversation

Vishveshwara
Copy link
Contributor

@Vishveshwara Vishveshwara commented Jun 18, 2025

Fixes #60

Screen Recording:

color.adjust.feature.mp4

Issues:

  • Doesn't work for Black/white images as it is using black/white quantizer. This can be fixed by converting them to use the remap quantizer

I would like someone to review this first , and suggest if it is a viable solution , and then I can update this PR

Summary by Sourcery

Implement a color adjustment feature by introducing a provider-driven weight model, a slider-based UI for per-color intensity control, and integrating those weights into the image processing pipeline’s quantizer while also offering manual editing via ProImageEditor.

New Features:

  • Add ColorAdjustmentProvider to manage per-color intensity weights
  • Introduce 'Adjust Colors' bottom sheet with sliders to control individual color contributions
  • Add an 'Adjust' button integrating ProImageEditor for manual image edits prior to color adjustment

Enhancements:

  • Refactor image processing pipeline and Epd interface to pass color weights through RemapQuantizer
  • Modify RemapQuantizer to factor in adjustable weights when mapping pixels to palette colors
  • Reset color weights on new imports and after manual edits to ensure consistent baseline

Copy link
Contributor

sourcery-ai bot commented Jun 18, 2025

Reviewer's Guide

Adds a per-palette color intensity adjustment feature by introducing a new provider for managing color weights, wiring it through the widget tree, extending the processing pipeline (processImages, Epd and quantizers) to accept and apply those weights, enhancing the RemapQuantizer’s distance calculation, and providing a UI modal with sliders to tweak and apply weights in the ImageEditor.

Sequence diagram for user adjusting color intensities

sequenceDiagram
  actor User
  participant ImageEditor
  participant BottomActionMenu
  participant ColorAdjustmentSliders
  participant ColorAdjustmentProvider
  participant processImages
  participant RemapQuantizer

  User->>BottomActionMenu: Tap 'Adjust Colors'
  BottomActionMenu->>ColorAdjustmentSliders: Show modal with sliders
  User->>ColorAdjustmentSliders: Adjust sliders, tap 'Apply'
  ColorAdjustmentSliders->>ColorAdjustmentProvider: updateWeights(newWeights)
  ColorAdjustmentProvider-->>ImageEditor: Notifies listeners
  ImageEditor->>processImages: processImages(..., weights)
  processImages->>RemapQuantizer: RemapQuantizer(..., weights)
  RemapQuantizer-->>processImages: Processed image
  processImages-->>ImageEditor: Updated images
Loading

Class diagram for ColorAdjustmentProvider and integration

classDiagram
  class ColorAdjustmentProvider {
    - Map<Color, double> _weights
    + Map<Color, double> get weights
    + void resetWeights(List<Color> colors)
    + void updateWeights(Map<Color, double> newWeights)
  }
  class ImageEditor {
    - Map<Color, double> _currentWeights
    + void _updateProcessedImages(img.Image? sourceImage, Map<Color, double> weights)
  }
  class BottomActionMenu {
    + void _showColorAdjustmentSheet(BuildContext context)
  }
  class ColorAdjustmentSliders {
    - List<Color> colors
  }
  ColorAdjustmentProvider <|.. ImageEditor : used by
  ImageEditor o-- BottomActionMenu : has
  BottomActionMenu o-- ColorAdjustmentSliders : shows
Loading

File-Level Changes

Change Details Files
Introduce ColorAdjustmentProvider for managing per-color weights
  • New ChangeNotifier with resetWeights and updateWeights methods
  • Registered provider in main.dart’s MultiProvider
  • Imported and injected provider in ImageEditor
lib/provider/color_adjustment_provider.dart
lib/main.dart
lib/view/image_editor.dart
Extend processing pipeline to propagate weights
  • Updated processImages to accept a weights map
  • Changed Epd.processingMethods signature to include weights
  • Modified processImages calls to pass weights to each method
lib/util/image_editor_utils.dart
lib/util/epd/epd.dart
lib/util/image_processing/image_processing.dart
Enhance RemapQuantizer to factor in color weights
  • Added weights parameter to constructor with default
  • Adjusted color-distance calculation to divide by weight and handle zero/negative
  • Updated instantiations of RemapQuantizer to supply weights
lib/util/image_processing/remap_quantizer.dart
lib/util/image_processing/image_processing.dart
Add UI and state logic for color adjustment sliders
  • Added “Adjust Colors” button in BottomActionMenu opening ColorAdjustmentSliders modal
  • Created ColorAdjustmentSliders widget with sliders, Reset and Apply controls
  • Tracked and compared current weights in ImageEditor state, reset on import/re‐edit
lib/view/image_editor.dart

Assessment against linked issues

Issue Objective Addressed Explanation
#60 Add sliders to adjust the threshold for each color (Black, White, Red) on a display.
#60 Control the conversion of colors based on the adjusted thresholds (e.g., Magenta -> Red with black parts based on threshold adjustments).

Possibly linked issues


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 - here's some feedback:

  • Avoid comparing Map<Color, double> by calling toString()—instead implement a proper deep‐equality check or maintain a hash/version so you can tell when weights actually change.
  • In RemapQuantizer, building a new Color per pixel to look up weights is expensive—use integer channel values (e.g. the 32-bit color int) or a palette‐indexed weight list for O(1) access without object allocation.
  • You’re calling resetWeights(_colors) in multiple callbacks (initState, import, edit, etc.); centralize initialization (e.g. default provider state or a single listener) to avoid duplication and reduce boilerplate.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Avoid comparing `Map<Color, double>` by calling `toString()`—instead implement a proper deep‐equality check or maintain a hash/version so you can tell when weights actually change.
- In `RemapQuantizer`, building a new `Color` per pixel to look up weights is expensive—use integer channel values (e.g. the 32-bit color int) or a palette‐indexed weight list for O(1) access without object allocation.
- You’re calling `resetWeights(_colors)` in multiple callbacks (initState, import, edit, etc.); centralize initialization (e.g. default provider state or a single listener) to avoid duplication and reduce boilerplate.

## Individual Comments

### Comment 1
<location> `lib/view/image_editor.dart:110` </location>
<code_context>
-    _updateProcessedImages(imgLoader.image);
+    var colorAdjuster = context.watch<ColorAdjustmentProvider>();
+
+    if (imgLoader.image != null && colorAdjuster.weights.isEmpty) {
+      colorAdjuster.resetWeights(_colors);
+    }
+
</code_context>

<issue_to_address>
Possible race condition when resetting color weights.

Since the provider's state may not update synchronously, this logic could trigger multiple resets and cause UI issues. Move the reset to a more suitable lifecycle method or ensure the provider updates before the next build.
</issue_to_address>

### Comment 2
<location> `lib/provider/color_adjustment_provider.dart:8` </location>
<code_context>
+
+  Map<Color, double> get weights => _weights;
+
+  void resetWeights(List<Color> colors) {
+    _weights = {for (var color in colors) color: 1.0};
+  }
+
</code_context>

<issue_to_address>
resetWeights does not notify listeners.

Since notifyListeners() is not called after updating _weights, UI components depending on this data may not refresh. Please add notifyListeners() after resetting the weights.
</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.

Comment on lines +110 to +111
if (imgLoader.image != null && colorAdjuster.weights.isEmpty) {
colorAdjuster.resetWeights(_colors);
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Possible race condition when resetting color weights.

Since the provider's state may not update synchronously, this logic could trigger multiple resets and cause UI issues. Move the reset to a more suitable lifecycle method or ensure the provider updates before the next build.

Comment on lines +8 to +9
void resetWeights(List<Color> colors) {
_weights = {for (var color in colors) color: 1.0};
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): resetWeights does not notify listeners.

Since notifyListeners() is not called after updating _weights, UI components depending on this data may not refresh. Please add notifyListeners() after resetting the weights.

@Vishveshwara
Copy link
Contributor Author

@kienvo can you please review the logic for adjusting the colors via the remap quantizer?

@Vishveshwara
Copy link
Contributor Author

@kienvo @AsCress @Jhalakupadhyay Can you please review this ? is this approach good , since it is working through the quantizer .

@kienvo
Copy link
Member

kienvo commented Jun 19, 2025

Modifying the original image would be a better and simpler approach. https://github.com/brendan-duncan/image/blob/main/doc/filters.md

And something like real-time adjustment would be good, but I'm not sure if Flutter can be able to do this.

@Vishveshwara
Copy link
Contributor Author

Vishveshwara commented Jun 19, 2025

Modifying the original image would be a better and simpler approach. https://github.com/brendan-duncan/image/blob/main/doc/filters.md

And something like real-time adjustment would be good, but I'm not sure if Flutter can be able to do this.

I have already added a feature ,which adjusts the original image in this pr
#57
which uses the pro_image_editor package

modyfying the original image is good but it doesn't have fine tune controls for having more (red,black,white) in the display, which I think will give a good control

if we use displays supporting more colors, for example (red,black,white,yellow) and want yellow to be more dominant this feature would be good

@Vishveshwara Vishveshwara marked this pull request as draft June 23, 2025 07:21
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.

Add a feature to adjust the colors before transferring the image
2 participants