Skip to content

Commit 662501f

Browse files
committed
feat: improve image conversion
1 parent 7dddfff commit 662501f

File tree

6 files changed

+61
-22
lines changed

6 files changed

+61
-22
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
# flutter-package-devspace
22
A repo that contains unfinished packages that can be integrated via submodule.
3+
4+
5+
6+
### Notes
7+
8+
9+
#### Image Conversion
10+
In order to use image conversion in the web make sure to add
11+
12+
```html
13+
<script src="https://unpkg.com/pica/dist/pica.min.js" ></script>
14+
```
15+
16+
For more info see https://pub.dev/packages/flutter_image_compress#web

lib/blue_forms/models/elements/form_input_images.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class FormInputImages extends FormInput {
3131
final int min;
3232
final int max;
3333
final FormInputImagesFileSettings fileSettings;
34-
final void Function(List<img.Image> images)? onChange;
34+
final void Function(List<Uint8List> images)? onChange;
3535

3636
const FormInputImages({
3737
required super.id,

lib/blue_forms/widgets/form_input_images.dart

+44-20
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class _FormInputImagesWidget extends StatelessWidget {
1111
final bool visuallyMarkRequired;
1212
final dynamic currentSavedValue;
1313
final String? externalError;
14-
final void Function(List<img.Image> images) onSave;
14+
final void Function(List<Uint8List> images) onSave;
1515

1616
const _FormInputImagesWidget({
1717
super.key,
@@ -67,7 +67,7 @@ class _FormInputImagesWidgetMulti extends StatefulWidget {
6767
final bool visuallyMarkRequired;
6868
final dynamic currentSavedValue;
6969
final String? externalError;
70-
final void Function(List<img.Image> images) onSave;
70+
final void Function(List<Uint8List> images) onSave;
7171

7272
const _FormInputImagesWidgetMulti({
7373
super.key,
@@ -407,7 +407,7 @@ class _FormInputImagesWidgetSingle extends StatefulWidget {
407407
final bool visuallyMarkRequired;
408408
final dynamic currentSavedValue;
409409
final String? externalError;
410-
final void Function(img.Image? image) onSave;
410+
final void Function(Uint8List? image) onSave;
411411

412412
const _FormInputImagesWidgetSingle({
413413
// ignore: unused_element
@@ -450,7 +450,7 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
450450

451451
return _FormInputContainerWidget(
452452
description: widget.definition.description,
453-
child: FormField<img.Image?>(
453+
child: FormField<Uint8List?>(
454454
initialValue: widget.currentSavedValue ?? widget.definition.initialValue,
455455
onSaved: widget.onSave,
456456
validator: (image)
@@ -530,7 +530,7 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
530530
}
531531

532532

533-
Widget _buildPreview(BuildContext context, FormFieldState<img.Image?> state)
533+
Widget _buildPreview(BuildContext context, FormFieldState<Uint8List?> state)
534534
{
535535
if (_imageProvider == null)
536536
{
@@ -612,7 +612,7 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
612612
);
613613
}
614614

615-
Future<void> _addImage(ImageSource source, FormFieldState<img.Image?> state) async
615+
Future<void> _addImage(ImageSource source, FormFieldState<Uint8List?> state) async
616616
{
617617

618618

@@ -627,11 +627,11 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
627627
_internalError = null;
628628
});
629629

630-
img.Image? image;
630+
Uint8List? image;
631631

632632
if (imageFile != null)
633633
{
634-
image = await imageFile.getImage();
634+
image = await imageFile.readAsBytes();
635635
}
636636

637637
if (image == null) return;
@@ -644,7 +644,7 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
644644
{
645645
state.didChange(image);
646646
widget.definition.onChange?.call([image!]);
647-
_imageProvider = image!.toImageProvider();
647+
_imageProvider = MemoryImage(image!);
648648
});
649649
}
650650
finally
@@ -657,38 +657,62 @@ class _FormInputImagesWidgetSingleState extends State<_FormInputImagesWidgetSing
657657

658658
}
659659

660-
Future<img.Image> _imageProcessing(img.Image image, FormFieldState<img.Image?> state) async
660+
Future<Uint8List> _imageProcessing(Uint8List image, FormFieldState<Uint8List?> state) async
661661
{
662-
if (widget.definition.fileSettings.minWidth != null && image.width < widget.definition.fileSettings.minWidth!)
662+
final codec = await ui.instantiateImageCodec(image);
663+
final frame = await codec.getNextFrame();
664+
665+
666+
if (widget.definition.fileSettings.minWidth != null && frame.image.width < widget.definition.fileSettings.minWidth!)
663667
{
664668
_internalError = 'MIN_WIDTH';
665669
state.validate();
666670

667671
throw Exception('Image width is smaller than min width');
668672
}
669673

670-
if (widget.definition.fileSettings.minHeight != null && image.height < widget.definition.fileSettings.minHeight!)
674+
if (widget.definition.fileSettings.minHeight != null && frame.image.height < widget.definition.fileSettings.minHeight!)
671675
{
672676
_internalError = 'MIN_HEIGHT';
673677
state.validate();
674678

675679
throw Exception('Image height is smaller than min height');
676680
}
677681

682+
int minHeight = frame.image.height;
683+
int minWidth = frame.image.width;
678684

679-
// TODO: use the following for image processing (other is a way too slow): https://pub.dev/packages/flutter_image_compress
685+
if (widget.definition.fileSettings.maxWidth != null)
686+
{
687+
if (widget.definition.fileSettings.maxHeight != null)
688+
{
689+
throw UnimplementedError('Max width and max height are not yet supported');
690+
}
691+
else
692+
{
693+
minWidth = widget.definition.fileSettings.maxWidth!;
694+
}
695+
}
696+
else if (widget.definition.fileSettings.maxHeight != null)
697+
{
698+
minHeight = widget.definition.fileSettings.maxHeight!;
699+
}
680700

681-
return image.convertImage(
682-
type: widget.definition.fileSettings.conversion,
683-
quality: widget.definition.fileSettings.conversionQuality,
684-
maxWidth: widget.definition.fileSettings.maxWidth,
685-
maxHeight: widget.definition.fileSettings.maxHeight,
701+
return await FlutterImageCompress.compressWithList(image,
702+
minHeight: minHeight,
703+
minWidth: minWidth,
704+
quality: (widget.definition.fileSettings.conversionQuality * 100).round(),
705+
format: switch (widget.definition.fileSettings.conversion)
706+
{
707+
kImageConversionType.jpeg => CompressFormat.jpeg,
708+
kImageConversionType.png => CompressFormat.png,
709+
},
686710
);
687-
711+
688712
}
689713

690714

691-
void _deleteCurrentImage(FormFieldState<img.Image?> state)
715+
void _deleteCurrentImage(FormFieldState<Uint8List?> state)
692716
{
693717
if (state.value == null)
694718
{

lib/devspace.dart

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:flutter/foundation.dart';
1717
import 'package:flutter/material.dart' as material;
1818
import 'package:flutter/material.dart';
1919
import 'package:flutter_animate/flutter_animate.dart';
20+
import 'package:flutter_image_compress/flutter_image_compress.dart';
2021
import 'package:get_it/get_it.dart';
2122
import 'package:go_router/go_router.dart';
2223
import 'package:http/http.dart' as http;

lib/type_extensions/image.dart

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ part of devspace;
44
// ignore: camel_case_types
55
enum kImageConversionType
66
{
7-
none,
87
jpeg,
98
png
109
}

pubspec.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dependencies:
3232
loading_indicator: ^3.1.1
3333
omni_datetime_picker: ^2.0.2
3434
image: ^4.2.0
35+
flutter_image_compress: ^2.3.0
3536

3637
dev_dependencies:
3738
flutter_test:

0 commit comments

Comments
 (0)