copyRotate function

Image copyRotate(
  1. Image src,
  2. {required num angle,
  3. Interpolation interpolation = Interpolation.nearest}
)

Returns a copy of the src image, rotated by angle degrees.

Implementation

Image copyRotate(Image src,
    {required num angle, Interpolation interpolation = Interpolation.nearest}) {
  final num nAngle = angle % 360.0;

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

  // Optimized version for orthogonal angles.
  if ((nAngle % 90.0) == 0.0) {
    final iAngle = nAngle ~/ 90.0;
    switch (iAngle) {
      case 1: // 90 deg.
        return _rotate90(src);
      /**/
      case 2: // 180 deg.
        return _rotate180(src);
      case 3: // 270 deg.
        return _rotate270(src);
      default: // 0 deg.
        return Image.from(src);
    }
  }

  // Generic angle.
  final rad = nAngle * pi / 180.0;
  final ca = cos(rad);
  final sa = sin(rad);
  final ux = (src.width * ca).abs();
  final uy = (src.width * sa).abs();
  final vx = (src.height * sa).abs();
  final vy = (src.height * ca).abs();
  final w2 = 0.5 * src.width;
  final h2 = 0.5 * src.height;
  final dw2 = 0.5 * (ux + vx);
  final dh2 = 0.5 * (uy + vy);

  Image? firstFrame;
  final numFrames = src.numFrames;
  for (var i = 0; i < numFrames; ++i) {
    final frame = src.frames[i];
    final dst = firstFrame?.addFrame() ??
        Image.fromResized(src,
            width: (ux + vx).toInt(),
            height: (uy + vy).toInt(),
            noAnimation: true);
    firstFrame ??= dst;
    final bg = frame.backgroundColor ?? src.backgroundColor;
    if (bg != null) {
      dst.clear(bg);
    }

    for (final p in dst) {
      final x = p.x;
      final y = p.y;
      final x2 = w2 + (x - dw2) * ca + (y - dh2) * sa;
      final y2 = h2 - (x - dw2) * sa + (y - dh2) * ca;
      if (frame.isBoundsSafe(x2, y2)) {
        final c =
            frame.getPixelInterpolate(x2, y2, interpolation: interpolation);
        dst.setPixel(x, y, c);
      }
    }
  }

  return firstFrame!;
}