如何在Flutter中裁剪图像?

47

假设我有一张竖向的矩形图片:

输入图像描述

我想对其进行剪裁,使其呈现如下:

输入图像描述

在Flutter中如何实现此操作?

(我不需要调整图片大小。)

(图片来自https://flic.kr/p/nwXTDb

9个回答

79

我可能会使用 BoxDecoration 和一个 DecorationImage。你可以使用 alignmentfit 属性来确定你的图像如何裁剪。如果你不想在 Container 上硬编码高度,可以使用 AspectRatio 组件。

截屏

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://istack.dev59.com/lkd0a.webp'),
              )
            ),
          ),
        ),
      ),
    );
  }
}

1
哇,我有不同的问题,但这个BoxDecoration技巧对我有帮助。谢谢啊 :) - Piyush Kumar
9
您试图在呈现文件时进行裁剪。然而,我希望存储图像的裁剪版本,然后再对其进行呈现。您知道是否有这样的技术或软件包吗? - Karan Saluja
1
嗨,我想要在两个方向上显示图像的一部分。比如说我有一个1080x1920的图像,我想要显示(x=100200, y=300400)这一部分。因此我不能使用fit+alignment方法。我该怎么做呢?谢谢! - ch271828n

30

您还可以直接使用 Image 类与BoxFit一起使用,实现类似以下的效果:

new Image.asset(
  stringToImageLocation,
  fit: BoxFit.cover,
)

1
曾经使用过 DecorationImage - Padmal
3
嗨,我想在两个方向上显示图像的一部分。比如说,我有一个1080x1920的图像,我想显示(x=100200, y=300400)这一部分。因此,我不能使用fit+alignment方法。我该怎么做呢?谢谢! - ch271828n

17

为您的Image小部件提供一个适合的因子,然后将其包装在AspectRatio中。

AspectRatio(
  aspectRatio: 1.5, 
  child: Image.asset(
    'your_image_asset',
    fit: BoxFit.cover,
  ),
)

3
到目前为止,最有用的答案 <3 帮得好! - 钟智强

15

看看brendan-duncan/image,这是一个用于在Dart中操作图像的平台无关库。

您可以使用以下函数:

Image copyCrop(Image src, int x, int y, int w, int h);

谢谢!你试过用Flutter吗?我想知道如何在Brendan的图像库中获取Flutter图像。 - Seth Ladd
3
我认为Flutter没有提供一种简单的方法来获取ui.Image解码后的图像。但是,如果您使用Brendan的图像库进行解码,您可以调用image.getBytes()并将其传递给new Image.memory - Collin Jackson
2
能否提供一个Flutter从网络图片中裁剪特定区域的示例?我正在尝试在特定的 { x: 897, y: 235, width: 845, height: 845 } 值处裁剪图片,但找不到适合我的方法。 - Mārtiņš Ciekurs

5

我只使用了这2个属性,就成功运作了:

CachedNetworkImage(
  fit: BoxFit.cover,// OR BoxFit.fitWidth
  alignment: FractionalOffset.topCenter,
  ....
)

4

有一个新的包叫做ImageCropper。我建议大家使用它,因为它拥有许多功能,使一切变得更加容易。它允许您将图像裁剪到任意或指定的纵横比,并且甚至可以压缩图像。这是该软件包的链接:https://pub.dev/packages/image_cropper


如何从这个包中添加自定义比率? - jithin
我在ImageCropper的存储库中发现了这个:https://github.com/hnvn/flutter_image_cropper/issues/80 - CoderUni
谢谢,@uni,是的,没错,但这只能帮助显示一个纵横比。实际上,如果我们使用aspectRatio,它将锁定所有列表,从aspectRatioPresets中选择。 - jithin
我需要使用2个自定义比例,但是aspectRatio只能接受一个。 - jithin
根据 https://github.com/hnvn/flutter_image_cropper/issues/81,2019 年 iOS 不支持多个自定义比例。我不确定在 2021 年是否仍然保持不变。如果您想知道现在是否支持,请向维护者询问。 - CoderUni
显示剩余2条评论

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(() {});
    }
  }
}

2

在这里,我将文件裁剪成正方形。
我使用image库。

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',
    );
  }
}

谢谢,这段代码让我朝着正确的方向开始了!不知道是否有避免使用临时文件的方法? - Jennifer Zouak
我猜您可以根据您的需求使用getApplicationDocumentsDirectory或getApplicationSupportDirectory。 - Angelina Gromova

0

从图库中选择图片,我们可以使用Flutter中的image_cropper依赖来裁剪它。

 Dependency :   image_cropper: ^1.4.1

从相册选择图像时的代码:

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");
}

}

请确保将活动添加到AndroidManifest.xml文件中。
    <activity
        android:name="com.yalantis.ucrop.UCropActivity"
        android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

输出会像这样:

Crop feature be like

您可以按照不同的尺寸裁剪您的图片。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接