Skip to content

Instantly share code, notes, and snippets.

@alexmercerind
Last active January 5, 2023 13:29
Show Gist options
  • Save alexmercerind/688b73fdfdc33e0bf1937604ded13afa to your computer and use it in GitHub Desktop.
Save alexmercerind/688b73fdfdc33e0bf1937604ded13afa to your computer and use it in GitHub Desktop.
crop image to square in Dart
import 'dart:io';
import 'dart:math';
import 'dart:isolate';
import 'package:image/image.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'package:safe_local_storage/safe_local_storage.dart';
/// This method crops passed given [image] into square & returns it
/// as [Uint8List] in JPEG format.
/// The passed [image] may be:
/// * [Uri] or [String] - URL to the image.
/// * [File] - local file.
/// * [Uint8List] or [List<int>] - encoded image data.
///
/// The method is asynchronous & works on separate isolate & thus, performant.
///
/// This is specifically used in the native notifications i.e. System Media Transport Controls, MPRIS & Android Media Session.
///
Future<Uint8List?> imageCropSquare(dynamic image) async {
final receivePort = ReceivePort();
await Isolate.spawn(
_cropSquareIsolate,
_DecodeParam(
image,
receivePort.sendPort,
),
);
final result = await receivePort.first;
receivePort.close();
assert(result is Uint8List || result == null);
return result;
}
/// Used for packing parameters for [_cropSquareIsolate] method.
class _DecodeParam {
final dynamic image;
final SendPort sendPort;
_DecodeParam(
this.image,
this.sendPort,
);
}
/// Method spawned on another isolate for [imageCropSquare].
///
/// Returns `null` if passed [data.image] is in unknown format or
/// original image if some other error is received.
///
void _cropSquareIsolate(_DecodeParam data) async {
Uint8List? buffer;
if (data.image is Uint8List || data.image is List<int>) {
buffer = data.image;
} else if (data.image is Uri || data.image is String) {
try {
final response = await http.get(
data.image is Uri ? data.image : Uri.parse(data.image),
);
buffer = response.bodyBytes;
} catch (exception, stacktrace) {
debugPrint(exception.toString());
debugPrint(stacktrace.toString());
}
} else if (data.image is File) {
try {
buffer = await (data.image as File).readAsBytes_();
} catch (exception, stacktrace) {
debugPrint(exception.toString());
debugPrint(stacktrace.toString());
}
}
if (buffer != null) {
try {
final image = decodeImage(buffer);
if (image != null && image.width != 0 && image.height != 0) {
final dimension = min(image.width, image.height);
final result = copyResizeCropSquare(image, dimension);
data.sendPort.send(encodeJpg(result));
}
return data.sendPort.send(buffer);
} catch (exception, stacktrace) {
debugPrint(exception.toString());
debugPrint(stacktrace.toString());
}
}
data.sendPort.send(null);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment