diff --git a/lib/src/taro.dart b/lib/src/taro.dart index 6f4b761..8070879 100644 --- a/lib/src/taro.dart +++ b/lib/src/taro.dart @@ -23,11 +23,7 @@ class Taro { final _loader = TaroLoader(); /// The [TaroResizeOption] used to resize images. - TaroResizeOption _resizeOption = const ( - mode: TaroResizeMode.skip, - maxWidth: null, - maxHeight: null, - ); + TaroResizeOption _resizeOption = const TaroResizeOptionSkip(); /// The [TaroResizeOption] used to resize images. /// Changing this option will affect all image loading. @@ -94,10 +90,10 @@ class Taro { headerOption: headerOption ?? _headerOption, ); - if (resizeOption?.mode == TaroResizeMode.memory) { + if (resizeOption is TaroResizeOptionMemory) { return ResizeImage.resizeIfNeeded( - resizeOption?.maxWidth, - resizeOption?.maxHeight, + resizeOption.maxWidth, + resizeOption.maxHeight, image, ); } diff --git a/lib/src/taro_resizer.dart b/lib/src/taro_resizer.dart index 19c1dc3..3a8ce12 100644 --- a/lib/src/taro_resizer.dart +++ b/lib/src/taro_resizer.dart @@ -16,116 +16,117 @@ class TaroResizer { required String contentType, required TaroResizeOption resizeOption, }) async { - if (resizeOption.mode case TaroResizeMode.skip || TaroResizeMode.memory) { - // do nothing - return ( - bytes: bytes, - contentType: contentType, - ); - } + switch (resizeOption) { + case TaroResizeOptionSkip() || TaroResizeOptionMemory(): + // do nothing + return ( + bytes: bytes, + contentType: contentType, + ); + case TaroResizeOptionDisk( + format: final optionFormat, + maxWidth: final optionMaxWidth, + maxHeight: final optionMaxHeight, + ): + final originalImage = img.decodeImage(bytes); + if (originalImage == null) { + return throw TaroResizeException( + exception: Exception('Failed to decode image.'), + ); + } - final originalImage = img.decodeImage(bytes); - if (originalImage == null) { - return throw TaroResizeException( - exception: Exception('Failed to decode image.'), - ); - } + final int maxWidth; + if (optionMaxWidth != null) { + maxWidth = min(optionMaxWidth, originalImage.width); + } else { + maxWidth = originalImage.width; + } - final int maxWidth; - if (resizeOption.maxWidth != null) { - maxWidth = min(resizeOption.maxWidth!, originalImage.width); - } else { - maxWidth = originalImage.width; - } + final int maxHeight; + if (optionMaxHeight != null) { + maxHeight = min(optionMaxHeight, originalImage.height); + } else { + maxHeight = originalImage.height; + } - final int maxHeight; - if (resizeOption.maxHeight != null) { - maxHeight = min(resizeOption.maxHeight!, originalImage.height); - } else { - maxHeight = originalImage.height; - } + if (maxWidth == originalImage.width && + maxHeight == originalImage.height) { + return ( + bytes: bytes, + contentType: contentType, + ); + } - if (maxWidth == originalImage.width && maxHeight == originalImage.height) { - return ( - bytes: bytes, - contentType: contentType, - ); - } + final cmd = img.Command() + ..image(originalImage) + ..copyResize( + width: maxWidth, + height: maxHeight, + ); - final cmd = img.Command() - ..image(originalImage) - ..copyResize( - width: maxWidth, - height: maxHeight, - ); + final String encodeImageType; + switch (optionFormat) { + case TaroResizeFormat.original: + switch (contentType) { + case 'image/gif': + case 'image/jpeg': + case 'image/png': + case 'image/bmp': + case 'image/x-icon': + case 'image/tiff': + encodeImageType = contentType; + default: + encodeImageType = 'image/png'; + } + case TaroResizeFormat.gif: + encodeImageType = 'image/gif'; + case TaroResizeFormat.jpeg: + encodeImageType = 'image/jpeg'; + case TaroResizeFormat.png: + encodeImageType = 'image/png'; + case TaroResizeFormat.bmp: + encodeImageType = 'image/bmp'; + case TaroResizeFormat.ico: + encodeImageType = 'image/x-icon'; + case TaroResizeFormat.tiff: + encodeImageType = 'image/tiff'; + } - final String encodeImageType; - switch (resizeOption.mode) { - case TaroResizeMode.skip: - // this case is not possible - throw Exception('This case is not possible.'); - case TaroResizeMode.original: - switch (contentType) { + switch (encodeImageType) { case 'image/gif': + cmd.encodeGif(); case 'image/jpeg': + cmd.encodeJpg(); case 'image/png': + cmd.encodePng(); case 'image/bmp': + cmd.encodeBmp(); case 'image/x-icon': + cmd.encodeIco(); case 'image/tiff': - encodeImageType = contentType; + cmd.encodeTiff(); default: - encodeImageType = 'image/png'; + // if the contentType is not supported, encode the image to png + cmd.encodePng(); } - case TaroResizeMode.gif: - encodeImageType = 'image/gif'; - case TaroResizeMode.jpeg: - encodeImageType = 'image/jpeg'; - case TaroResizeMode.png: - encodeImageType = 'image/png'; - case TaroResizeMode.bmp: - encodeImageType = 'image/bmp'; - case TaroResizeMode.ico: - encodeImageType = 'image/x-icon'; - case TaroResizeMode.tiff: - encodeImageType = 'image/tiff'; - default: - encodeImageType = 'image/png'; - } - switch (encodeImageType) { - case 'image/gif': - cmd.encodeGif(); - case 'image/jpeg': - cmd.encodeJpg(); - case 'image/png': - cmd.encodePng(); - case 'image/bmp': - cmd.encodeBmp(); - case 'image/x-icon': - cmd.encodeIco(); - case 'image/tiff': - cmd.encodeTiff(); - default: - // if the contentType is not supported, encode the image to png - cmd.encodePng(); - } + final Uint8List? result; + try { + result = await cmd.getBytesThread(); + } on Exception catch (exception) { + throw TaroResizeException( + exception: exception, + ); + } - final Uint8List? result; - try { - result = await cmd.getBytesThread(); - } on Exception catch (exception) { - throw TaroResizeException( - exception: exception, - ); - } + if (result == null) { + throw const TaroResizeFailedException(); + } - if (result == null) { - throw const TaroResizeFailedException(); + return ( + bytes: result, + contentType: encodeImageType, + ); } - - return ( - bytes: result, - contentType: encodeImageType, - ); } } diff --git a/lib/src/taro_type.dart b/lib/src/taro_type.dart index b8aee65..552928f 100644 --- a/lib/src/taro_type.dart +++ b/lib/src/taro_type.dart @@ -1,43 +1,65 @@ -/// [TaroRequestOption] is used to configure the options for a resizing request. -typedef TaroResizeOption = ({ - /// The resize mode of the image. - TaroResizeMode mode, +/// The [TaroResizeOption] is used to determine how images are resized and saved. +/// Please refer to [https://pub.dev/packages/image] for supported formats. +sealed class TaroResizeOption { + const TaroResizeOption(); +} - /// The maximum width of the image. If null, the width is not limited. - int? maxWidth, +/// The image is not resized, saved original size and format. +class TaroResizeOptionSkip extends TaroResizeOption { + const TaroResizeOptionSkip(); +} - /// The maximum height of the image. If null, the height is not limited. - int? maxHeight, -}); +/// The image is resized in memory, saved original size and format. +class TaroResizeOptionMemory extends TaroResizeOption { + const TaroResizeOptionMemory({ + required this.maxWidth, + required this.maxHeight, + }); -/// The [TaroResizeMode] enum is used to determine how images are resized. -/// Please refer to [https://pub.dev/packages/image] for supported formats. -enum TaroResizeMode { - /// The image is not resized. - skip, + /// The maximum width of the image. + final int maxWidth; - /// The image is resized and saved original image. - memory, + /// The maximum height of the image. + final int maxHeight; +} + +class TaroResizeOptionDisk extends TaroResizeOption { + const TaroResizeOptionDisk({ + required this.format, + this.maxWidth, + this.maxHeight, + }); + + /// The format of the image. + final TaroResizeFormat format; + + /// The maximum width of the image. If null, the width is not limited. + final int? maxWidth; + + /// The maximum height of the image. If null, the height is not limited. + final int? maxHeight; +} - /// The image is resized to the original contentType and saved cache. +enum TaroResizeFormat { + /// The original format of the image. original, - /// The image is resized to a gif and saved cache. + /// The image is saved as a gif. gif, - /// The image is resized to a jpg and saved cache. + /// The image is saved as a jpeg. jpeg, - /// The image is resized to a png and saved cache. + /// The image is saved as a png. png, - /// The image is resized to a bmp and saved cache. + /// The image is saved as a bmp. bmp, - /// The image is resized to a ico and saved cache. + /// The image is saved as an icon. ico, - /// The image is resized to a tiff and saved cache. + /// The image is saved as a tiff. tiff, } diff --git a/test/taro_loader_network_test.dart b/test/taro_loader_network_test.dart index e0c7504..67af150 100644 --- a/test/taro_loader_network_test.dart +++ b/test/taro_loader_network_test.dart @@ -27,11 +27,7 @@ void main() { ); final bodyBytes = Uint8List(100); - const resizeOption = ( - mode: TaroResizeMode.skip, - maxWidth: null, - maxHeight: null, - ); + const resizeOption = TaroResizeOptionSkip(); const headerOption = ( checkMaxAgeIfExist: false, ifThrowMaxAgeHeaderError: false, diff --git a/test/taro_loader_network_test.mocks.dart b/test/taro_loader_network_test.mocks.dart index 718de1f..6b88f18 100644 --- a/test/taro_loader_network_test.mocks.dart +++ b/test/taro_loader_network_test.mocks.dart @@ -125,11 +125,7 @@ class MockTaroResizer extends _i1.Mock implements _i5.TaroResizer { _i3.Future<({_i4.Uint8List bytes, String contentType})> resizeIfNeeded({ required _i4.Uint8List? bytes, required String? contentType, - required ({ - int? maxHeight, - int? maxWidth, - _i6.TaroResizeMode mode - })? resizeOption, + required _i6.TaroResizeOption? resizeOption, }) => (super.noSuchMethod( Invocation.method(