paintExtendedImage function

void paintExtendedImage (
  1. {@required Canvas canvas,
  2. @required Rect rect,
  3. @required Image image,
  4. double scale: 1.0,
  5. ColorFilter colorFilter,
  6. BoxFit fit,
  7. Alignment alignment: Alignment.center,
  8. Rect centerSlice,
  9. ImageRepeat repeat: ImageRepeat.noRepeat,
  10. bool flipHorizontally: false,
  11. bool invertColors: false,
  12. FilterQuality filterQuality: FilterQuality.low,
  13. Rect customSourceRect,
  14. BeforePaintImage beforePaintImage,
  15. AfterPaintImage afterPaintImage,
  16. GestureDetails gestureDetails,
  17. EditActionDetails editActionDetails,
  18. bool isAntiAlias: false}
)

Implementation

void paintExtendedImage({
  @required Canvas canvas,
  @required Rect rect,
  @required ui.Image image,
  double scale = 1.0,
  ColorFilter colorFilter,
  BoxFit fit,
  Alignment alignment = Alignment.center,
  Rect centerSlice,
  ImageRepeat repeat = ImageRepeat.noRepeat,
  bool flipHorizontally = false,
  bool invertColors = false,
  FilterQuality filterQuality = FilterQuality.low,
  Rect customSourceRect,
  //you can paint anything if you want before paint image.
  BeforePaintImage beforePaintImage,
  //you can paint anything if you want after paint image.
  AfterPaintImage afterPaintImage,
  GestureDetails gestureDetails,
  EditActionDetails editActionDetails,
  bool isAntiAlias = false,
}) {
  assert(canvas != null);
  assert(image != null);
  assert(alignment != null);
  assert(repeat != null);
  assert(flipHorizontally != null);
  assert(isAntiAlias != null);
  if (rect.isEmpty) {
    return;
  }

  Size outputSize = rect.size;
  Size inputSize = Size(image.width.toDouble(), image.height.toDouble());

  final Offset topLeft = rect.topLeft;

  // if (editActionDetails != null && editActionDetails.isHalfPi) {
  //   outputSize = Size(outputSize.height, outputSize.width);
  //   var center = rect.center;
  //   topLeft = Rect.fromLTWH(center.dx - rect.height / 2.0,
  //           center.dy - rect.width / 2.0, rect.height, rect.width)
  //       .topLeft;
  // }

  Offset sliceBorder;
  if (centerSlice != null) {
    sliceBorder = Offset(centerSlice.left + inputSize.width - centerSlice.right,
        centerSlice.top + inputSize.height - centerSlice.bottom);
    outputSize = outputSize - sliceBorder as Size;
    inputSize = inputSize - sliceBorder as Size;
  }
  fit ??= centerSlice == null ? BoxFit.scaleDown : BoxFit.fill;
  assert(centerSlice == null || (fit != BoxFit.none && fit != BoxFit.cover));
  final FittedSizes fittedSizes =
      applyBoxFit(fit, inputSize / scale, outputSize);
  final Size sourceSize = fittedSizes.source * scale;
  Size destinationSize = fittedSizes.destination;
  if (centerSlice != null) {
    outputSize += sliceBorder;
    destinationSize += sliceBorder;
    // We don't have the ability to draw a subset of the image at the same time
    // as we apply a nine-patch stretch.
    assert(sourceSize == inputSize,
        'centerSlice was used with a BoxFit that does not guarantee that the image is fully visible.');
  }
  if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {
    // There's no need to repeat the image because we're exactly filling the
    // output rect with the image.
    repeat = ImageRepeat.noRepeat;
  }
  final Paint paint = Paint()..isAntiAlias = isAntiAlias;
  if (colorFilter != null) {
    paint.colorFilter = colorFilter;
  }
  if (sourceSize != destinationSize) {
    paint.filterQuality = filterQuality;
  }
  paint.invertColors = invertColors;
  final double halfWidthDelta =
      (outputSize.width - destinationSize.width) / 2.0;
  final double halfHeightDelta =
      (outputSize.height - destinationSize.height) / 2.0;
  final double dx = halfWidthDelta +
      (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta;
  final double dy = halfHeightDelta + alignment.y * halfHeightDelta;
  final Offset destinationPosition = topLeft.translate(dx, dy);
  Rect destinationRect = destinationPosition & destinationSize;

  bool needClip = false;

  if (gestureDetails != null) {
    destinationRect =
        gestureDetails.calculateFinalDestinationRect(rect, destinationRect);

    ///outside and need clip
    needClip = outRect(rect, destinationRect);

    if (gestureDetails.slidePageOffset != null) {
      destinationRect = destinationRect.shift(gestureDetails.slidePageOffset);
      rect = rect.shift(gestureDetails.slidePageOffset);
    }

    if (needClip) {
      canvas.save();
      canvas.clipRect(rect);
    }
  }
  bool hasEditAction = false;
  if (editActionDetails != null) {
    if (editActionDetails.cropRectPadding != null) {
      destinationRect = getDestinationRect(
          inputSize: inputSize,
          rect: editActionDetails.cropRectPadding.deflateRect(rect),
          fit: fit,
          flipHorizontally: false,
          scale: scale,
          centerSlice: centerSlice,
          alignment: alignment);
    }

    editActionDetails.initRect(rect, destinationRect);

    destinationRect = editActionDetails.getFinalDestinationRect();

    ///outside and need clip
    needClip = outRect(rect, destinationRect);

    hasEditAction = editActionDetails.hasEditAction;

    if (needClip || hasEditAction) {
      canvas.save();
      if (needClip) {
        canvas.clipRect(rect);
      }
    }

    if (hasEditAction) {
      final Offset origin =
          editActionDetails.screenCropRect?.center ?? destinationRect.center;

      final Matrix4 result = Matrix4.identity();

      final EditActionDetails editAction = editActionDetails;

      result.translate(
        origin.dx,
        origin.dy,
      );

      if (editAction.hasRotateAngle) {
        result.multiply(Matrix4.rotationZ(editAction.rotateRadian));
      }

      if (editAction.flipY) {
        result.multiply(Matrix4.rotationY(pi));
      }

      if (editAction.flipX) {
        result.multiply(Matrix4.rotationX(pi));
      }

      result.translate(-origin.dx, -origin.dy);
      canvas.transform(result.storage);
      destinationRect = editAction.paintRect(destinationRect);
    }
  }

  if (beforePaintImage != null) {
    final bool handle = beforePaintImage(canvas, destinationRect, image, paint);
    if (handle) {
      return;
    }
  }

  final bool needSave = repeat != ImageRepeat.noRepeat || flipHorizontally;
  if (needSave) {
    canvas.save();
  }
  if (repeat != ImageRepeat.noRepeat) {
    canvas.clipRect(rect);
  }
  if (flipHorizontally) {
    final double dx = -(rect.left + rect.width / 2.0);
    canvas.translate(-dx, 0.0);
    canvas.scale(-1.0, 1.0);
    canvas.translate(dx, 0.0);
  }

  if (centerSlice == null) {
    final Rect sourceRect = customSourceRect ??
        alignment.inscribe(sourceSize, Offset.zero & inputSize);
    for (final Rect tileRect
        in _generateImageTileRects(rect, destinationRect, repeat)) {
      canvas.drawImageRect(image, sourceRect, tileRect, paint);
    }
  } else {
    for (final Rect tileRect
        in _generateImageTileRects(rect, destinationRect, repeat)) {
      canvas.drawImageNine(image, centerSlice, tileRect, paint);
    }
  }

  if (needSave) {
    canvas.restore();
  }

  if (needClip || hasEditAction) {
    canvas.restore();
  }

  if (afterPaintImage != null) {
    afterPaintImage(canvas, destinationRect, image, paint);
  }
}