FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize)

Apply a BoxFit value.

The arguments to this method, in addition to the BoxFit value to apply, are two sizes, ostensibly the sizes of an input box and an output box. Specifically, the inputSize argument gives the size of the complete source that is being fitted, and the outputSize gives the size of the rectangle into which the source is to be drawn.

This function then returns two sizes, combined into a single FittedSizes object.

The FittedSizes.source size is the subpart of the inputSize that is to be shown. If the entire input source is shown, then this will equal the inputSize, but if the input source is to be cropped down, this may be smaller.

The FittedSizes.destination size is the subpart of the outputSize in which to paint the (possibly cropped) source. If the FittedSizes.destination size is smaller than the outputSize then the source is being letterboxed (or pillarboxed).

This method does not express an opinion regarding the alignment of the source and destination sizes within the input and output rectangles. Typically they are centered (this is what BoxDecoration does, for instance, and is how BoxFit is defined). The Alignment class provides a convenience function, Alignment.inscribe, for resolving the sizes to rects, as shown in the example below.

Sample code

This function paints a dart:ui.Image image onto the Rect outputRect on a Canvas canvas, using a Paint paint, applying the BoxFit algorithm fit:

void paintImage(ui.Image image, Rect outputRect, Canvas canvas, Paint paint, BoxFit fit) {
  final Size imageSize = new Size(image.width.toDouble(), image.height.toDouble());
  final FittedSizes sizes = applyBoxFit(fit, imageSize, outputRect.size);
  final Rect inputSubrect = Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
  final Rect outputSubrect = Alignment.center.inscribe(sizes.destination, outputRect);
  canvas.drawImageRect(image, inputSubrect, outputSubrect, paint);
}

See also:

Source

FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) {
  if (inputSize.height <= 0.0 || inputSize.width <= 0.0 || outputSize.height <= 0.0 || outputSize.width <= 0.0)
    return const FittedSizes(Size.zero, Size.zero);

  Size sourceSize, destinationSize;
  switch (fit) {
    case BoxFit.fill:
      sourceSize = inputSize;
      destinationSize = outputSize;
      break;
    case BoxFit.contain:
      sourceSize = inputSize;
      if (outputSize.width / outputSize.height > sourceSize.width / sourceSize.height)
        destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, outputSize.height);
      else
        destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
      break;
    case BoxFit.cover:
      if (outputSize.width / outputSize.height > inputSize.width / inputSize.height) {
        sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width);
      } else {
        sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, inputSize.height);
      }
      destinationSize = outputSize;
      break;
    case BoxFit.fitWidth:
      sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width);
      destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
      break;
    case BoxFit.fitHeight:
      sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, inputSize.height);
      destinationSize = new Size(sourceSize.width * outputSize.height / sourceSize.height, outputSize.height);
      break;
    case BoxFit.none:
      sourceSize = new Size(math.min(inputSize.width, outputSize.width),
                            math.min(inputSize.height, outputSize.height));
      destinationSize = sourceSize;
      break;
    case BoxFit.scaleDown:
      sourceSize = inputSize;
      destinationSize = inputSize;
      final double aspectRatio = inputSize.width / inputSize.height;
      if (destinationSize.height > outputSize.height)
        destinationSize = new Size(outputSize.height * aspectRatio, outputSize.height);
      if (destinationSize.width > outputSize.width)
        destinationSize = new Size(outputSize.width, outputSize.width / aspectRatio);
      break;
  }
  return new FittedSizes(sourceSize, destinationSize);
}