LCOV - code coverage report
Current view: top level - lib - image_composition.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 8 37 21.6 %
Date: 2021-08-10 15:50:53 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:ui';
       3             : 
       4             : import 'extensions.dart';
       5             : 
       6             : export 'extensions.dart';
       7             : 
       8             : class _Composed {
       9             :   /// The image that will be composed.
      10             :   final Image image;
      11             : 
      12             :   /// The position where the [image] will be composed.
      13             :   final Vector2 position;
      14             : 
      15             :   /// The source on the [image] that will be composed.
      16             :   final Rect source;
      17             : 
      18             :   /// The angle (in radians) used to rotate the [image] around it's [anchor].
      19             :   final double angle;
      20             : 
      21             :   /// The point around which the [image] will be rotated
      22             :   /// (defaults to the centre of the [source]).
      23             :   final Vector2 anchor;
      24             : 
      25             :   final bool isAntiAlias;
      26             : 
      27             :   /// The [BlendMode] that will be used when composing the [image].
      28             :   final BlendMode blendMode;
      29             : 
      30           0 :   _Composed(
      31             :     this.image,
      32             :     this.position,
      33             :     this.source,
      34             :     this.angle,
      35             :     this.anchor,
      36             :     this.isAntiAlias,
      37             :     this.blendMode,
      38             :   );
      39             : }
      40             : 
      41             : /// The [ImageComposition] allows for composing multiple images onto a single image.
      42             : ///
      43             : /// **Note:** Composing images is a heavy async operation and should not be called inside the game loop.
      44             : class ImageComposition {
      45             :   /// The values that will be used to compose the image
      46             :   final List<_Composed> _composes = [];
      47             : 
      48             :   /// The [defaultBlendMode] can be used to change how each image will be
      49             :   /// blended onto the composition. Defaults to [BlendMode.srcOver].
      50             :   final BlendMode defaultBlendMode;
      51             : 
      52             :   /// The [defaultAntiAlias] can be used to if each image will be anti aliased.
      53             :   final bool defaultAntiAlias;
      54             : 
      55           1 :   ImageComposition({
      56             :     this.defaultBlendMode = BlendMode.srcOver,
      57             :     this.defaultAntiAlias = false,
      58             :   });
      59             : 
      60             :   /// Add an image to the [ImageComposition].
      61             :   ///
      62             :   /// The [image] will be added at the given [position] on the composition.
      63             :   ///
      64             :   /// An optional [source] can be used to only add the data that is within the
      65             :   /// [source] of the [image].
      66             :   ///
      67             :   /// An optional [angle] (in radians) can be used to rotate the image when it
      68             :   /// gets added to the composition. It will be rotated in a clock-wise direction
      69             :   /// around the [anchor].
      70             :   ///
      71             :   /// By default the [anchor] will be the [source].width and [source].height
      72             :   /// divided by `2`.
      73             :   ///
      74             :   /// [isAntiAlias] can be used to if the [image] will be anti aliased. Defaults
      75             :   /// to [defaultAntiAlias].
      76             :   ///
      77             :   /// The [blendMode] can be used to change how the [image] will be blended onto
      78             :   /// the composition. Defaults to [defaultBlendMode].
      79           1 :   void add(
      80             :     Image image,
      81             :     Vector2 position, {
      82             :     Rect? source,
      83             :     double angle = 0,
      84             :     Vector2? anchor,
      85             :     bool? isAntiAlias,
      86             :     BlendMode? blendMode,
      87             :   }) {
      88           1 :     final imageRect = image.getBoundingRect();
      89             :     source ??= imageRect;
      90           2 :     anchor ??= source.toVector2() / 2;
      91           1 :     blendMode ??= defaultBlendMode;
      92           1 :     isAntiAlias ??= defaultAntiAlias;
      93             : 
      94             :     assert(
      95           4 :       imageRect.topLeft <= source.topLeft &&
      96           3 :           imageRect.bottomRight >= source.bottomRight,
      97             :       'Source rect should fit within in the image constraints',
      98             :     );
      99             : 
     100           0 :     _composes.add(_Composed(
     101             :       image,
     102             :       position,
     103             :       source,
     104             :       angle,
     105             :       anchor,
     106             :       isAntiAlias,
     107             :       blendMode,
     108             :     ));
     109             :   }
     110             : 
     111           0 :   void clear() => _composes.clear();
     112             : 
     113             :   /// Compose all the images into a single composition.
     114           0 :   Future<Image> compose() async {
     115             :     // Rect used to determine how big the output image will be.
     116             :     var output = const Rect.fromLTWH(0, 0, 0, 0);
     117           0 :     final recorder = PictureRecorder();
     118           0 :     final canvas = Canvas(recorder);
     119             : 
     120           0 :     for (final compose in _composes) {
     121           0 :       final image = compose.image;
     122           0 :       final position = compose.position;
     123           0 :       final source = compose.source;
     124           0 :       final rotation = compose.angle;
     125           0 :       final anchor = compose.anchor;
     126           0 :       final isAntiAlias = compose.isAntiAlias;
     127           0 :       final blendMode = compose.blendMode;
     128           0 :       final destination = Rect.fromLTWH(0, 0, source.width, source.height);
     129           0 :       final realDest = destination.translate(position.x, position.y);
     130             : 
     131             :       canvas
     132           0 :         ..save()
     133           0 :         ..translateVector(position)
     134           0 :         ..translateVector(anchor)
     135           0 :         ..rotate(rotation)
     136           0 :         ..translateVector(-anchor)
     137           0 :         ..drawImageRect(
     138             :           image,
     139             :           source,
     140             :           destination,
     141           0 :           Paint()
     142           0 :             ..blendMode = blendMode
     143           0 :             ..isAntiAlias = isAntiAlias,
     144             :         )
     145           0 :         ..restore();
     146             : 
     147             :       // Expand the output so it can be used later on when the output image gets
     148             :       // created.
     149           0 :       output = output.expandToInclude(realDest);
     150             :     }
     151             : 
     152             :     return recorder
     153           0 :         .endRecording()
     154           0 :         .toImage(output.width.toInt(), output.height.toInt());
     155             :   }
     156             : }

Generated by: LCOV version 1.15