Flutter图片元数据获取插件native_exif的使用

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

Flutter图片元数据获取插件native_exif的使用

native_exif 是一个简单的EXIF元数据读取/写入插件,适用于Flutter应用。它利用了iOS和Android平台的原生功能来处理图像的EXIF数据。

使用方法

创建EXIF读取实例

首先需要通过指定图像路径来创建一个EXIF读取实例:

final exif = await Exif.fromPath(pickedFile!.path);

读取属性

可以通过预定义函数或获取所有属性来读取图像的EXIF信息:

final originalDate = await exif.getOriginalDate();
final latLong = await exif.getLatLong();
final attribute = await exif.getAttribute("key");
final attributes = await exif.getAttributes();

写入属性

可以将特定键的EXIF数据以字符串形式写入:

await exif.writeAttribute("key", "value");
await exif.writeAttributes({"key1": "value1", "key2": "value2"});

关闭EXIF接口

操作完成后应关闭EXIF接口:

await exif.close();

平台注意事项

该插件仅支持iOS和Android平台。

Android

  • 使用androidx ExifInterface
  • 支持的EXIF和GPS属性有限,请参考相关代码文档。
  • 目前只能正确写入ASCII字符。
  • GPSLatitudeGPSLongitude 可以写入负值,但返回时为正值,需结合GPSLatitudeRefGPSLongitudeRefgetLatLong() 来确定坐标。

iOS

  • 支持的EXIF和GPS属性请参阅Apple官方文档。
  • GPS字典键需要加上GPS前缀。
  • 同样需要注意GPSLatitudeGPSLongitude 的正负值问题。

示例代码

以下是一个完整的示例应用程序,展示如何使用native_exif插件:

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

import 'package:native_exif/native_exif.dart';

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final picker = ImagePicker();

  XFile? pickedFile;
  Exif? exif;
  Map<String, Object>? attributes;
  DateTime? shootingDate;
  ExifLatLong? coordinates;

  Future<void> showError(Object e) async {
    debugPrintStack(label: e.toString(), stackTrace: e is Error ? e.stackTrace : null);

    return showDialog<void>(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Error'),
          content: SingleChildScrollView(
            child: ListBody(
              children: [Text(e.toString())],
            ),
          ),
          actions: <Widget>[
            TextButton(
              child: const Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  Future getImage() async {
    pickedFile = await picker.pickImage(source: ImageSource.gallery);
    if (pickedFile == null) {
      return;
    }

    exif = await Exif.fromPath(pickedFile!.path);
    attributes = await exif!.getAttributes();
    shootingDate = await exif!.getOriginalDate();
    coordinates = await exif!.getLatLong();

    setState(() {});
  }

  Future closeImage() async {
    await exif?.close();
    shootingDate = null;
    attributes = {};
    exif = null;
    coordinates = null;

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Plugin example app')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (pickedFile == null)
              const Text("Please open an image.")
            else
              Column(
                children: [
                  Text("The selected image has ${attributes?.length ?? 0} attributes."),
                  Text("It was taken at ${shootingDate.toString()}"),
                  Text(attributes?["UserComment"]?.toString() ?? ''),
                  Text("Attributes: $attributes"),
                  Text("Coordinates: $coordinates"),
                  TextButton(
                    onPressed: () async {
                      try {
                        final dateFormat = DateFormat('yyyy:MM:dd HH:mm:ss');
                        await exif!.writeAttribute('DateTimeOriginal', dateFormat.format(DateTime.now()));

                        shootingDate = await exif!.getOriginalDate();
                        attributes = await exif!.getAttributes();

                        setState(() {});
                      } catch (e) {
                        showError(e);
                      }
                    },
                    child: const Text('Update date attribute'),
                  ),
                  // 其他按钮...
                  ElevatedButton(
                    onPressed: closeImage,
                    style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.red)),
                    child: const Text('Close image'),
                  )
                ],
              ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: getImage,
              child: const Text('Open image'),
            ),
            if (pickedFile != null)
              ElevatedButton(
                onPressed: () async {
                  try {
                    final file = File(p.join(Directory.systemTemp.path, 'tempimage.jpg'));
                    final imageBytes = await pickedFile!.readAsBytes();
                    await file.create();
                    await file.writeAsBytes(imageBytes);
                    final _attributes = await exif?.getAttributes() ?? {};
                    final newExif = await Exif.fromPath(file.path);

                    _attributes['DateTimeOriginal'] = '2021:05:15 13:00:00';
                    _attributes['UserComment'] = "This file is user generated!";

                    await newExif.writeAttributes(_attributes);

                    shootingDate = await newExif.getOriginalDate();
                    attributes = await newExif.getAttributes();
                    coordinates = await newExif.getLatLong();

                    setState(() {});
                  } catch (e) {
                    showError(e);
                  }
                },
                child: const Text("Create file and write exif data"),
              ),
          ],
        ),
      ),
    );
  }
}

此示例展示了如何从相册中选择一张图片,读取并修改其EXIF数据,并在界面上显示相关信息。希望这些信息能帮助您更好地理解和使用native_exif插件。


更多关于Flutter图片元数据获取插件native_exif的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图片元数据获取插件native_exif的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用native_exif插件来获取图片元数据的示例代码。这个插件允许你从图像文件中读取EXIF(Exchangeable Image File Format)数据。

首先,确保你的Flutter项目已经配置好了native_exif插件。你可以通过以下步骤来添加这个插件:

  1. 在你的pubspec.yaml文件中添加依赖:
dependencies:
  flutter:
    sdk: flutter
  native_exif: ^2.0.0  # 请检查最新版本号
  1. 运行flutter pub get来安装依赖。

接下来,下面是一个简单的示例代码,展示了如何使用native_exif插件来获取图片元数据:

import 'package:flutter/material.dart';
import 'package:native_exif/native_exif.dart';
import 'dart:io';

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File? _imageFile;
  Map<String, dynamic>? _exifData;

  Future<void> _pickImage() async {
    final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      setState(() {
        _imageFile = File(pickedFile.path);
      });

      // 获取EXIF数据
      _exifData = await NativeExif.readExifFromBytes(await _imageFile!.readAsBytes());
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter EXIF Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: _pickImage,
              child: Text('Pick Image'),
            ),
            if (_imageFile != null)
              Image.file(_imageFile!),
            if (_exifData != null)
              Expanded(
                child: SingleChildScrollView(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: _exifData!.entries.map((entry) {
                        return Text(
                          '${entry.key}: ${entry.value}',
                          style: TextStyle(fontSize: 16),
                        );
                      }).toList(),
                    ),
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们使用了image_picker插件来选择图片,然后通过native_exif插件读取图片的EXIF数据。请确保你也添加了image_picker插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  native_exif: ^2.0.0  # 请检查最新版本号
  image_picker: ^0.8.4+4  # 请检查最新版本号

并且运行flutter pub get来安装它。

这个示例代码展示了如何从图片中选择文件,读取其EXIF数据,并在UI中显示这些数据。注意,EXIF数据可能包含很多字段,这里只是简单地遍历并显示所有字段及其值。你可以根据需要处理特定的EXIF字段。

回到顶部