最近遇到一个项目需求,这里记录下。将图片进行顺时针旋转90°和逆时针90°,保证图片都铺满矩形框区域

import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double rate = 4 / 6;
  String imageUrl =
      'https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/b2de9c82d158ccbfb40a4fd81bd8bc3eb035419a.jpg';
  double imageWidth = 0;
  double imageHeight = 0;
  double scale = 1;
  double angle = 0;
  Future? future;

  @override
  void initState() {
    future = download();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF5F9FA),
      appBar: AppBar(
        title: const Text('图片旋转'),
      ),
      body: FutureBuilder(
        future: future,
        builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
          if (snapshot.data == null) {
            return const SizedBox();
          }
          Uint8List bytes = snapshot.data;
          return Column(
            children: [
              ElevatedButton(
                  onPressed: () {
                    changeAngle(false);
                  },
                  child: const Text('逆时针')),
              ElevatedButton(
                  onPressed: () {
                    changeAngle(true);
                  },
                  child: const Text('顺时针')),
              AspectRatio(
                aspectRatio: rate,
                child: Container(
                  width: double.infinity,
                  height: double.infinity,
                  color: Colors.blue,
                  padding: const EdgeInsets.all(6),
                  child: LayoutBuilder(
                    builder: (c, b) {
                      if (angle % pi != 0) {
                        scale = getMinMaxScaleSingle(b.maxWidth, b.maxHeight);
                      } else {
                        scale = 1;
                      }
                      return Transform.scale(
                        scale: scale,
                        child: Transform.rotate(
                          angle: angle,
                          child: Image.memory(bytes),
                        ),
                      );
                    },
                  ),
                ),
              )
            ],
          );
        },
      ),
    );
  }

  changeAngle(bool clockwise) {
    if (clockwise) {
      angle += pi / 2;
      if (angle == pi * 2) angle = 0;
    } else {
      angle -= pi / 2;
      if (angle == -pi * 2) angle = 0;
    }
    if (mounted) setState(() {});
  }

  //获得单个图片区域的最小最大缩放比例
  double getMinMaxScaleSingle(double width, double height) {
    final fittedSizes = getFittedSizes(width, height);
    double imgWidth = fittedSizes.destination.width;
    double imgHeight = fittedSizes.destination.height;
    if (angle % pi != 0) {
      imgWidth = fittedSizes.destination.height;
      imgHeight = fittedSizes.destination.width;
    }
    double scaleX = width / imgWidth;
    double scaleY = height / imgHeight;
    double minScale = scaleX > scaleY ? scaleY : scaleX;
    return minScale;
  }

  FittedSizes getFittedSizes(double width, double height) {
    return applyBoxFit(
        BoxFit.contain, Size(imageWidth, imageHeight), Size(width, height));
  }

  Future download() async {
    var httpClient = HttpClient();
    try {
      var request = await httpClient.getUrl(Uri.parse(imageUrl));
      var response = await request.close();
      var imageByte = await consolidateHttpClientResponseBytes(response);
      var codec = await ui.instantiateImageCodec(imageByte);
      ui.FrameInfo fi = await codec.getNextFrame();
      imageWidth = fi.image.width * 1.0;
      imageHeight = fi.image.height * 1.0;
      return imageByte;
    } catch (error) {
      return null;
    }
  }
}
12-09 14:10