From a3f1601db863b5b1a0eebd08311467836a7b789c Mon Sep 17 00:00:00 2001 From: Erick Date: Fri, 31 Mar 2023 08:39:08 -0300 Subject: [PATCH] feat: Adding ImageExtension.resize (#2418) Adds a helper method to ImageExtension to make it easier to resize an image. --- examples/lib/main.dart | 2 ++ examples/lib/stories/image/image.dart | 23 +++++++++++++++ examples/lib/stories/image/resize.dart | 29 +++++++++++++++++++ examples/pubspec.yaml | 3 +- packages/flame/lib/src/extensions/image.dart | 25 +++++++++++++++- .../test/extensions/image_extension_test.dart | 16 ++++++++++ 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 examples/lib/stories/image/image.dart create mode 100644 examples/lib/stories/image/resize.dart diff --git a/examples/lib/main.dart b/examples/lib/main.dart index 1a302c6fc..5f39aa024 100644 --- a/examples/lib/main.dart +++ b/examples/lib/main.dart @@ -18,6 +18,7 @@ import 'package:examples/stories/components/components.dart'; import 'package:examples/stories/effects/effects.dart'; import 'package:examples/stories/experimental/experimental.dart'; import 'package:examples/stories/games/games.dart'; +import 'package:examples/stories/image/image.dart'; import 'package:examples/stories/input/input.dart'; import 'package:examples/stories/layout/layout.dart'; import 'package:examples/stories/parallax/parallax.dart'; @@ -77,6 +78,7 @@ void runAsDashbook() { addSystemStories(dashbook); addUtilsStories(dashbook); addWidgetsStories(dashbook); + addImageStories(dashbook); // Bridge package examples addForge2DStories(dashbook); diff --git a/examples/lib/stories/image/image.dart b/examples/lib/stories/image/image.dart new file mode 100644 index 000000000..af4eae7bf --- /dev/null +++ b/examples/lib/stories/image/image.dart @@ -0,0 +1,23 @@ +import 'package:dashbook/dashbook.dart'; + +import 'package:examples/commons/commons.dart'; +import 'package:examples/stories/image/resize.dart'; +import 'package:flame/game.dart'; + +void addImageStories(Dashbook dashbook) { + dashbook.storiesOf('Image') + ..decorator(CenterDecorator()) + ..add( + 'resize', + (context) => GameWidget( + game: ImageResizeExample( + Vector2( + context.numberProperty('width', 200), + context.numberProperty('height', 300), + ), + ), + ), + codeLink: baseLink('image/resize.dart'), + info: ImageResizeExample.description, + ); +} diff --git a/examples/lib/stories/image/resize.dart b/examples/lib/stories/image/resize.dart new file mode 100644 index 000000000..667f5e4ce --- /dev/null +++ b/examples/lib/stories/image/resize.dart @@ -0,0 +1,29 @@ +import 'package:flame/components.dart'; +import 'package:flame/extensions.dart'; +import 'package:flame/game.dart'; + +class ImageResizeExample extends FlameGame { + ImageResizeExample(this.sizeTarget); + + static const String description = ''' + Shows how a dart:ui `Image` can be resized using Flame Image extensions. + Use the properties on the side to change the size of the image. + '''; + + final Vector2 sizeTarget; + + @override + Future onLoad() async { + final image = await images.load('flame.png'); + + final resized = await image.resize(sizeTarget); + add( + SpriteComponent( + sprite: Sprite(resized), + position: size / 2, + size: resized.size, + anchor: Anchor.center, + ), + ); + } +} diff --git a/examples/pubspec.yaml b/examples/pubspec.yaml index 9b4f7ea9e..8de9ead7b 100644 --- a/examples/pubspec.yaml +++ b/examples/pubspec.yaml @@ -26,11 +26,12 @@ dependencies: padracing: ^1.0.0 provider: ^6.0.3 rogue_shooter: ^0.1.0 - test: ^1.23.1 trex_game: ^0.1.0 dev_dependencies: flame_lint: ^0.2.0 + test: any + flutter: uses-material-design: true diff --git a/packages/flame/lib/src/extensions/image.dart b/packages/flame/lib/src/extensions/image.dart index ba23d5350..817a1edbc 100644 --- a/packages/flame/lib/src/extensions/image.dart +++ b/packages/flame/lib/src/extensions/image.dart @@ -2,12 +2,14 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:ui'; -import 'package:flame/src/extensions/color.dart'; +import 'package:flame/palette.dart'; import 'package:flame/src/extensions/vector2.dart'; export 'dart:ui' show Image; extension ImageExtension on Image { + static final Paint _whitePaint = BasicPalette.white.paint(); + /// Converts a raw list of pixel values into an [Image] object. /// /// The pixels must be in the RGBA format, i.e. first 4 bytes encode the red, @@ -90,4 +92,25 @@ extension ImageExtension on Image { } return fromPixels(newPixelData, width, height); } + + /// Resizes this image to the given [newSize]. + /// + /// Keep in mind that is considered an expensive operation and should be + /// avoided in the the game loop methods. Prefer using it + /// in the loading phase of the game or components. + Future resize(Vector2 newSize) async { + final recorder = PictureRecorder(); + Canvas(recorder).drawImageRect( + this, + getBoundingRect(), + newSize.toRect(), + _whitePaint, + ); + final picture = recorder.endRecording(); + final resizedImage = await picture.toImage( + newSize.x.toInt(), + newSize.y.toInt(), + ); + return resizedImage; + } } diff --git a/packages/flame/test/extensions/image_extension_test.dart b/packages/flame/test/extensions/image_extension_test.dart index a97a06bbd..4238b5975 100644 --- a/packages/flame/test/extensions/image_extension_test.dart +++ b/packages/flame/test/extensions/image_extension_test.dart @@ -1,8 +1,10 @@ import 'dart:math'; import 'dart:typed_data'; +import 'dart:ui'; import 'package:flame/extensions.dart'; import 'package:flame_test/flame_test.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; final output = List.filled(8 * 8 * 4, 255); @@ -151,5 +153,19 @@ void main() { ); expect(orignalBrightenPixelsList, expectedBrightenPixels); }); + + test('resize resizes the image', () async { + final recorder = PictureRecorder(); + Canvas(recorder).drawRect( + const Rect.fromLTWH(0, 0, 100, 100), + Paint()..color = Colors.white, + ); + final pic = recorder.endRecording(); + final image = await pic.toImage(100, 100); + + final resizedImage = await image.resize(Vector2(200, 400)); + expect(resizedImage.width, equals(200)); + expect(resizedImage.height, equals(400)); + }); }); }