45

Let's say I have a rectangular, portrait image:

enter image description here

I'd like to crop it, such that it's rendered like this:

enter image description here

How can I do this in Flutter?

(I don't need to resize the image.)

(Image from https://flic.kr/p/nwXTDb)

Seth Ladd
  • 112,095
  • 66
  • 196
  • 279

9 Answers9

76

I would probably use a BoxDecoration with a DecorationImage. You can use the alignment and fit properties to determine how your image is cropped. You can use an AspectRatio widget if you don't want to hard code a height on the Container.

screenshot

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyHomePage(),
  ));
}

class MyHomePage extends StatelessWidget {

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Image Crop Example"),
      ),
      body: new Center(
        child: new AspectRatio(
          aspectRatio: 487 / 451,
          child: new Container(
            decoration: new BoxDecoration(
              image: new DecorationImage(
                fit: BoxFit.fitWidth,
                alignment: FractionalOffset.topCenter,
                image: new NetworkImage('https://i.stack.imgur.com/lkd0a.png'),
              )
            ),
          ),
        ),
      ),
    );
  }
}
Collin Jackson
  • 110,240
  • 31
  • 221
  • 152
  • 1
    wow i had different issue, but this BoxDecoration technique worked out for me. Thanks man :) – Piyush Kumar Mar 05 '18 at 14:02
  • 8
    You are trying to crop the file while rendering it. However, I want to store the cropped version of the image and then render it. Do you know of any such technique or package? – Karan Saluja Nov 22 '18 at 04:29
  • 1
    Hi, I want to show part of the image in **both** directions. Say I have 1080x1920 image, and I want to show (x=100~200, y=300~400) part. Thus I cannot use this fit+alignment method. How can I do so? Thanks! – ch271828n Jan 13 '21 at 13:50
30

You can also directly use the Image class with BoxFit and do something like:

new Image.asset(
  stringToImageLocation,
  fit: BoxFit.cover,
)
Mary
  • 18,347
  • 23
  • 59
  • 76
  • 1
    Worked with `DecorationImage` as well – Padmal Jul 02 '19 at 12:11
  • 2
    Hi, I want to show part of the image in both directions. Say I have 1080x1920 image, and I want to show (x=100~200, y=300~400) part. Thus I cannot use this fit+alignment method. How can I do so? Thanks! – ch271828n Jan 13 '21 at 13:50
17

Provide a fit factor to your Image widget and then wrap it in AspectRatio.

AspectRatio(
  aspectRatio: 1.5, 
  child: Image.asset(
    'your_image_asset',
    fit: BoxFit.cover,
  ),
)
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
13

Take a look to brendan-duncan/image, it's platform-independent library to manipulate images in Dart.

You can use the function:

Image copyCrop(Image src, int x, int y, int w, int h);
Wael Boutglay
  • 1,163
  • 1
  • 15
  • 21
  • Thanks! Have you tried it with Flutter? I'm wondering how to get a Flutter Image in and out of brendan's image library. – Seth Ladd Jun 21 '17 at 02:31
  • 3
    I don't think Flutter provides an easy way to get the decoded image out of a `ui.Image`. But if you use brendan's image library to do the decoding, you can call `image.getBytes()` and pass that to a `new Image.memory` – Collin Jackson Jun 21 '17 at 22:57
  • 2
    Is it possible to add example on how to do it in Flutter from network image? I'm trying to crop image at specific `{ x: 897, y: 235, width: 845, height: 845 }` values, but can't find anything that could work for me. – Mārtiņš Ciekurs Jul 31 '19 at 13:17
5

Worked for me using just these 2 properties:

CachedNetworkImage(
  fit: BoxFit.cover,// OR BoxFit.fitWidth
  alignment: FractionalOffset.topCenter,
  ....
)
Deven
  • 3,078
  • 1
  • 32
  • 34
4

There is a new package called ImageCropper. I would recommend everyone to use this instead as it has many features and makes everything easier. It allows you to crop the image to any or specified aspect ratio you want and can even compress the image. Here is the link to the package: https://pub.dev/packages/image_cropper

CoderUni
  • 5,474
  • 7
  • 26
  • 58
  • how to add a custom ratio from this package? – jithin Mar 03 '21 at 10:15
  • can please answer in https://stackoverflow.com/questions/66454096/how-to-add-custom-crop-ratio-into-image-cropper-library-flutter ? – jithin Mar 03 '21 at 10:15
  • I couldn't find anything in docs or SC, can you please help me with a code snippet? – jithin Mar 03 '21 at 22:31
  • I found this in ImageCropper's repo: https://github.com/hnvn/flutter_image_cropper/issues/80 – CoderUni Mar 04 '21 at 05:01
  • Thanks, @uni , Yes that's right, but it only helps to show only one aspect ratio in fact if we use aspectRatio it will lock all the list from the aspectRatioPresets. – jithin Mar 04 '21 at 08:03
  • I need to Use 2 custom ratios, but aspectRatio only accepts one. – jithin Mar 04 '21 at 08:04
  • Based from https://github.com/hnvn/flutter_image_cropper/issues/81, ios doesn't support multiple custom ratios during 2019. I'm not sure if it still remains the same this 2021. You'd have to ask the maintainer if this is now supported. – CoderUni Mar 04 '21 at 10:41
4
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image_cropper/image_cropper.dart';

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  /// Variables
  File imageFile;

  /// Widget
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Color(0XFF307777),
          title: Text("Image Cropper"),
        ),
        body: Container(
            child: imageFile == null
                ? Container(
                    alignment: Alignment.center,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        RaisedButton(
                          color: Color(0XFF307777),
                          onPressed: () {
                            _getFromGallery();
                          },
                          child: Text(
                            "PICK FROM GALLERY",
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      ],
                    ),
                  )
                : Container(
                    child: Image.file(
                      imageFile,
                      fit: BoxFit.cover,
                    ),
                  )));
  }

  /// Get from gallery
  _getFromGallery() async {
    PickedFile pickedFile = await ImagePicker().getImage(
      source: ImageSource.gallery,
      maxWidth: 1800,
      maxHeight: 1800,
    );
    _cropImage(pickedFile.path);
  }

  /// Crop Image
  _cropImage(filePath) async {
    File croppedImage = await ImageCropper.cropImage(
      sourcePath: filePath,
      maxWidth: 1080,
      maxHeight: 1080,
    );
    if (croppedImage != null) {
      imageFile = croppedImage;
      setState(() {});
    }
  }
}
Miriam
  • 337
  • 3
  • 6
2

Here I crop file to square.
I use image library.

import 'dart:io';
import 'package:image/image.dart' as img;
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

class CropperService {
  static const _side = 1800;

  Future<File> cropImageFile(File file, [int? side]) async {
    final image = await img.decodeImageFile(file.path);
    if (image == null) throw Exception('Unable to decode image');
    final croppedImage = img.copyResizeCropSquare(image, size: _side);
    final croppedFile = await _convertImageToFile(croppedImage, file.path);
    return croppedFile;
  }

  Future<File> _convertImageToFile(img.Image image, String path) async {
    final newPath = await _croppedFilePath(path);
    final jpegBytes = img.encodeJpg(image);

    final convertedFile = await File(newPath).writeAsBytes(jpegBytes);
    await File(path).delete();
    return convertedFile;
  }

  Future<String> _croppedFilePath(String path) async {
    final tempDir = await getTemporaryDirectory();
    return join(
      tempDir.path,
      '${basenameWithoutExtension(path)}_compressed.jpg',
    );
  }
}
0

Selected image from gallery and we can crop it using image_cropper dependency in flutter.

 Dependency :   image_cropper: ^1.4.1

Code when we select image from gallery:

Future<void> pickFromGallery() async {
try {
  final picker = ImagePicker();
  final pickedImage = await picker.pickImage(source: ImageSource.gallery);

  if (pickedImage == null) return;

  final croppedImage = await ImageCropper().cropImage(
    sourcePath: pickedImage.path,
    aspectRatioPresets: [
      CropAspectRatioPreset.square,
      CropAspectRatioPreset.ratio3x2,
      CropAspectRatioPreset.original,
      CropAspectRatioPreset.ratio4x3,
      CropAspectRatioPreset.ratio16x9
    ],
    androidUiSettings: AndroidUiSettings(
      toolbarTitle: 'Crop Image',
      toolbarColor: Colors.deepOrange,
      toolbarWidgetColor: Colors.white,
      initAspectRatio: CropAspectRatioPreset.original,
      lockAspectRatio: false,
    ),
    iosUiSettings: IOSUiSettings(
      title: 'Crop Image',
      aspectRatioLockEnabled: false,
    ),
  );

  if (croppedImage == null) return;

  final croppedFile = File(croppedImage.path);

  setState(() {
    this.image = croppedFile;
  });

  print("Image path: ${croppedFile.path}");
} on PlatformException catch (e) {
  print("Failed to pick or crop image: $e");
}

}

and please sure to add activity to AndroidManifest.xml file.

    <activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

The output be like :

Crop feature be like

You can crop your image in various size.

Nisha Jain
  • 637
  • 6
  • 14