copyResize function

Image copyResize(
  1. Image src, {
  2. int? width,
  3. int? height,
  4. bool? maintainAspect,
  5. Color? backgroundColor,
  6. Interpolation interpolation = Interpolation.nearest,
})

Returns a resized copy of the src Image. If height isn't specified, then it will be determined by the aspect ratio of src and width. If width isn't specified, then it will be determined by the aspect ratio of src and height.

Implementation

Image copyResize(Image src,
    {int? width,
    int? height,
    bool? maintainAspect,
    Color? backgroundColor,
    Interpolation interpolation = Interpolation.nearest}) {
  if (width == null && height == null) {
    throw ImageException('Invalid size');
  }

  // You can't interpolate index pixels
  if (src.hasPalette) {
    interpolation = Interpolation.nearest;
  }

  if (src.exif.imageIfd.hasOrientation && src.exif.imageIfd.orientation != 1) {
    src = bakeOrientation(src);
  }

  var x1 = 0;
  var y1 = 0;
  var x2 = 0;
  var y2 = 0;

  // this block sets [width] and [height] if null or negative.
  if (width != null && height != null && maintainAspect == true) {
    x1 = 0;
    x2 = width;
    final srcAspect = src.height / src.width;
    final h = (width * srcAspect).toInt();
    final dy = (height - h) ~/ 2;
    y1 = dy;
    y2 = y1 + h;
    if (y1 < 0 || y2 > height) {
      y1 = 0;
      y2 = height;
      final srcAspect = src.width / src.height;
      final w = (height * srcAspect).toInt();
      final dx = (width - w) ~/ 2;
      x1 = dx;
      x2 = x1 + w;
    }
  } else {
    maintainAspect = false;
  }

  if (height == null || height <= 0) {
    height = (width! * (src.height / src.width)).round();
  }
  if (width == null || width <= 0) {
    width = (height * (src.width / src.height)).round();
  }

  final w = maintainAspect! ? x2 - x1 : width;
  final h = maintainAspect ? y2 - y1 : height;

  if (!maintainAspect) {
    x1 = 0;
    x2 = width;
    y1 = 0;
    y2 = height;
  }

  if (width == src.width && height == src.height) {
    return src.clone();
  }

  final scaleX = Int32List(w);
  final dx = src.width / w;
  for (var x = 0; x < w; ++x) {
    scaleX[x] = (x * dx).toInt();
  }
  final scaleY = Int32List(h);
  final dy = src.height / h;
  for (var y = 0; y < h; ++y) {
    scaleY[y] = (y * dy).toInt();
  }

  Image? firstFrame;
  final numFrames = src.numFrames;
  for (var i = 0; i < numFrames; ++i) {
    final frame = src.frames[i];
    final dst = Image.fromResized(frame,
        width: width, height: height, noAnimation: true);
    firstFrame?.addFrame(dst);
    firstFrame ??= dst;

    final dy = frame.height / h;
    final dx = frame.width / w;

    if (maintainAspect && backgroundColor != null) {
      dst.clear(backgroundColor);
    }

    if (interpolation == Interpolation.average) {
      final srcPixel = frame.getPixelSafe(0, 0);
      for (var y = 0; y < h; ++y) {
        final ay1 = (y * dy).toInt();
        var ay2 = ((y + 1) * dy).toInt();
        if (ay2 == ay1) {
          ay2++;
        }

        for (var x = 0; x < w; ++x) {
          final ax1 = (x * dx).toInt();
          var ax2 = ((x + 1) * dx).toInt();
          if (ax2 == ax1) {
            ax2++;
          }

          num r = 0;
          num g = 0;
          num b = 0;
          num a = 0;
          var np = 0;
          for (var sy = ay1; sy < ay2; ++sy) {
            for (var sx = ax1; sx < ax2; ++sx, ++np) {
              frame.getPixel(sx, sy, srcPixel);
              r += srcPixel.r;
              g += srcPixel.g;
              b += srcPixel.b;
              a += srcPixel.a;
            }
          }
          dst.setPixelRgba(x1 + x, y1 + y, r / np, g / np, b / np, a / np);
        }
      }
    } else if (interpolation == Interpolation.nearest) {
      if (frame.hasPalette) {
        for (var y = 0; y < h; ++y) {
          final y2 = (y * dy).toInt();
          for (var x = 0; x < w; ++x) {
            dst.setPixelIndex(
                x1 + x, y1 + y, frame.getPixelIndex(scaleX[x], y2));
          }
        }
      } else {
        final srcPixel = frame.getPixelSafe(0, 0);
        for (var y = 0; y < h; ++y) {
          for (var x = 0; x < w; ++x) {
            frame.getPixel(scaleX[x], scaleY[y], srcPixel);
            dst.setPixelRgba(
                x1 + x, y1 + y, srcPixel.r, srcPixel.g, srcPixel.b, srcPixel.a);
            // Not calling setPixel which triggers runtime type checking
            // mainly for hasPalette routine. Palette images are treated in
            // the above if-else block.
            //dst.setPixel(x1 + x, y1 + y, frame.getPixel(scaleX[x], y2));
          }
        }
      }
    } else if (interpolation == Interpolation.linear) {
      // 4 predefined pixel object for 4 vertices
      final icc = frame.getPixelSafe(0, 0);
      final icn = frame.getPixelSafe(0, 0);
      final inc = frame.getPixelSafe(0, 0);
      final inn = frame.getPixelSafe(0, 0);

      num linear(num icc, num inc, num icn, num inn, num kx, num ky) =>
          icc +
          kx * (inc - icc + ky * (icc + inn - icn - inc)) +
          ky * (icn - icc);

      // Copy the pixels from this image to the new image.
      for (var y = 0; y < h; ++y) {
        final sy2 = y * dy;
        for (var x = 0; x < w; ++x) {
          final sx2 = x * dx;
          final fx = sx2.clamp(0, frame.width - 1);
          final fy = sy2.clamp(0, frame.height - 1);
          final ix = fx.toInt();
          final iy = fy.toInt();
          final kx = fx - ix;
          final ky = fy - iy;
          final nx = (ix + 1).clamp(0, frame.width - 1);
          final ny = (iy + 1).clamp(0, frame.height - 1);

          frame
            ..getPixel(ix, iy, icc)
            ..getPixel(ix, ny, icn)
            ..getPixel(nx, iy, inc)
            ..getPixel(nx, ny, inn);

          dst.setPixelRgba(
              x1 + x,
              y1 + y,
              linear(icc.r, inc.r, icn.r, inn.r, kx, ky),
              linear(icc.g, inc.g, icn.g, inn.g, kx, ky),
              linear(icc.b, inc.b, icn.b, inn.b, kx, ky),
              linear(icc.a, inc.a, icn.a, inn.a, kx, ky));
        }
      }
    } else {
      // Copy the pixels from this image to the new image.
      for (var y = 0; y < h; ++y) {
        final sy2 = y * dy;
        for (var x = 0; x < w; ++x) {
          final sx2 = x * dx;
          dst.setPixel(
              x1 + x,
              y1 + y,
              frame.getPixelInterpolate(sx2, sy2,
                  interpolation: interpolation));
        }
      }
    }
  }

  return firstFrame!;
}