cropImage method

  1. @override
Future<CroppedFile?> cropImage({
  1. required String sourcePath,
  2. int? maxWidth,
  3. int? maxHeight,
  4. CropAspectRatio? aspectRatio,
  5. List<CropAspectRatioPreset> aspectRatioPresets = const [CropAspectRatioPreset.original, CropAspectRatioPreset.square, CropAspectRatioPreset.ratio3x2, CropAspectRatioPreset.ratio4x3, CropAspectRatioPreset.ratio16x9],
  6. CropStyle cropStyle = CropStyle.rectangle,
  7. ImageCompressFormat compressFormat = ImageCompressFormat.jpg,
  8. int compressQuality = 90,
  9. List<PlatformUiSettings>? uiSettings,
})

Launch cropper UI for an image.

parameters:

  • sourcePath: the absolute path of an image file.

  • maxWidth: maximum cropped image width. (IGNORED)

  • maxHeight: maximum cropped image height. (IGNORED)

  • aspectRatio: controls the aspect ratio of crop bounds. If this values is set, the cropper is locked and user can't change the aspect ratio of crop bounds. (IGNORED)

  • aspectRatioPresets: controls the list of aspect ratios in the crop menu view. In Android, you can set the initialized aspect ratio when starting the cropper by setting the value of AndroidUiSettings.initAspectRatio. Default is a list of CropAspectRatioPreset.original, CropAspectRatioPreset.square, CropAspectRatioPreset.ratio3x2, CropAspectRatioPreset.ratio4x3 and CropAspectRatioPreset.ratio16x9. (IGNORED)

  • cropStyle: controls the style of crop bounds, it can be rectangle or circle style (default is CropStyle.rectangle). This field can be overrided by WebUiSettings.viewPort.type

  • compressFormat: the format of result image, png or jpg (default is ImageCompressFormat.jpg)

  • compressQuality: the value 0 - 100 to control the quality of image compression

  • uiSettings: controls UI customization on specific platform (android, ios, web,...). This field is required and must provide WebUiSettings

return:

A result file of the cropped image.

Implementation

@override
Future<CroppedFile?> cropImage({
  required String sourcePath,
  int? maxWidth,
  int? maxHeight,
  CropAspectRatio? aspectRatio,
  List<CropAspectRatioPreset> aspectRatioPresets = const [
    CropAspectRatioPreset.original,
    CropAspectRatioPreset.square,
    CropAspectRatioPreset.ratio3x2,
    CropAspectRatioPreset.ratio4x3,
    CropAspectRatioPreset.ratio16x9
  ],
  CropStyle cropStyle = CropStyle.rectangle,
  ImageCompressFormat compressFormat = ImageCompressFormat.jpg,
  int compressQuality = 90,
  List<PlatformUiSettings>? uiSettings,
}) async {
  WebUiSettings? webSettings;
  for (final settings in uiSettings ?? <PlatformUiSettings>[]) {
    if (settings is WebUiSettings) {
      webSettings = settings;
      break;
    }
  }
  if (webSettings == null) {
    assert(true, 'must provide WebUiSettings to run on Web');
    throw 'must provide WebUiSettings to run on Web';
  }

  final context = webSettings.context;
  final shapeType = cropStyle == CropStyle.circle ? 'circle' : 'square';

  final element = html.DivElement();
  final option = Options(
    boundary: webSettings.boundary == null
        ? Boundary(width: 500, height: 500)
        : Boundary(
            width: webSettings.boundary!.width ?? 500,
            height: webSettings.boundary!.height ?? 500,
          ),
    viewport: webSettings.viewPort == null
        ? ViewPort(width: 400, height: 400, type: shapeType)
        : ViewPort(
            width: webSettings.viewPort!.width ?? 400,
            height: webSettings.viewPort!.height ?? 400,
            type: webSettings.viewPort!.type ?? shapeType,
          ),
    customClass: webSettings.customClass,
    enableExif: webSettings.enableExif ?? true,
    enableOrientation: webSettings.enableOrientation ?? true,
    enableZoom: webSettings.enableZoom ?? false,
    enableResize: webSettings.enableResize ?? false,
    enforceBoundary: webSettings.enforceBoundary ?? true,
    mouseWheelZoom: webSettings.mouseWheelZoom ?? true,
    showZoomer: webSettings.showZoomer ?? true,
  );
  final croppie = Croppie(element, option);
  croppie.bind(BindConfiguration(url: sourcePath));

  final viewId = 'croppie-view-${DateTime.now().millisecondsSinceEpoch}';

  // ignore: undefined_prefixed_name
  ui.platformViewRegistry
      .registerViewFactory(viewId, (int viewId) => element);

  final cropper = HtmlElementView(
    key: UniqueKey(),
    viewType: viewId,
  );

  final format = compressFormat == ImageCompressFormat.png ? 'png' : 'jpeg';
  final quality = compressQuality * 1.0 / 100;

  Future<String?> doCrop() async {
    final blob = await croppie.resultBlob(
      format: format,
      quality: quality,
    );
    if (blob != null) {
      final blobUrl = html.Url.createObjectUrlFromBlob(blob);
      return blobUrl;
    }
    return null;
  }

  void doRotate(RotationAngle angle) {
    croppie.rotate(rotationAngleToNumber(angle));
  }

  final cropperWidth = option.boundary?.width ?? 500;
  final cropperHeight = option.boundary?.height ?? 500;
  if (webSettings.presentStyle == CropperPresentStyle.page) {
    PageRoute<String> pageRoute;
    if (webSettings.customRouteBuilder != null) {
      pageRoute = webSettings.customRouteBuilder!(cropper, doCrop, doRotate);
    } else {
      pageRoute = MaterialPageRoute(
        builder: (c) => CropperPage(
          cropper: cropper,
          crop: doCrop,
          rotate: doRotate,
          cropperContainerWidth: cropperWidth + 50.0,
          cropperContainerHeight: cropperHeight + 50.0,
          translations:
              webSettings?.translations ?? const WebTranslations.en(),
        ),
      );
    }
    final result = await Navigator.of(context).push<String>(pageRoute);

    return result != null ? CroppedFile(result) : null;
  } else {
    Dialog cropperDialog;
    if (webSettings.customDialogBuilder != null) {
      cropperDialog =
          webSettings.customDialogBuilder!(cropper, doCrop, doRotate);
    } else {
      cropperDialog = Dialog(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12.0),
        ),
        child: CropperDialog(
          cropper: cropper,
          crop: doCrop,
          rotate: doRotate,
          cropperContainerWidth: cropperWidth + 50.0,
          cropperContainerHeight: cropperHeight + 50.0,
          translations:
              webSettings.translations ?? const WebTranslations.en(),
        ),
      );
    }
    final result = await showDialog<String?>(
      context: context,
      barrierColor: webSettings.barrierColor,
      builder: (_) => cropperDialog,
    );

    return result != null ? CroppedFile(result) : null;
  }
}