feat: allow updating image size

This commit is contained in:
Henri Carnot 2022-05-31 20:32:35 +00:00 committed by Nicolas Werner
parent 525f45940e
commit 69dacc8ccd
2 changed files with 71 additions and 38 deletions

View File

@ -98,10 +98,9 @@ class MatrixImageFile extends MatrixFile {
); );
} }
/// builds a [MatrixImageFile] and shrinks it in order to reduce traffic /// Builds a [MatrixImageFile] and shrinks it in order to reduce traffic.
/// /// If shrinking does not work (e.g. for unsupported MIME types), the
/// in case shrinking does not work (e.g. for unsupported MIME types), the /// initial image is preserved without shrinking it.
/// initial image is simply preserved
static Future<MatrixImageFile> shrink( static Future<MatrixImageFile> shrink(
{required Uint8List bytes, {required Uint8List bytes,
required String name, required String name,
@ -112,31 +111,13 @@ class MatrixImageFile extends MatrixFile {
customImageResizer, customImageResizer,
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 {
final arguments = MatrixImageFileResizeArguments( final image = MatrixImageFile(name: name, mimeType: mimeType, bytes: bytes);
bytes: bytes,
maxDimension: maxDimension,
fileName: name,
calcBlurhash: true,
);
final resizedData = customImageResizer != null
? await customImageResizer(arguments)
: compute != null
? await compute(_resize, arguments)
: _resize(arguments);
if (resizedData == null) { return await image.generateThumbnail(
return MatrixImageFile(bytes: bytes, name: name, mimeType: mimeType); dimension: maxDimension,
} customImageResizer: customImageResizer,
compute: compute) ??
final thumbnailFile = MatrixImageFile( image;
bytes: resizedData.bytes,
name: name,
mimeType: mimeType,
width: resizedData.width,
height: resizedData.height,
blurhash: resizedData.blurhash,
);
return thumbnailFile;
} }
int? _width; int? _width;
@ -150,7 +131,7 @@ class MatrixImageFile extends MatrixFile {
int? get height => _height; int? get height => _height;
/// If the image size is null, allow us to update it's value. /// If the image size is null, allow us to update it's value.
void setImageSizeIfNull({required int width, required int height}) { void setImageSizeIfNull({required int? width, required int? height}) {
_width ??= width; _width ??= width;
_height ??= height; _height ??= height;
} }
@ -168,7 +149,8 @@ class MatrixImageFile extends MatrixFile {
if (blurhash != null) 'xyz.amorgan.blurhash': blurhash, if (blurhash != null) 'xyz.amorgan.blurhash': blurhash,
}); });
/// computes a thumbnail for the image /// Computes a thumbnail for the image.
/// Also sets height and width on the original image if they were unset.
Future<MatrixImageFile?> generateThumbnail( Future<MatrixImageFile?> generateThumbnail(
{int dimension = Client.defaultThumbnailSize, {int dimension = Client.defaultThumbnailSize,
Future<MatrixImageFileResizedResponse?> Function( Future<MatrixImageFileResizedResponse?> Function(
@ -176,19 +158,39 @@ class MatrixImageFile extends MatrixFile {
customImageResizer, customImageResizer,
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 {
final thumbnailFile = await shrink( final arguments = MatrixImageFileResizeArguments(
bytes: bytes, bytes: bytes,
name: name,
mimeType: mimeType,
compute: compute,
maxDimension: dimension, maxDimension: dimension,
customImageResizer: customImageResizer, fileName: name,
calcBlurhash: true,
); );
// the thumbnail should rather return null than the unshrinked image final resizedData = customImageResizer != null
if ((thumbnailFile.width ?? 0) > dimension || ? await customImageResizer(arguments)
(thumbnailFile.height ?? 0) > dimension) { : compute != null
? await compute(_resize, arguments)
: _resize(arguments);
if (resizedData == null) {
return null; return null;
} }
// we should take the opportinity to update the image dimmension
setImageSizeIfNull(
width: resizedData.originalWidth, height: resizedData.originalHeight);
// the thumbnail should rather return null than the unshrinked image
if (resizedData.width > dimension || resizedData.height > dimension) {
return null;
}
final thumbnailFile = MatrixImageFile(
bytes: resizedData.bytes,
name: name,
mimeType: mimeType,
width: resizedData.width,
height: resizedData.height,
blurhash: resizedData.blurhash,
);
return thumbnailFile; return thumbnailFile;
} }
@ -223,6 +225,8 @@ class MatrixImageFile extends MatrixFile {
bytes: bytes, bytes: bytes,
width: resized.width, width: resized.width,
height: resized.height, height: resized.height,
originalHeight: image.height,
originalWidth: image.width,
blurhash: arguments.calcBlurhash blurhash: arguments.calcBlurhash
? BlurHash.encode( ? BlurHash.encode(
resized, resized,
@ -240,10 +244,15 @@ class MatrixImageFileResizedResponse {
final int height; final int height;
final String? blurhash; final String? blurhash;
final int? originalHeight;
final int? originalWidth;
const MatrixImageFileResizedResponse({ const MatrixImageFileResizedResponse({
required this.bytes, required this.bytes,
required this.width, required this.width,
required this.height, required this.height,
this.originalHeight,
this.originalWidth,
this.blurhash, this.blurhash,
}); });
} }

View File

@ -22,6 +22,7 @@ import 'package:matrix/matrix.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm; import 'package:olm/olm.dart' as olm;
import 'package:http/http.dart' as http;
void main() { void main() {
/// All Tests related to device keys /// All Tests related to device keys
@ -45,5 +46,28 @@ void main() {
expect(encryptedFile.data.isNotEmpty, true); expect(encryptedFile.data.isNotEmpty, true);
} }
}); });
test('Shrink', () async {
final resp = await http.get(Uri.parse(
'https://upload.wikimedia.org/wikipedia/commons/5/5f/Salagou_Lake%2C_Celles_cf01.jpg'));
if (resp.statusCode == 200) {
final file = MatrixImageFile(
name: 'file.jpg',
bytes: resp.bodyBytes,
);
expect(file.bytes.isNotEmpty, true);
expect(file.height, null);
expect(file.width, null);
final thumb = await file.generateThumbnail();
expect(thumb != null, true);
// and the image size where updated
expect(file.height, 4552);
expect(file.width, 7283);
}
});
}); });
} }