Flutter图片比较插件image_comparator的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter图片比较插件image_comparator的使用

Image Comparator

Image Comparator 是一个强大的 Flutter 包装器,用于轻松创建交互式的图像比较视图。这个包允许您通过提供可拖动的控制点来比较两张图片,该控制点可以自定义以适应您的应用程序设计。您可以将其用于各种用例,例如展示前后对比图片、突出显示差异或演示更改的影响。

使用方法

ImageComparator(
  width: 300,
  height: 300,
  image1: Image.asset("assets/images/before.jpg", fit: BoxFit.cover),
  image2: Image.asset("assets/images/after.jpg", fit: BoxFit.cover),
  controlLineWidth: 2,
  controlLineColor: Colors.white,
  controlThumb: const Icon(Icons.circle, color: Colors.white),
  controlHorizontalOffset: 0.8,
  controlVerticalOffset: 0.5,
)

参数说明

参数 类型 描述
image1 Widget 要比较的第一张图片。
image2 Widget 要比较的第二张图片。
controlThumb Widget 控制点的样式。使用控件自定义控制点的外观。
controlLineWidth double 控制线的宽度。
controlLineColor Color 控制线的颜色。
controlHorizontalOffset double 控制点的初始位置。它应该在 0.01.0 之间。
controlVerticalOffset double 控制点的位置偏移量。它应该在 0.01.0 之间。

注意: 如果您没有提供 widthheight,请将此控件包裹在 Expanded 中。记住,widthheight 参数只允许特定尺寸。

示例代码

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_comparator/image_comparator.dart';
import 'package:image_compare_slider/image_compare_slider.dart';
import 'package:collection/collection.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.white),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double thumbPositionOffset = 0.5;
  ThumbStyle thumbStyle = ThumbStyle.icon;
  List<Color> controlLineColor = [
    Colors.white,
    Colors.amber,
    Colors.teal,
    Colors.redAccent
  ];
  int selectedColorIndex = 0;

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Container(
            padding: const EdgeInsets.only(top: 48, bottom: 18),
            child: const Text(
              "Image Comparator View",
              style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.bold,
                  fontSize: 20),
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(18),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(12),
                child: ImageComparator(
                  image1: Image.asset(
                    "assets/images/before.jpg",
                    fit: BoxFit.cover,
                  ),
                  image2: Image.asset(
                    "assets/images/after.jpg",
                    fit: BoxFit.cover,
                  ),
                  controlLineWidth: 22,
                  controlLineColor: controlLineColor[selectedColorIndex],
                  controlVerticalOffset: thumbPositionOffset,
                  controlThumb: getThumbStyle(thumbStyle,
                      controlColor: controlLineColor[selectedColorIndex]),
                  controlHorizontalOffset: 0.5,
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 12.0),
            child: Column(
              children: [
                Row(
                  children: [
                    const Text("Control Color"),
                    const SizedBox(
                      width: 12,
                    ),
                    Row(
                      children: controlLineColor
                          .mapIndexed((index, item) =&gt; GestureDetector(
                            onTap: () =&gt; setState(() {
                              selectedColorIndex = index;
                            }),
                            child: Container(
                                decoration: BoxDecoration(
                                    color: item,
                                    border: Border.all(
                                        color: selectedColorIndex == index
                                            ? Colors.black
                                            : Colors.transparent,
                                        width: 2)),
                                    width: 42,
                                    height: 22),
                              ))
                            )
                          .toList(),
                    ),
                  ],
                ),
                Row(
                  children: [
                    const Text("Thumb Position"),
                    Expanded(
                      child: Slider(
                        value: thumbPositionOffset,
                        onChanged: (value) {
                          setState(() =&gt; thumbPositionOffset = value);
                        },
                      ),
                    ),
                  ],
                ),
                SizedBox(
                  height: 8,
                ),
                Container(
                  height: 1,
                  color: Colors.grey,
                ),
                SizedBox(
                  height: 8,
                ),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("Custom Thumb Icon"),
                    const SizedBox(
                      width: 28,
                    ),
                    Row(
                      children: ThumbStyle.values
                          .map((item) =&gt; GestureDetector(
                            onTap: () {
                              setState(() {
                                thumbStyle = item;
                              });
                            },
                            child: Container(
                              color: item == thumbStyle
                                  ? Colors.yellow
                                  : Colors.white,
                              padding: EdgeInsets.symmetric(
                                  horizontal: 12, vertical: 8),
                              child: Text(item.name),
                            ),
                          ))
                          .toList(),
                    )
                  ],
                )
              ],
            ),
          ),
          const SizedBox(
            height: 24,
          ),
        ],
      ),
    );
  }

  Widget getThumbStyle(ThumbStyle thumbStyle,
      {Color controlColor = Colors.white}) {
    switch (thumbStyle) {
      case ThumbStyle.icon:
        return Icon(
          Icons.circle,
          color: controlColor,
        );
      case ThumbStyle.svg:
        return SvgPicture.asset("assets/images/gesture.svg");
      case ThumbStyle.widget:
        return Container(
          width: 20,
          height: 20,
          decoration: BoxDecoration(
              border: Border.all(color: controlColor, width: 2),
              borderRadius: BorderRadius.circular(4)),
        );
      case ThumbStyle.image:
        return Image.asset(
          "assets/images/thumb.png",
          width: 28,
          height: 28,
        );
      case ThumbStyle.text:
        return Text(
          "&lt; Slide it &gt;",
          style: TextStyle(color: controlColor, fontWeight: FontWeight.bold),
        );
    }
  }
}

enum ThumbStyle {
  icon,
  svg,
  widget,
  image,
  text,
}

更多关于Flutter图片比较插件image_comparator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图片比较插件image_comparator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用image_comparator插件进行图片比较的示例代码。

首先,确保你已经在pubspec.yaml文件中添加了image_comparator依赖:

dependencies:
  flutter:
    sdk: flutter
  image_comparator: ^latest_version  # 替换为实际最新版本号

然后,运行flutter pub get来获取依赖。

接下来,我们编写一个Flutter应用来演示如何使用image_comparator插件。

示例代码

import 'package:flutter/material.dart';
import 'package:image_comparator/image_comparator.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Image Comparator Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ImageComparatorScreen(),
    );
  }
}

class ImageComparatorScreen extends StatefulWidget {
  @override
  _ImageComparatorScreenState createState() => _ImageComparatorScreenState();
}

class _ImageComparatorScreenState extends State<ImageComparatorScreen> {
  Uint8List? image1Bytes;
  Uint8List? image2Bytes;
  double? similarityScore;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Image Comparator Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Upload Image 1:'),
            SizedBox(height: 16),
            _buildImagePickerButton('image1.png', (bytes) {
              setState(() {
                image1Bytes = bytes;
              });
            }),
            SizedBox(height: 32),
            Text('Upload Image 2:'),
            SizedBox(height: 16),
            _buildImagePickerButton('image2.png', (bytes) {
              setState(() {
                image2Bytes = bytes;
              });
              _compareImages();
            }),
            SizedBox(height: 32),
            if (similarityScore != null)
              Text('Similarity Score: ${similarityScore!.toStringAsFixed(2)}'),
          ],
        ),
      ),
    );
  }

  Widget _buildImagePickerButton(String defaultFileName, VoidCallback onImagePicked) {
    return ElevatedButton(
      onPressed: () async {
        final Uint8List? pickedImageBytes = await _pickImageFromGallery();
        if (pickedImageBytes != null) {
          // Save the image bytes to a file (for demonstration purposes)
          // In a real app, you might want to handle these bytes differently
          final file = File('/tmp/${defaultFileName}');
          await file.writeAsBytes(pickedImageBytes);
          onImagePicked();
        }
      },
      child: Text('Pick Image'),
    );
  }

  Future<Uint8List?> _pickImageFromGallery() async {
    final pickedFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      final imageFile = File(pickedFile.path);
      return await imageFile.readAsBytes();
    }
    return null;
  }

  void _compareImages() async {
    if (image1Bytes != null && image2Bytes != null) {
      final image1 = ui.decodeImageFromList(image1Bytes!);
      final image2 = ui.decodeImageFromList(image2Bytes!);

      if (image1 != null && image2 != null) {
        final comparator = ImageComparator();
        final result = await comparator.compareImages(image1, image2);
        setState(() {
          similarityScore = result.similarityScore;
        });
      }
    }
  }
}

// Note: You need to import the image_picker package to pick images from the gallery
// Add this to your pubspec.yaml dependencies:
// dependencies:
//   image_picker: ^latest_version  # Replace with actual version
import 'package:image_picker/image_picker.dart';
final picker = ImagePicker();

注意事项

  1. 依赖管理:确保你已经添加了image_comparatorimage_picker的依赖,并运行了flutter pub get
  2. 图片选择器:上面的代码使用了image_picker插件来选择图片。你需要确保在pubspec.yaml中添加了image_picker的依赖。
  3. 文件存储:示例代码中为了演示,将图片字节存储到了/tmp/目录下,这在实际应用中可能不适用。
  4. 异步操作:图片选择和比较都是异步操作,确保使用awaitasync来正确管理这些操作。

通过以上代码,你可以在Flutter应用中实现图片比较功能,并获取两个图片之间的相似度分数。

回到顶部