How to crop Image from image picker in flutter? - flutter

I want to allow the user to crop the Image he chose from the image picker and save it(Similar to uploading profile pic on Whatsapp). How can I do this in flutter?
Sample Image:

You can use these 2 flutter libraries to achieve this,
image_picker;
image_cropper
The image picker use the native libraries in iOS and Android to achieve it, therefore it will delivery a good performance way.
Here is a sample available in image_picker:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(new ConfigScreen());
class ConfigScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ImageCropper',
theme: ThemeData.light().copyWith(primaryColor: Colors.deepOrange),
home: MyHomePage(
title: 'ImageCropper',
),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({this.title});
#override
_MyHomePageState createState() => _MyHomePageState();
}
enum AppState {
free,
picked,
cropped,
}
class _MyHomePageState extends State<MyHomePage> {
AppState state;
File imageFile;
#override
void initState() {
super.initState();
state = AppState.free;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: imageFile != null ? Image.file(imageFile) : Container(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepOrange,
onPressed: () {
if (state == AppState.free)
_pickImage();
else if (state == AppState.picked)
_cropImage();
else if (state == AppState.cropped) _clearImage();
},
child: _buildButtonIcon(),
),
);
}
Widget _buildButtonIcon() {
if (state == AppState.free)
return Icon(Icons.add);
else if (state == AppState.picked)
return Icon(Icons.crop);
else if (state == AppState.cropped)
return Icon(Icons.clear);
else
return Container();
}
Future<Null> _pickImage() async {
imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
if (imageFile != null) {
setState(() {
state = AppState.picked;
});
}
}
Future<Null> _cropImage() async {
File croppedFile = await ImageCropper.cropImage(
sourcePath: imageFile.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
void _clearImage() {
imageFile = null;
setState(() {
state = AppState.free;
});
}
}

The image_picker already can crop the image. You pass in the specified width and height for the image you want and the plugin actually crops the original image.
_imageFile = ImagePicker.pickImage(source: source, maxWidth: 200.0, maxHeight: 300.0);
What you are asking for is another plugin to crop images after one has been selected and that would be outside the scope of the image_picker.
I am facing something similar and you can always have the user edit the photo or video with the built in camera app until there is a plugin made for cropping images.
For cropping images on the UI level you can do something like this:
https://stackoverflow.com/a/44665742/7303311

To crop the image from image_cropper library you case just set the
aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1)
Here's the sample code:
CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: pickedImage.path,
aspectRatio: imagePickingType == ImagePickingType.profilePic ? CropAspectRatio(ratioX: 1, ratioY: 1) :
imagePickingType == ImagePickingType.communityWall ? CropAspectRatio(ratioX: 16, ratioY: 9) : null,
uiSettings: [
AndroidUiSettings(
toolbarTitle: cropPageTitle ?? 'Edit Image',
toolbarColor: toolbarTextColor ??
theme.scaffoldBackgroundColor,
toolbarWidgetColor: toolbarBackgroundColor ??
theme.primaryColor,
initAspectRatio:
initialAspectRation ?? CropAspectRatioPreset.original,
lockAspectRatio: (imagePickingType == ImagePickingType.profilePic) || (imagePickingType == ImagePickingType.communityWall),
backgroundColor: theme.scaffoldBackgroundColor,
activeControlsWidgetColor: theme.primaryColor,
),
IOSUiSettings(
title: cropPageTitle ?? 'Edit Image',
rotateClockwiseButtonHidden: true,
aspectRatioPickerButtonHidden: true,
aspectRatioLockEnabled: (imagePickingType == ImagePickingType.profilePic) || (imagePickingType == ImagePickingType.communityWall),
rotateButtonsHidden: true,
),
],
);
if (croppedFile != null) {
return File(croppedFile.path);
} else {
File(pickedImage.path);
}

Related

image_picker It does not allow me to load an image from gallery or camera

Everything works normally, but when I click to load an image from the gallery or from the camera, it does not load the image
The message in the VSC Debug Console is:
D/MediaScannerConnection( 5069): Scanned /data/user/0/com.lot.sig/cache/ce7735c2-8d36-4633-996f-bfae03424df26527509175807023631.jpg to null
This is my user_profile.dart:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
class UserProfile extends StatefulWidget {
UserProfile();
#override
_UserProfile createState() => _UserProfile();
}
enum AppState {
free,
picked,
cropped,
}
class _UserProfile extends State<UserProfile> {
AppState? state;
File? imageFile;
#override
void initState() {
super.initState();
state = AppState.free;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black87,
title: Text("Hola"),
),
body: Center(
child: imageFile != null ? Image.file(imageFile!) : Container(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.black87,
onPressed: () {
if (state == AppState.free)
_pickImage();
else if (state == AppState.picked)
_cropImage();
else if (state == AppState.cropped) _clearImage();
},
child: _buildButtonIcon(),
),
);
}
Widget _buildButtonIcon() {
if (state == AppState.free)
return Icon(Icons.add);
else if (state == AppState.picked)
return Icon(Icons.crop);
else if (state == AppState.cropped)
return Icon(Icons.clear);
else
return Container();
}
Future<Null> _pickImage() async {
final _imageFile = await ImagePicker().pickImage(source: ImageSource.gallery);
if (_imageFile != null) {
imageFile = File(_imageFile.path);
setState(() {
state = AppState.picked;
});
}
}
Future<Null> _cropImage() async {
File? croppedFile = await ImageCropper.cropImage(
sourcePath: imageFile!.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
void _clearImage() {
imageFile = null;
setState(() {
state = AppState.free;
});
}
}
And this is my image_picker_handler.dart :
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:sig/utilitary/image_picker_dialog.dart';
class ImagePickerHandler {
late ImagePickerDialog imagePicker;
AnimationController? _controller;
ImagePickerListener _listener;
ImagePickerHandler(this._listener, this._controller);
final ImagePicker _picker = ImagePicker();
openCamera() async {
imagePicker.dismissDialog();
var image = await (_picker.pickImage(source: ImageSource.camera) as FutureOr<XFile>);
cropImage(image);
}
openGallery() async {
imagePicker.dismissDialog();
var image = await (_picker.pickImage(source: ImageSource.gallery) as FutureOr<XFile>);
cropImage(image);
}
void init() {
imagePicker = new ImagePickerDialog(this, _controller);
imagePicker.initState();
}
Future cropImage(XFile image) async {
File? croppedFile = await ImageCropper.cropImage(
sourcePath: image.path,
maxWidth: 512,
maxHeight: 512,
);
_listener.userImage(croppedFile);
}
showDialog(BuildContext context) {
imagePicker.getImage(context);
}
}
abstract class ImagePickerListener {
userImage(File? _image);
}

how to show selected image in alert dialog?

I want to implement that after clicking upload button it will pick image from gallery. After picking image then open Image cropper screen lastly cropped image will show in alert dialog. But here clicking upload button it pick image again clicking upload button open crop screen lastly clicking upload button it shows alert dialog.i want to change state automatically .. How can i fix that. Here is a sample code i have tried
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late AppState state;
File? imageFile;
#override
void initState() {
super.initState();
state = AppState.free;
}
#override
Widget build(BuildContext context) {
Future pickedImage() async {
final pickedImage =
await ImagePicker().pickImage(source: ImageSource.gallery);
imageFile = pickedImage != null ? File(pickedImage.path) : null;
if (imageFile != null) {
setState(() {
state = AppState.picked;
});
}
}
Future<Null> _cropImage() async {
var croppedFile = await ImageCropper().cropImage(
sourcePath: imageFile!.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
ElevatedButton(
onPressed: () {
if (state == AppState.free)
pickedImage();
else if (state == AppState.picked)
_cropImage();
else if (state == AppState.cropped) {
showAlertDialog(context);
} else {
Container();
}
},
child: Text("Upload"))
],
));
}
showAlertDialog(BuildContext context) {
// Create button
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
// Create AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Simple Alert"),
content: Container(
width: 250,
height: 100,
child: imageFile != null ? Image.file(imageFile!) : Container(),
),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
}
enum AppState {
free,
picked,
cropped,
}
Maybe you should add this line to setState block also.
if (croppedFile != null) {
//imageFile = croppedFile;
setState(() {
imageFile = croppedFile; //to here
state = AppState.cropped;
});
}
ImagePicker return a nullable CroppedFile?.
You can create a state variable to hold it.
File? imageFile;
CroppedFile? croppedFile;
/// you can also directly assing it on `croppedFile = await ImageCropper().cropImage(`
if (croppedFile != null) {
croppedFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
Now to view the croppedFile
croppedFile != null ? Image.file(File(croppedFile!.path)) : null),

flutter) There's a problem with using imagePicker

I'm using sdk 2.12.0 and image_picker 0.8.4 version.
I'm going to link my gallery to get an image.
However, when I press the Add Image button on my app, the app turns off immediately.
This is the code for the image_picker I used.
class CreatePage extends StatefulWidget {
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
Future<void> _getImage() async {
//ImagePiker
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
And this is my full code about this page. (Firebase code is included)
import 'dart:io';
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class CreatePage extends StatefulWidget {
//user info
const CreatePage({Key? key, required this.user}) : super(key: key);
final User user;
#override
_CreatePageState createState() => _CreatePageState();
}
class _CreatePageState extends State<CreatePage> {
//input text
final TextEditingController createText = TextEditingController();
//ImagePicker
final ImagePicker _picker = ImagePicker();
File? _imageFile;
//_createPageState가 제거될 때 호출됨
#override
void dispose() {
// TODO: implement dispose
createText.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppbar(),
body: _buildBody(),
floatingActionButton: FloatingActionButton(
onPressed: _getImage,
backgroundColor: Colors.blue,
child: Icon(Icons.add_a_photo),
),
);
}
_buildAppbar() {
return AppBar(
actions: [
IconButton(
icon: Icon(Icons.send),
onPressed: () {
_uploadPost(context);
},
),
],
);
}
_buildBody() {
return SingleChildScrollView(
child: Column(
children: [
_imageFile == null ? Text("No Image") : Image.file(_imageFile!),
TextField(
controller: createText,
decoration: InputDecoration(
hintText: "내용을 입력하세요",
),
)
],
),
);
}
//gallery image
Future<void> _getImage() async {
var image = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(image!.path);
});
}
Future _uploadPost(BuildContext context) async {
final firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('post')
.child('${DateTime.now().microsecondsSinceEpoch}.png');
final task = await firebaseStorageRef.putFile(
_imageFile!, SettableMetadata(contentType: "image/png")
);
final uri = await task.ref.getDownloadURL();
//database document
final doc = FirebaseFirestore.instance.collection('post').doc();
//json type
await doc.set({
'id': doc.id,
'photoUrl': uri.toString(), //storage file url
'contents': createText, //user input text
'email': widget.user.email, //user email
'displayName': widget.user.displayName, //user name
'userPhotoUrl': widget.user.photoURL, //user profile image
});
//return page
Navigator.pop(context);
}
}
Pressing the floatingActionButton turns off the app and outputs the following error.
Lost connection to device.
May I know the cause of this?
Thank you in advance.
try adding dependency
image_picker: ^0.8.3+2
import 'package:image_picker/image_picker.dart';
then add this code
String url = "";
ImagePicker image = ImagePicker();
File ? file;
getImage() async {
var img = await image.pickImage(source: ImageSource.gallery);
setState(() {
file = File(img!.path);
});
}
And add:
onTap: () {
getImage();
},
add code:
child: file != null ?
Column(
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
color: Colors.black,
margin: EdgeInsets.only(top: 80),
width: double.infinity,
height: 250,
child: Image.file(
file!,
fit: BoxFit.contain,
),
),
),
My guess is that you don't have permission to access the Media on the device, thus aborting the app the moment you try to do so. Check out the permission handler package.

Flutter Image Crop Not Responding

I am trying to crop an image from picked image from gallery, the image is picked perfectly but while trying to crop an image it seems nothing happened in the screen, and some problem detected in console though I can't understand the problem. the code I have used is from official pub.dev site [https://pub.dev/packages/image_cropper/example]
My Task is : pick and crop an image for
Help me to Resolve this Problem, Thanks in Advance.
The Code:
....
class _EditGalleryScreenState extends State<EditGalleryScreen> {
File imageFile;
List _galleries = new List();
#override
void initState() {
.....
}
....
//SOME API CALLS
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Gallery"),
),
body: _galleries.isNotEmpty
? GridView.builder(/* DIAPLYING LIST OF IMAGES FROM API CALL */)
: SizedBox(),
//BUTTON TO TRIGGER IMAGE PICKER
floatingActionButton: FloatingActionButton(
tooltip: "Add Image",
onPressed: () {
_pickImage();
},
child: Icon(Icons.add_a_photo),
backgroundColor: AppColors.PRIMARY_COLOR,
),
);
}
Future<Null> _pickImage() async {
// imageFile = await ImagePicker.pickImage(source: ImageSource.gallery); // this was deprecated so i have updated to otherone
PickedFile imageFile = await ImagePicker().getImage(
source: ImageSource.gallery,
maxWidth: 500,
maxHeight: 500,
imageQuality: 20);
if (imageFile != null) {
setState(() {
state = AppState.picked;
debugPrint("Image Picked and State Changed");
_cropImage();//calling CROP FUNCTION
});
}
}
Future<Null> _cropImage() async {
debugPrint("Crop Image Called");
File croppedFile = await ImageCropper.cropImage(
sourcePath: imageFile.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
}
Screen Shot of Console

How to save perticular part of the screen as image in flutter

I have list of images of answer sheet in server.I need to display that images and need to select some particular area of that image, and save only that area as image. I done displaying and selection part but i don't know how to save only that selected area as image. please help me as soon as possible.
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'dart:io';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Colors.red,
scaffoldBackgroundColor: Colors.white,
canvasColor: Colors.transparent),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
List<AnswerSheet> answerSheets = [
AnswerSheet(
imageUrl:
'https://d18x2uyjeekruj.cloudfront.net/wp-content/uploads/2019/04/Scan12.jpg',
downloadedImagePath: '',
selectedOffsets: List()),
AnswerSheet(
imageUrl:
'https://d18x2uyjeekruj.cloudfront.net/wp-content/uploads/2019/04/Scan12.jpg',
downloadedImagePath: '',
selectedOffsets: List())
];
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
body: GestureDetector(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) =>
EntryItem(answerSheets[index]),
itemCount: answerSheets.length,
),
));
}
}
class EntryItem extends StatefulWidget {
final AnswerSheet answerSheet;
EntryItem(this.answerSheet);
#override
_EntryItemState createState() => _EntryItemState();
}
class _EntryItemState extends State<EntryItem> {
final GlobalKey _myCanvasKey = new GlobalKey();
MyCustomPainter _customPainter;
Offset _startOffset;
bool isLoading = true;
ui.Image _image;
bool _isImageEditable = true;
BuildContext context;
#override
void initState() {
super.initState();
_downloadImage();
}
#override
Widget build(BuildContext context) {
this.context = context;
if (isLoading) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Center(child: CircularProgressIndicator()));
} else {
return GestureDetector(
onHorizontalDragStart: _onHorizontalDragStart,
onHorizontalDragUpdate: _onHorizontalDragUpdate,
onHorizontalDragEnd: _onHorizontalDragEnd,
child: Container(
margin: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: Color(0xFFF4F4F4),
borderRadius: BorderRadius.circular(10.0)),
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: CustomPaint(
key: _myCanvasKey,
size: MediaQuery.of(context).size,
painter: _customPainter,
),
),
));
}
}
Future downloadAndSaveImage(AnswerSheet answerSheet) async {
print("downloading....");
var response = await get(answerSheet.imageUrl);
var documentDirectory = await getApplicationDocumentsDirectory();
File file = File(join(documentDirectory.path, '${DateTime.now()}.jpg'));
file.writeAsBytesSync(response.bodyBytes);
answerSheet.downloadedImagePath = file.path;
print(file.path);
return response.bodyBytes;
}
Future<Null> _downloadImage() async {
List<int> img = await downloadAndSaveImage(widget.answerSheet);
_image = await _loadImage(img);
setState(() {
_customPainter =
MyCustomPainter(answerSheet: widget.answerSheet, image: _image);
isLoading = false;
});
}
Future<ui.Image> _loadImage(List<int> img) async {
final Completer<ui.Image> completer = Completer();
ui.decodeImageFromList(img, (ui.Image img) {
return completer.complete(img);
});
return completer.future;
}
Rect getRect(Offset offset) {
return Rect.fromPoints(offset, Offset(offset.dx + 30, offset.dy + 30));
}
_onHorizontalDragStart(DragStartDetails detailData) {
if (_isImageEditable) {
_startOffset = detailData.globalPosition;
widget.answerSheet.selectedOffsets.add(_startOffset);
}
}
_onHorizontalDragUpdate(DragUpdateDetails detailData) {
if (_isImageEditable) {
widget.answerSheet.selectedOffsets
.add(Offset(detailData.localPosition.dx, _startOffset.dy));
_myCanvasKey.currentContext.findRenderObject().markNeedsPaint();
}
}
_onHorizontalDragEnd(DragEndDetails details) {
print('_onHorizontalDragEnd');
if (_isImageEditable) {
_myCanvasKey.currentContext.findRenderObject().markNeedsPaint();
_startOffset = null;
}
}
}
class MyCustomPainter extends CustomPainter {
final AnswerSheet answerSheet;
final ui.Image image;
MyCustomPainter({this.answerSheet, this.image});
Paint _paint = new Paint()
..color = Colors.deepOrange.withOpacity(0.3)
..style = PaintingStyle.stroke;
Offset _prvOffset;
#override
void paint(Canvas canvas, Size size) {
_paint.strokeWidth = 40;
Rect myRect = Offset(0.0, 0.0) & Size(size.width, size.height);
drawImage(myRect, size, canvas, new Paint(), BoxFit.fill);
if (answerSheet.selectedOffsets.length != 0) {
for (Offset currOffset in answerSheet.selectedOffsets) {
if (_prvOffset != null && currOffset != null)
canvas.drawLine(_prvOffset, currOffset, _paint);
_prvOffset = currOffset;
}
_prvOffset = null;
}
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
Paint getPaint(Color color) {
return new Paint()
..isAntiAlias = true
..strokeWidth = 1.0
..color = color
..style = PaintingStyle.fill;
}
void drawImage(
Rect outputRect, Size size, Canvas canvas, Paint paint, BoxFit fit) {
final Size imageSize =
Size(image.width.toDouble(), image.height.toDouble());
final FittedSizes sizes = applyBoxFit(fit, imageSize, outputRect.size);
final Rect inputSubrect =
Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
final Rect outputSubrect =
Alignment.center.inscribe(sizes.destination, outputRect);
canvas.drawImageRect(image, inputSubrect, outputSubrect, paint);
}
}
class AnswerSheet {
String imageUrl;
String downloadedImagePath;
List<Offset> selectedOffsets;
AnswerSheet({this.imageUrl, this.downloadedImagePath, this.selectedOffsets});
}
screenshot
A simple plugin to capture widgets as Images.
This plugin wraps your widgets inside RenderRepaintBoundary
This handy plugin can be used to capture any Widget including full screen screenshots & individual widgets like Text().
Ok, you need to use image_cropper or crop packages. These are helpful to you. Look at the below example:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ImageCropper',
theme: ThemeData.light().copyWith(primaryColor: Colors.deepOrange),
home: MyHomePage(
title: 'ImageCropper',
),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({this.title});
#override
_MyHomePageState createState() => _MyHomePageState();
}
enum AppState {
free,
picked,
cropped,
}
class _MyHomePageState extends State<MyHomePage> {
AppState state;
File imageFile;
#override
void initState() {
super.initState();
state = AppState.free;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: imageFile != null ? Image.file(imageFile) : Container(),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepOrange,
onPressed: () {
if (state == AppState.free)
_pickImage();
else if (state == AppState.picked)
_cropImage();
else if (state == AppState.cropped) _clearImage();
},
child: _buildButtonIcon(),
),
);
}
Widget _buildButtonIcon() {
if (state == AppState.free)
return Icon(Icons.add);
else if (state == AppState.picked)
return Icon(Icons.crop);
else if (state == AppState.cropped)
return Icon(Icons.clear);
else
return Container();
}
Future<Null> _pickImage() async {
imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
if (imageFile != null) {
setState(() {
state = AppState.picked;
});
}
}
Future<Null> _cropImage() async {
File croppedFile = await ImageCropper.cropImage(
sourcePath: imageFile.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
]
: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio5x3,
CropAspectRatioPreset.ratio5x4,
CropAspectRatioPreset.ratio7x5,
CropAspectRatioPreset.ratio16x9
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Cropper',
toolbarColor: Colors.deepOrange,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Cropper',
));
if (croppedFile != null) {
imageFile = croppedFile;
setState(() {
state = AppState.cropped;
});
}
}
void _clearImage() {
imageFile = null;
setState(() {
state = AppState.free;
});
}
}