Skip to content

Commit

Permalink
Add histogram
Browse files Browse the repository at this point in the history
  • Loading branch information
kra-mo committed Sep 16, 2024
1 parent 1d05450 commit f878f7e
Show file tree
Hide file tree
Showing 13 changed files with 287 additions and 5 deletions.
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ linter:
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
Binary file added assets/icons/1.5x/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/2.0x/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/3.0x/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/4.0x/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/histogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 70 additions & 4 deletions lib/editor_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/material.dart';

import 'package:crop_image/crop_image.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'utils.dart';
import 'image.dart';
Expand All @@ -15,6 +16,7 @@ import 'slider_row.dart';
import 'switch.dart';
import 'toggle_buttons.dart';
import 'spinner.dart';
import 'histogram.dart';
import 'dialog.dart';
import 'snack_bar.dart';
import 'title_bar.dart';
Expand All @@ -33,6 +35,8 @@ class SlyEditorPage extends StatefulWidget {
}

class _SlyEditorPageState extends State<SlyEditorPage> {
final Future<SharedPreferences> prefs = SharedPreferences.getInstance();

final GlobalKey<SlyButtonState> _saveButtonKey = GlobalKey<SlyButtonState>();
final GlobalKey _imageWidgetKey = GlobalKey();
int _controlsWidgetKeyValue = 0;
Expand Down Expand Up @@ -67,6 +71,7 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
bool _canRedo = false;

int _selectedPageIndex = 0;
bool _showHistogram = false;

final String _saveButtonLabel =
!kIsWeb && Platform.isIOS ? 'Save to Photos' : 'Save';
Expand Down Expand Up @@ -226,6 +231,15 @@ class _SlyEditorPageState extends State<SlyEditorPage> {

@override
void initState() {
prefs.then((value) {
final showHistogram = value.getBool('showHistogram');
if (showHistogram == null) return;

setState(() {
_showHistogram = showHistogram;
});
});

_editedImage = SlyImage.from(_originalImage);
subscription = _editedImage.controller.stream.listen(_onImageUpdate);
updateImage();
Expand Down Expand Up @@ -995,7 +1009,7 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
);

final controlsWidget = AnimatedSize(
key: Key("controlsWidget $_controlsWidgetKeyValue"),
key: Key('controlsWidget $_controlsWidgetKeyValue'),
duration: const Duration(milliseconds: 300),
curve: Curves.easeOutQuint,
child: AnimatedSwitcher(
Expand Down Expand Up @@ -1044,7 +1058,30 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
alignment: constraints.maxWidth > 600
? WrapAlignment.start
: WrapAlignment.center,
children: <Widget>[
children: <Widget?>[
[0, 1].contains(_selectedPageIndex)
? Tooltip(
message: _showHistogram
? 'Hide Histogram'
: 'Show Histogram',
child: IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
icon: const ImageIcon(
color: Colors.white54,
AssetImage('assets/icons/histogram.png'),
),
onPressed: () async {
await (await prefs)
.setBool('showHistogram', !_showHistogram);

setState(() {
_showHistogram = !_showHistogram;
});
},
),
)
: null,
Tooltip(
message: 'Show Original',
child: IconButton(
Expand Down Expand Up @@ -1114,8 +1151,32 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
},
),
),
],
].whereType<Widget>().toList(),
),
);

final histogram = AnimatedSize(
duration: Duration(
milliseconds: _selectedPageIndex == 3 ? 0 : 300,
),
curve: Curves.easeOutQuint,
child: [0, 1].contains(_selectedPageIndex) && _showHistogram
? Padding(
padding: EdgeInsets.only(
bottom: constraints.maxWidth > 600 ? 12 : 0,
top: (constraints.maxWidth > 600 &&
!kIsWeb &&
(Platform.isLinux || Platform.isMacOS))
? 0
: 8,
),
child: SizedBox(
height: constraints.maxWidth > 600 ? 40 : 30,
width: constraints.maxWidth > 600 ? null : 150,
child: getHistogram(_editedImage),
),
)
: Container(),
);

if (constraints.maxWidth > 600) {
Expand Down Expand Up @@ -1201,6 +1262,7 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
child: Container(),
),
),
histogram,
Expanded(child: controlsWidget),
_selectedPageIndex != 3 &&
_selectedPageIndex != 4
Expand Down Expand Up @@ -1265,7 +1327,11 @@ class _SlyEditorPageState extends State<SlyEditorPage> {
]
: <Widget>[
imageWidget,
toolbar,
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [toolbar, histogram],
),
controlsWidget,
],
),
Expand Down
69 changes: 69 additions & 0 deletions lib/histogram.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';

import 'package:fl_chart/fl_chart.dart';

import 'image.dart';

LineChart getHistogram(SlyImage image) {
final imageData = image.getHistogramData();

final List<List<FlSpot>> spots = [
List.generate(16, (index) => FlSpot(index.toDouble(), 0)),
List.generate(16, (index) => FlSpot(index.toDouble(), 0)),
List.generate(16, (index) => FlSpot(index.toDouble(), 0))
];

int channel = 0;
for (int pixel in imageData) {
int i = pixel >> 4;
if (i == 0 && pixel != 0) {
i = 1;
} else if (i == 15 && pixel != 255) {
i = 14;
}

spots[channel][i] = FlSpot((i).toDouble(), spots[channel][i].y + 1);
channel = (channel + 1) % 3;
}

final List<List<Color>> colors = [
[Colors.red.shade900, Colors.red],
[Colors.green.shade900, Colors.green],
[Colors.blue.shade900, Colors.blue],
];

final List<LineChartBarData> lineBarsData = [];

for (int i = 0; i < 3; i++) {
lineBarsData.add(
LineChartBarData(
spots: spots[i],
isCurved: true,
gradient: LinearGradient(
colors: [colors[i][0], colors[i][1]],
),
barWidth: 2,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: [colors[i][0], colors[i][1]]
.map((color) => color.withOpacity(1 / 3))
.toList(),
),
),
),
);
}

return LineChart(
LineChartData(
titlesData: const FlTitlesData(show: false),
lineTouchData: const LineTouchData(enabled: false),
gridData: const FlGridData(show: false),
borderData: FlBorderData(show: false),
lineBarsData: lineBarsData,
),
);
}
8 changes: 8 additions & 0 deletions lib/image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,14 @@ class SlyImage {
return (await cmd.executeThread()).outputBytes!;
}

/// Returns a short list representing lightness across the image,
/// useful for building a histogram.
Uint8List getHistogramData() {
final resizedImage = img.copyResize(_image, width: 20, height: 20);

return resizedImage.buffer.asUint8List();
}

void dispose() {
controller.close();
_editsApplied = double.infinity;
Expand Down
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import Foundation
import file_selector_macos
import gal
import screen_retriever
import shared_preferences_foundation
import url_launcher_macos
import window_manager

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}
7 changes: 7 additions & 0 deletions macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ PODS:
- FlutterMacOS
- screen_retriever (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
- window_manager (0.2.0):
Expand All @@ -17,6 +20,7 @@ DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)

Expand All @@ -29,6 +33,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/gal/darwin
screen_retriever:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
window_manager:
Expand All @@ -39,6 +45,7 @@ SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8

Expand Down
Loading

0 comments on commit f878f7e

Please sign in to comment.