refactor: Make MatrixFile final and move all image calculation into isolate
This makes all fields in a MatrixFile final and the object therefore stateless. It also moves all calculations into the isolate. After some benchmarks it seems that this does not really speed up the thumbnail creation but it does no longer block the UI for some seconds.
This commit is contained in:
parent
6dbe62424d
commit
9fa5667234
|
|
@ -28,9 +28,9 @@ import 'package:mime/mime.dart';
|
||||||
import '../../matrix.dart';
|
import '../../matrix.dart';
|
||||||
|
|
||||||
class MatrixFile {
|
class MatrixFile {
|
||||||
Uint8List bytes;
|
final Uint8List bytes;
|
||||||
String name;
|
final String name;
|
||||||
String mimeType;
|
final String mimeType;
|
||||||
|
|
||||||
/// Encrypts this file and returns the
|
/// Encrypts this file and returns the
|
||||||
/// encryption information as an [EncryptedFile].
|
/// encryption information as an [EncryptedFile].
|
||||||
|
|
@ -66,14 +66,36 @@ class MatrixFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatrixImageFile extends MatrixFile {
|
class MatrixImageFile extends MatrixFile {
|
||||||
Image? _image;
|
|
||||||
|
|
||||||
MatrixImageFile({
|
MatrixImageFile({
|
||||||
required Uint8List bytes,
|
required Uint8List bytes,
|
||||||
required String name,
|
required String name,
|
||||||
String? mimeType,
|
String? mimeType,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.blurhash,
|
||||||
}) : super(bytes: bytes, name: name, mimeType: mimeType);
|
}) : super(bytes: bytes, name: name, mimeType: mimeType);
|
||||||
|
|
||||||
|
/// Creates a new image file and calculates the width, height and blurhash.
|
||||||
|
static Future<MatrixImageFile> create(
|
||||||
|
{required Uint8List bytes,
|
||||||
|
required String name,
|
||||||
|
String? mimeType,
|
||||||
|
Future<T> Function<T, U>(FutureOr<T> Function(U arg) function, U arg)?
|
||||||
|
compute}) async {
|
||||||
|
final metaData = compute != null
|
||||||
|
? await compute(_calcMetadata, bytes)
|
||||||
|
: _calcMetadata(bytes);
|
||||||
|
|
||||||
|
return MatrixImageFile(
|
||||||
|
bytes: metaData?.bytes ?? bytes,
|
||||||
|
name: name,
|
||||||
|
mimeType: mimeType,
|
||||||
|
width: metaData?.width,
|
||||||
|
height: metaData?.height,
|
||||||
|
blurhash: metaData?.blurhash,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// builds a [MatrixImageFile] and shrinks it in order to reduce traffic
|
/// builds a [MatrixImageFile] and shrinks it in order to reduce traffic
|
||||||
///
|
///
|
||||||
/// in case shrinking does not work (e.g. for unsupported MIME types), the
|
/// in case shrinking does not work (e.g. for unsupported MIME types), the
|
||||||
|
|
@ -85,11 +107,11 @@ class MatrixImageFile extends MatrixFile {
|
||||||
String? mimeType,
|
String? mimeType,
|
||||||
Future<T> Function<T, U>(FutureOr<T> Function(U arg) function, U arg)?
|
Future<T> Function<T, U>(FutureOr<T> Function(U arg) function, U arg)?
|
||||||
compute}) async {
|
compute}) async {
|
||||||
Image? image;
|
|
||||||
final arguments = _ResizeArguments(
|
final arguments = _ResizeArguments(
|
||||||
bytes: bytes,
|
bytes: bytes,
|
||||||
maxDimension: maxDimension,
|
maxDimension: maxDimension,
|
||||||
fileName: name,
|
fileName: name,
|
||||||
|
calcBlurhash: true,
|
||||||
);
|
);
|
||||||
final resizedData = compute != null
|
final resizedData = compute != null
|
||||||
? await compute(_resize, arguments)
|
? await compute(_resize, arguments)
|
||||||
|
|
@ -98,48 +120,26 @@ class MatrixImageFile extends MatrixFile {
|
||||||
if (resizedData == null) {
|
if (resizedData == null) {
|
||||||
return MatrixImageFile(bytes: bytes, name: name, mimeType: mimeType);
|
return MatrixImageFile(bytes: bytes, name: name, mimeType: mimeType);
|
||||||
}
|
}
|
||||||
image = decodeImage(resizedData);
|
|
||||||
|
|
||||||
if (image == null) {
|
|
||||||
return MatrixImageFile(bytes: bytes, name: name, mimeType: mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
final encoded = encodeNamedImage(image, name);
|
|
||||||
if (encoded == null) {
|
|
||||||
return MatrixImageFile(bytes: bytes, name: name, mimeType: mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
final thumbnailFile = MatrixImageFile(
|
final thumbnailFile = MatrixImageFile(
|
||||||
bytes: Uint8List.fromList(encoded),
|
bytes: resizedData.bytes,
|
||||||
name: name,
|
name: name,
|
||||||
mimeType: mimeType,
|
mimeType: mimeType,
|
||||||
|
width: resizedData.width,
|
||||||
|
height: resizedData.height,
|
||||||
|
blurhash: resizedData.blurhash,
|
||||||
);
|
);
|
||||||
// preserving the previously generated image
|
|
||||||
thumbnailFile._image = image;
|
|
||||||
return thumbnailFile;
|
return thumbnailFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns the width of the image
|
/// returns the width of the image
|
||||||
int? get width {
|
final int? width;
|
||||||
_image ??= decodeImage(bytes);
|
|
||||||
return _image?.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns the height of the image
|
/// returns the height of the image
|
||||||
int? get height {
|
final int? height;
|
||||||
_image ??= decodeImage(bytes);
|
|
||||||
return _image?.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// generates the blur hash for the image
|
/// generates the blur hash for the image
|
||||||
String? get blurhash {
|
final String? blurhash;
|
||||||
_image ??= decodeImage(bytes)!;
|
|
||||||
if (_image != null) {
|
|
||||||
final blur = BlurHash.encode(_image!, numCompX: 4, numCompY: 3);
|
|
||||||
return blur.hash;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get msgType => 'm.image';
|
String get msgType => 'm.image';
|
||||||
|
|
@ -171,7 +171,23 @@ class MatrixImageFile extends MatrixFile {
|
||||||
return thumbnailFile;
|
return thumbnailFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8List? _resize(_ResizeArguments arguments) {
|
static _ResizedResponse? _calcMetadata(Uint8List bytes) {
|
||||||
|
final image = decodeImage(bytes);
|
||||||
|
if (image == null) return null;
|
||||||
|
|
||||||
|
return _ResizedResponse(
|
||||||
|
bytes: bytes,
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
blurhash: BlurHash.encode(
|
||||||
|
image,
|
||||||
|
numCompX: 4,
|
||||||
|
numCompY: 3,
|
||||||
|
).hash,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _ResizedResponse? _resize(_ResizeArguments arguments) {
|
||||||
final image = decodeImage(arguments.bytes);
|
final image = decodeImage(arguments.bytes);
|
||||||
|
|
||||||
final resized = copyResize(image!,
|
final resized = copyResize(image!,
|
||||||
|
|
@ -180,26 +196,54 @@ class MatrixImageFile extends MatrixFile {
|
||||||
|
|
||||||
final encoded = encodeNamedImage(resized, arguments.fileName);
|
final encoded = encodeNamedImage(resized, arguments.fileName);
|
||||||
if (encoded == null) return null;
|
if (encoded == null) return null;
|
||||||
return Uint8List.fromList(encoded);
|
final bytes = Uint8List.fromList(encoded);
|
||||||
|
return _ResizedResponse(
|
||||||
|
bytes: bytes,
|
||||||
|
width: resized.width,
|
||||||
|
height: resized.height,
|
||||||
|
blurhash: arguments.calcBlurhash
|
||||||
|
? BlurHash.encode(
|
||||||
|
resized,
|
||||||
|
numCompX: 4,
|
||||||
|
numCompY: 3,
|
||||||
|
).hash
|
||||||
|
: null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ResizedResponse {
|
||||||
|
final Uint8List bytes;
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final String? blurhash;
|
||||||
|
|
||||||
|
const _ResizedResponse({
|
||||||
|
required this.bytes,
|
||||||
|
required this.width,
|
||||||
|
required this.height,
|
||||||
|
this.blurhash,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class _ResizeArguments {
|
class _ResizeArguments {
|
||||||
final Uint8List bytes;
|
final Uint8List bytes;
|
||||||
final int maxDimension;
|
final int maxDimension;
|
||||||
final String fileName;
|
final String fileName;
|
||||||
|
final bool calcBlurhash;
|
||||||
|
|
||||||
const _ResizeArguments({
|
const _ResizeArguments({
|
||||||
required this.bytes,
|
required this.bytes,
|
||||||
required this.maxDimension,
|
required this.maxDimension,
|
||||||
required this.fileName,
|
required this.fileName,
|
||||||
|
required this.calcBlurhash,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatrixVideoFile extends MatrixFile {
|
class MatrixVideoFile extends MatrixFile {
|
||||||
int? width;
|
final int? width;
|
||||||
int? height;
|
final int? height;
|
||||||
int? duration;
|
final int? duration;
|
||||||
|
|
||||||
MatrixVideoFile(
|
MatrixVideoFile(
|
||||||
{required Uint8List bytes,
|
{required Uint8List bytes,
|
||||||
|
|
@ -221,7 +265,7 @@ class MatrixVideoFile extends MatrixFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatrixAudioFile extends MatrixFile {
|
class MatrixAudioFile extends MatrixFile {
|
||||||
int? duration;
|
final int? duration;
|
||||||
|
|
||||||
MatrixAudioFile(
|
MatrixAudioFile(
|
||||||
{required Uint8List bytes,
|
{required Uint8List bytes,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ void main() {
|
||||||
'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';
|
'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';
|
||||||
final data = base64Decode(base64Image);
|
final data = base64Decode(base64Image);
|
||||||
|
|
||||||
final image = MatrixImageFile(
|
final image = await MatrixImageFile.create(
|
||||||
bytes: data,
|
bytes: data,
|
||||||
name: 'bomb.png',
|
name: 'bomb.png',
|
||||||
mimeType: 'image/png',
|
mimeType: 'image/png',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue