mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Exiv2 ffi package
This commit is contained in:
parent
809d81db9d
commit
f1704cc37d
29 changed files with 934 additions and 0 deletions
7
np_exiv2/.gitignore
vendored
Normal file
7
np_exiv2/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
|
||||
# Avoid committing pubspec.lock for library packages; see
|
||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
pubspec.lock
|
1
np_exiv2/analysis_options.yaml
Normal file
1
np_exiv2/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
include: package:np_lints/np.yaml
|
7
np_exiv2/ffigen.yaml
Normal file
7
np_exiv2/ffigen.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
output: "lib/src/generated_bindings.g.dart"
|
||||
name: "NpExiv2C"
|
||||
headers:
|
||||
entry-points:
|
||||
- "headers/np_exiv2_c.h"
|
||||
preamble: |
|
||||
// ignore_for_file: unused_element, unused_field
|
91
np_exiv2/headers/np_exiv2_c.h
Normal file
91
np_exiv2/headers/np_exiv2_c.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
#pragma once
|
||||
#pragma GCC visibility push(default)
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
exiv2_type_id_unsigned_byte = 0,
|
||||
exiv2_type_id_ascii_string,
|
||||
exiv2_type_id_unsigned_short,
|
||||
exiv2_type_id_unsigned_long,
|
||||
exiv2_type_id_unsigned_rational,
|
||||
exiv2_type_id_signed_byte,
|
||||
exiv2_type_id_undefined,
|
||||
exiv2_type_id_signed_short,
|
||||
exiv2_type_id_signed_long,
|
||||
exiv2_type_id_signed_rational,
|
||||
exiv2_type_id_tiff_float,
|
||||
exiv2_type_id_tiff_double,
|
||||
exiv2_type_id_tiff_ifd,
|
||||
exiv2_type_id_unsigned_long_long,
|
||||
exiv2_type_id_signed_long_long,
|
||||
exiv2_type_id_tiff_ifd8,
|
||||
exiv2_type_id_string,
|
||||
// int32_t[3] (year, month, day)
|
||||
exiv2_type_id_date,
|
||||
// int32_t[5] (hour, minute, second, tz_hour, tz_minute)
|
||||
exiv2_type_id_time,
|
||||
exiv2_type_id_comment,
|
||||
exiv2_type_id_directory,
|
||||
exiv2_type_id_xmp_text,
|
||||
exiv2_type_id_xmp_alt,
|
||||
exiv2_type_id_xmp_bag,
|
||||
exiv2_type_id_xmp_seq,
|
||||
exiv2_type_id_lang_alt,
|
||||
exiv2_type_id_invalid_type_id,
|
||||
} Exiv2TypeId;
|
||||
|
||||
/**
|
||||
* A key value pair
|
||||
*/
|
||||
typedef struct {
|
||||
const char *tag_key;
|
||||
Exiv2TypeId type_id;
|
||||
const uint8_t *data;
|
||||
// size of data in bytes
|
||||
size_t size;
|
||||
// number of elements in data if it's an array, 1 otherwise
|
||||
size_t count;
|
||||
} Exiv2Metadatum;
|
||||
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
const Exiv2Metadatum *iptc_data;
|
||||
size_t iptc_count;
|
||||
const Exiv2Metadatum *exif_data;
|
||||
size_t exif_count;
|
||||
const Exiv2Metadatum *xmp_data;
|
||||
size_t xmp_count;
|
||||
} Exiv2ReadResult;
|
||||
|
||||
/**
|
||||
* Extract metadata from a file pointed to by @a path
|
||||
*
|
||||
* @return A handle to retrieve actual results, 0 if failed
|
||||
*/
|
||||
const Exiv2ReadResult *exiv2_read_file(const char *path);
|
||||
|
||||
/**
|
||||
* Extract metadata from a buffer
|
||||
*
|
||||
* @return A handle to retrieve actual results, 0 if failed
|
||||
*/
|
||||
const Exiv2ReadResult *exiv2_read_buffer(const uint8_t *buffer,
|
||||
const size_t size);
|
||||
|
||||
/**
|
||||
* Release the resources of a Exiv2ReadResult object returned by
|
||||
* @a exiv2_read_file
|
||||
*/
|
||||
void exiv2_result_free(const Exiv2ReadResult *that);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#pragma GCC visibility pop
|
3
np_exiv2/lib/np_exiv2.dart
Normal file
3
np_exiv2/lib/np_exiv2.dart
Normal file
|
@ -0,0 +1,3 @@
|
|||
library np_exiv2;
|
||||
|
||||
export 'src/api.dart';
|
296
np_exiv2/lib/src/api.dart
Normal file
296
np_exiv2/lib/src/api.dart
Normal file
|
@ -0,0 +1,296 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:euc/jis.dart';
|
||||
import 'package:ffi/ffi.dart' as ffi;
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_exiv2/src/generated_bindings.g.dart';
|
||||
import 'package:quiver/iterables.dart';
|
||||
|
||||
enum TypeId {
|
||||
unsignedByte,
|
||||
asciiString,
|
||||
unsignedShort,
|
||||
unsignedLong,
|
||||
unsignedRational,
|
||||
signedByte,
|
||||
undefined,
|
||||
signedShort,
|
||||
signedLong,
|
||||
signedRational,
|
||||
tiffFloat,
|
||||
tiffDouble,
|
||||
tiffIfd,
|
||||
unsignedLongLong,
|
||||
signedLongLong,
|
||||
tiffIfd8,
|
||||
string,
|
||||
date,
|
||||
time,
|
||||
comment,
|
||||
directory,
|
||||
xmpText,
|
||||
xmpAlt,
|
||||
xmpBag,
|
||||
xmpSeq,
|
||||
langAlt,
|
||||
invalidTypeId,
|
||||
;
|
||||
|
||||
factory TypeId.fromNative(Exiv2TypeId src) {
|
||||
return TypeId.values[src.index];
|
||||
}
|
||||
}
|
||||
|
||||
class Date {
|
||||
const Date(this.year, this.month, this.day);
|
||||
|
||||
final int year;
|
||||
final int month;
|
||||
final int day;
|
||||
}
|
||||
|
||||
class Time {
|
||||
const Time(this.hour, this.minute, this.second, this.tzHour, this.tzMinute);
|
||||
|
||||
final int hour;
|
||||
final int minute;
|
||||
final int second;
|
||||
final int tzHour;
|
||||
final int tzMinute;
|
||||
}
|
||||
|
||||
class Rational {
|
||||
const Rational(this.numerator, this.denominator);
|
||||
|
||||
double toDouble() => numerator / denominator;
|
||||
|
||||
@override
|
||||
String toString() => "$numerator/$denominator";
|
||||
|
||||
final int numerator;
|
||||
final int denominator;
|
||||
}
|
||||
|
||||
class Value {
|
||||
const Value({
|
||||
required this.typeId,
|
||||
required Uint8List data,
|
||||
required int count,
|
||||
}) : _data = data,
|
||||
_count = count;
|
||||
|
||||
T as<T>() => asTyped() as T;
|
||||
|
||||
Object asTyped() {
|
||||
try {
|
||||
switch (typeId) {
|
||||
case TypeId.unsignedByte:
|
||||
return _listOrValue(_data);
|
||||
case TypeId.asciiString:
|
||||
// this is supposed to be ascii but vendors are putting utf-8 strings
|
||||
return utf8.decode(_data);
|
||||
case TypeId.unsignedShort:
|
||||
return _listOrValue(_data.buffer.asUint16List());
|
||||
case TypeId.unsignedLong:
|
||||
case TypeId.tiffIfd:
|
||||
return _listOrValue(_data.buffer.asUint32List());
|
||||
case TypeId.unsignedRational:
|
||||
return _listOrValue(partition(_data.buffer.asUint32List(), 2)
|
||||
.map((e) => Rational(e[0], e[1]))
|
||||
.toList());
|
||||
case TypeId.signedByte:
|
||||
return _listOrValue(_data.buffer.asInt8List());
|
||||
case TypeId.signedShort:
|
||||
return _listOrValue(_data.buffer.asInt16List());
|
||||
case TypeId.signedLong:
|
||||
return _listOrValue(_data.buffer.asInt32List());
|
||||
case TypeId.signedRational:
|
||||
return _listOrValue(partition(_data.buffer.asInt32List(), 2)
|
||||
.map((e) => Rational(e[0], e[1]))
|
||||
.toList());
|
||||
case TypeId.tiffFloat:
|
||||
return _listOrValue(_data.buffer.asFloat32List());
|
||||
case TypeId.tiffDouble:
|
||||
return _listOrValue(_data.buffer.asFloat64List());
|
||||
case TypeId.unsignedLongLong:
|
||||
case TypeId.tiffIfd8:
|
||||
return _listOrValue(_data.buffer.asUint64List());
|
||||
case TypeId.signedLongLong:
|
||||
return _listOrValue(_data.buffer.asInt64List());
|
||||
case TypeId.string:
|
||||
return utf8.decode(_data);
|
||||
case TypeId.date:
|
||||
return _data.buffer.asInt32List().let((e) => Date(e[0], e[1], e[2]));
|
||||
case TypeId.time:
|
||||
return _data.buffer
|
||||
.asInt32List()
|
||||
.let((e) => Time(e[0], e[1], e[2], e[3], e[4]));
|
||||
case TypeId.comment:
|
||||
return _convertCommentValue();
|
||||
case TypeId.undefined:
|
||||
case TypeId.directory:
|
||||
case TypeId.invalidTypeId:
|
||||
return _data.buffer.asUint8List();
|
||||
case TypeId.xmpText:
|
||||
case TypeId.xmpAlt:
|
||||
case TypeId.xmpBag:
|
||||
case TypeId.xmpSeq:
|
||||
case TypeId.langAlt:
|
||||
throw UnsupportedError("XMP not supported");
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[asTyped] Failed to convert data to type: $typeId, $_data",
|
||||
e, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
String toDebugString() {
|
||||
return "Value{"
|
||||
"typeId: $typeId, "
|
||||
"size: ${_data.length}, "
|
||||
"count: $_count, "
|
||||
"}";
|
||||
}
|
||||
|
||||
Object _listOrValue(List<Object> values) {
|
||||
return _count == 1 ? values.first : values;
|
||||
}
|
||||
|
||||
String _convertCommentValue() {
|
||||
// the first 8 chars is the charset, valid values are [ASCII, JIS,
|
||||
// UNICODE]
|
||||
return _data.buffer.asUint8List().let((e) {
|
||||
String? charset;
|
||||
Uint8List data = e;
|
||||
if (e.length >= 8) {
|
||||
charset = ascii.decode(e.sublist(0, 8));
|
||||
data = e.sublist(8);
|
||||
}
|
||||
if (charset == "ASCII") {
|
||||
return ascii.decode(data, allowInvalid: true);
|
||||
} else if (charset == "JIS") {
|
||||
return ShiftJIS().decode(data);
|
||||
} else if (charset == "UNICODE") {
|
||||
// UTF16
|
||||
return String.fromCharCodes(data.buffer.asUint16List());
|
||||
} else {
|
||||
// unknown, treat as utf8
|
||||
return utf8.decode(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final TypeId typeId;
|
||||
final Uint8List _data;
|
||||
final int _count;
|
||||
|
||||
static final _log = Logger("np_exiv2.api.Value");
|
||||
}
|
||||
|
||||
class Metadatum {
|
||||
const Metadatum({
|
||||
required this.tagKey,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
factory Metadatum.fromNative(Exiv2Metadatum src) {
|
||||
return Metadatum(
|
||||
tagKey: src.tag_key.cast<ffi.Utf8>().toDartString(),
|
||||
value: Value(
|
||||
typeId: TypeId.fromNative(src.type_id),
|
||||
count: src.count,
|
||||
data: Uint8List.fromList(src.data.asTypedList(src.size)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final String tagKey;
|
||||
final Value value;
|
||||
}
|
||||
|
||||
class ReadResult {
|
||||
const ReadResult(this.width, this.height, this.iptcData, this.exifData);
|
||||
|
||||
factory ReadResult.fromNative(Exiv2ReadResult src) {
|
||||
_log.fine(
|
||||
"[fromNative] w: ${src.width}, h: ${src.height}, iptcCount: ${src.iptc_count}, exifCount: ${src.exif_count}");
|
||||
final iptcData = <Metadatum>[];
|
||||
for (var i = 0; i < src.iptc_count; ++i) {
|
||||
iptcData.add(Metadatum.fromNative(src.iptc_data[i]));
|
||||
}
|
||||
final exifData = <Metadatum>[];
|
||||
for (var i = 0; i < src.exif_count; ++i) {
|
||||
exifData.add(Metadatum.fromNative(src.exif_data[i]));
|
||||
}
|
||||
return ReadResult(src.width, src.height, iptcData, exifData);
|
||||
}
|
||||
|
||||
final int width;
|
||||
final int height;
|
||||
final List<Metadatum> iptcData;
|
||||
final List<Metadatum> exifData;
|
||||
|
||||
static final _log = Logger("np_exiv2.api.ReadResult");
|
||||
}
|
||||
|
||||
ReadResult readFile(String path) {
|
||||
final lib = _ensureLib();
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final pathC = path.toNativeUtf8();
|
||||
try {
|
||||
_log.fine("[readFile] Reading $path");
|
||||
final result = lib.exiv2_read_file(pathC.cast());
|
||||
if (result == nullptr) {
|
||||
_log.severe("[readFile] Result is null for file: $path");
|
||||
throw StateError("Failed to read file");
|
||||
}
|
||||
try {
|
||||
return ReadResult.fromNative(result[0]);
|
||||
} finally {
|
||||
lib.exiv2_result_free(result);
|
||||
}
|
||||
} finally {
|
||||
ffi.malloc.free(pathC);
|
||||
_log.fine("[readFile] Done in ${stopwatch.elapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
|
||||
ReadResult readBuffer(Uint8List buffer) {
|
||||
final lib = _ensureLib();
|
||||
final stopwatch = Stopwatch()..start();
|
||||
Pointer<Uint8>? cbuffer;
|
||||
try {
|
||||
_log.fine("[readBuffer] Allocating buffer with size: ${buffer.length}");
|
||||
cbuffer = ffi.malloc.allocate<Uint8>(buffer.length);
|
||||
final cbufferView = cbuffer.asTypedList(buffer.length);
|
||||
cbufferView.setAll(0, buffer);
|
||||
_log.fine("[readBuffer] Reading buffer");
|
||||
final result = lib.exiv2_read_buffer(cbuffer, buffer.length);
|
||||
if (result == nullptr) {
|
||||
_log.severe("[readBuffer] Result is null for buffer");
|
||||
throw StateError("Failed to read buffer");
|
||||
}
|
||||
try {
|
||||
return ReadResult.fromNative(result[0]);
|
||||
} finally {
|
||||
lib.exiv2_result_free(result);
|
||||
}
|
||||
} finally {
|
||||
if (cbuffer != null) {
|
||||
ffi.malloc.free(cbuffer);
|
||||
_log.fine("[readBuffer] Done in ${stopwatch.elapsedMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NpExiv2C _ensureLib() {
|
||||
_lib ??= NpExiv2C(DynamicLibrary.open("libnp_exiv2_c.so"));
|
||||
return _lib!;
|
||||
}
|
||||
|
||||
NpExiv2C? _lib;
|
||||
final _log = Logger("np_exiv2.api");
|
329
np_exiv2/lib/src/generated_bindings.g.dart
Normal file
329
np_exiv2/lib/src/generated_bindings.g.dart
Normal file
|
@ -0,0 +1,329 @@
|
|||
// ignore_for_file: unused_element, unused_field
|
||||
|
||||
// AUTO GENERATED FILE, DO NOT EDIT.
|
||||
//
|
||||
// Generated by `package:ffigen`.
|
||||
// ignore_for_file: type=lint
|
||||
import 'dart:ffi' as ffi;
|
||||
|
||||
class NpExiv2C {
|
||||
/// Holds the symbol lookup function.
|
||||
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
_lookup;
|
||||
|
||||
/// The symbols are looked up in [dynamicLibrary].
|
||||
NpExiv2C(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
|
||||
|
||||
/// The symbols are looked up with [lookup].
|
||||
NpExiv2C.fromLookup(
|
||||
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||
lookup)
|
||||
: _lookup = lookup;
|
||||
|
||||
/// Extract metadata from a file pointed to by @a path
|
||||
///
|
||||
/// @return A handle to retrieve actual results, 0 if failed
|
||||
ffi.Pointer<Exiv2ReadResult> exiv2_read_file(
|
||||
ffi.Pointer<ffi.Char> path,
|
||||
) {
|
||||
return _exiv2_read_file(
|
||||
path,
|
||||
);
|
||||
}
|
||||
|
||||
late final _exiv2_read_filePtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<Exiv2ReadResult> Function(
|
||||
ffi.Pointer<ffi.Char>)>>('exiv2_read_file');
|
||||
late final _exiv2_read_file = _exiv2_read_filePtr.asFunction<
|
||||
ffi.Pointer<Exiv2ReadResult> Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
/// Extract metadata from a buffer
|
||||
///
|
||||
/// @return A handle to retrieve actual results, 0 if failed
|
||||
ffi.Pointer<Exiv2ReadResult> exiv2_read_buffer(
|
||||
ffi.Pointer<ffi.Uint8> buffer,
|
||||
int size,
|
||||
) {
|
||||
return _exiv2_read_buffer(
|
||||
buffer,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
late final _exiv2_read_bufferPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<Exiv2ReadResult> Function(
|
||||
ffi.Pointer<ffi.Uint8>, ffi.Size)>>('exiv2_read_buffer');
|
||||
late final _exiv2_read_buffer = _exiv2_read_bufferPtr.asFunction<
|
||||
ffi.Pointer<Exiv2ReadResult> Function(ffi.Pointer<ffi.Uint8>, int)>();
|
||||
|
||||
/// Release the resources of a Exiv2ReadResult object returned by
|
||||
/// @a exiv2_read_file
|
||||
void exiv2_result_free(
|
||||
ffi.Pointer<Exiv2ReadResult> that,
|
||||
) {
|
||||
return _exiv2_result_free(
|
||||
that,
|
||||
);
|
||||
}
|
||||
|
||||
late final _exiv2_result_freePtr = _lookup<
|
||||
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<Exiv2ReadResult>)>>(
|
||||
'exiv2_result_free');
|
||||
late final _exiv2_result_free = _exiv2_result_freePtr
|
||||
.asFunction<void Function(ffi.Pointer<Exiv2ReadResult>)>();
|
||||
}
|
||||
|
||||
final class __mbstate_t extends ffi.Union {
|
||||
@ffi.Array.multi([128])
|
||||
external ffi.Array<ffi.Char> __mbstate8;
|
||||
|
||||
@ffi.LongLong()
|
||||
external int _mbstateL;
|
||||
}
|
||||
|
||||
enum Exiv2TypeId {
|
||||
exiv2_type_id_unsigned_byte(0),
|
||||
exiv2_type_id_ascii_string(1),
|
||||
exiv2_type_id_unsigned_short(2),
|
||||
exiv2_type_id_unsigned_long(3),
|
||||
exiv2_type_id_unsigned_rational(4),
|
||||
exiv2_type_id_signed_byte(5),
|
||||
exiv2_type_id_undefined(6),
|
||||
exiv2_type_id_signed_short(7),
|
||||
exiv2_type_id_signed_long(8),
|
||||
exiv2_type_id_signed_rational(9),
|
||||
exiv2_type_id_tiff_float(10),
|
||||
exiv2_type_id_tiff_double(11),
|
||||
exiv2_type_id_tiff_ifd(12),
|
||||
exiv2_type_id_unsigned_long_long(13),
|
||||
exiv2_type_id_signed_long_long(14),
|
||||
exiv2_type_id_tiff_ifd8(15),
|
||||
exiv2_type_id_string(16),
|
||||
exiv2_type_id_date(17),
|
||||
exiv2_type_id_time(18),
|
||||
exiv2_type_id_comment(19),
|
||||
exiv2_type_id_directory(20),
|
||||
exiv2_type_id_xmp_text(21),
|
||||
exiv2_type_id_xmp_alt(22),
|
||||
exiv2_type_id_xmp_bag(23),
|
||||
exiv2_type_id_xmp_seq(24),
|
||||
exiv2_type_id_lang_alt(25),
|
||||
exiv2_type_id_invalid_type_id(26);
|
||||
|
||||
final int value;
|
||||
const Exiv2TypeId(this.value);
|
||||
|
||||
static Exiv2TypeId fromValue(int value) => switch (value) {
|
||||
0 => exiv2_type_id_unsigned_byte,
|
||||
1 => exiv2_type_id_ascii_string,
|
||||
2 => exiv2_type_id_unsigned_short,
|
||||
3 => exiv2_type_id_unsigned_long,
|
||||
4 => exiv2_type_id_unsigned_rational,
|
||||
5 => exiv2_type_id_signed_byte,
|
||||
6 => exiv2_type_id_undefined,
|
||||
7 => exiv2_type_id_signed_short,
|
||||
8 => exiv2_type_id_signed_long,
|
||||
9 => exiv2_type_id_signed_rational,
|
||||
10 => exiv2_type_id_tiff_float,
|
||||
11 => exiv2_type_id_tiff_double,
|
||||
12 => exiv2_type_id_tiff_ifd,
|
||||
13 => exiv2_type_id_unsigned_long_long,
|
||||
14 => exiv2_type_id_signed_long_long,
|
||||
15 => exiv2_type_id_tiff_ifd8,
|
||||
16 => exiv2_type_id_string,
|
||||
17 => exiv2_type_id_date,
|
||||
18 => exiv2_type_id_time,
|
||||
19 => exiv2_type_id_comment,
|
||||
20 => exiv2_type_id_directory,
|
||||
21 => exiv2_type_id_xmp_text,
|
||||
22 => exiv2_type_id_xmp_alt,
|
||||
23 => exiv2_type_id_xmp_bag,
|
||||
24 => exiv2_type_id_xmp_seq,
|
||||
25 => exiv2_type_id_lang_alt,
|
||||
26 => exiv2_type_id_invalid_type_id,
|
||||
_ => throw ArgumentError("Unknown value for Exiv2TypeId: $value"),
|
||||
};
|
||||
}
|
||||
|
||||
/// A key value pair
|
||||
final class Exiv2Metadatum extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.Char> tag_key;
|
||||
|
||||
@ffi.UnsignedInt()
|
||||
external int type_idAsInt;
|
||||
|
||||
Exiv2TypeId get type_id => Exiv2TypeId.fromValue(type_idAsInt);
|
||||
|
||||
external ffi.Pointer<ffi.Uint8> data;
|
||||
|
||||
@ffi.Size()
|
||||
external int size;
|
||||
|
||||
@ffi.Size()
|
||||
external int count;
|
||||
}
|
||||
|
||||
final class Exiv2ReadResult extends ffi.Struct {
|
||||
@ffi.Uint32()
|
||||
external int width;
|
||||
|
||||
@ffi.Uint32()
|
||||
external int height;
|
||||
|
||||
external ffi.Pointer<Exiv2Metadatum> iptc_data;
|
||||
|
||||
@ffi.Size()
|
||||
external int iptc_count;
|
||||
|
||||
external ffi.Pointer<Exiv2Metadatum> exif_data;
|
||||
|
||||
@ffi.Size()
|
||||
external int exif_count;
|
||||
|
||||
external ffi.Pointer<Exiv2Metadatum> xmp_data;
|
||||
|
||||
@ffi.Size()
|
||||
external int xmp_count;
|
||||
}
|
||||
|
||||
const int NULL = 0;
|
||||
|
||||
const int __has_safe_buffers = 1;
|
||||
|
||||
const int __DARWIN_ONLY_64_BIT_INO_T = 0;
|
||||
|
||||
const int __DARWIN_ONLY_UNIX_CONFORMANCE = 0;
|
||||
|
||||
const int __DARWIN_ONLY_VERS_1050 = 0;
|
||||
|
||||
const int __DARWIN_UNIX03 = 0;
|
||||
|
||||
const int __DARWIN_64_BIT_INO_T = 0;
|
||||
|
||||
const int __DARWIN_VERS_1050 = 0;
|
||||
|
||||
const int __DARWIN_NON_CANCELABLE = 0;
|
||||
|
||||
const String __DARWIN_SUF_EXTSN = '\$DARWIN_EXTSN';
|
||||
|
||||
const int __DARWIN_C_ANSI = 4096;
|
||||
|
||||
const int __DARWIN_C_FULL = 900000;
|
||||
|
||||
const int __DARWIN_C_LEVEL = 900000;
|
||||
|
||||
const int __STDC_WANT_LIB_EXT1__ = 1;
|
||||
|
||||
const int __DARWIN_NO_LONG_LONG = 0;
|
||||
|
||||
const int __has_ptrcheck = 0;
|
||||
|
||||
const int USER_ADDR_NULL = 0;
|
||||
|
||||
const int __WORDSIZE = 64;
|
||||
|
||||
const int INT8_MAX = 127;
|
||||
|
||||
const int INT16_MAX = 32767;
|
||||
|
||||
const int INT32_MAX = 2147483647;
|
||||
|
||||
const int INT64_MAX = 9223372036854775807;
|
||||
|
||||
const int INT8_MIN = -128;
|
||||
|
||||
const int INT16_MIN = -32768;
|
||||
|
||||
const int INT32_MIN = -2147483648;
|
||||
|
||||
const int INT64_MIN = -9223372036854775808;
|
||||
|
||||
const int UINT8_MAX = 255;
|
||||
|
||||
const int UINT16_MAX = 65535;
|
||||
|
||||
const int UINT32_MAX = 4294967295;
|
||||
|
||||
const int UINT64_MAX = -1;
|
||||
|
||||
const int INT_LEAST8_MIN = -128;
|
||||
|
||||
const int INT_LEAST16_MIN = -32768;
|
||||
|
||||
const int INT_LEAST32_MIN = -2147483648;
|
||||
|
||||
const int INT_LEAST64_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_LEAST8_MAX = 127;
|
||||
|
||||
const int INT_LEAST16_MAX = 32767;
|
||||
|
||||
const int INT_LEAST32_MAX = 2147483647;
|
||||
|
||||
const int INT_LEAST64_MAX = 9223372036854775807;
|
||||
|
||||
const int UINT_LEAST8_MAX = 255;
|
||||
|
||||
const int UINT_LEAST16_MAX = 65535;
|
||||
|
||||
const int UINT_LEAST32_MAX = 4294967295;
|
||||
|
||||
const int UINT_LEAST64_MAX = -1;
|
||||
|
||||
const int INT_FAST8_MIN = -128;
|
||||
|
||||
const int INT_FAST16_MIN = -32768;
|
||||
|
||||
const int INT_FAST32_MIN = -2147483648;
|
||||
|
||||
const int INT_FAST64_MIN = -9223372036854775808;
|
||||
|
||||
const int INT_FAST8_MAX = 127;
|
||||
|
||||
const int INT_FAST16_MAX = 32767;
|
||||
|
||||
const int INT_FAST32_MAX = 2147483647;
|
||||
|
||||
const int INT_FAST64_MAX = 9223372036854775807;
|
||||
|
||||
const int UINT_FAST8_MAX = 255;
|
||||
|
||||
const int UINT_FAST16_MAX = 65535;
|
||||
|
||||
const int UINT_FAST32_MAX = 4294967295;
|
||||
|
||||
const int UINT_FAST64_MAX = -1;
|
||||
|
||||
const int INTPTR_MAX = 9223372036854775807;
|
||||
|
||||
const int INTPTR_MIN = -9223372036854775808;
|
||||
|
||||
const int UINTPTR_MAX = -1;
|
||||
|
||||
const int INTMAX_MAX = 9223372036854775807;
|
||||
|
||||
const int UINTMAX_MAX = -1;
|
||||
|
||||
const int INTMAX_MIN = -9223372036854775808;
|
||||
|
||||
const int PTRDIFF_MIN = -9223372036854775808;
|
||||
|
||||
const int PTRDIFF_MAX = 9223372036854775807;
|
||||
|
||||
const int SIZE_MAX = -1;
|
||||
|
||||
const int RSIZE_MAX = 9223372036854775807;
|
||||
|
||||
const int WCHAR_MAX = 2147483647;
|
||||
|
||||
const int WCHAR_MIN = -2147483648;
|
||||
|
||||
const int WINT_MIN = -2147483648;
|
||||
|
||||
const int WINT_MAX = 2147483647;
|
||||
|
||||
const int SIG_ATOMIC_MIN = -2147483648;
|
||||
|
||||
const int SIG_ATOMIC_MAX = 2147483647;
|
23
np_exiv2/pubspec.yaml
Normal file
23
np_exiv2/pubspec.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: np_exiv2
|
||||
description: A starting point for Dart libraries or applications.
|
||||
version: 1.0.0
|
||||
# repository: https://github.com/my_org/my_repo
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
|
||||
# Add regular dependencies here.
|
||||
dependencies:
|
||||
euc: ^1.0.6+8
|
||||
ffi: ^2.1.3
|
||||
logging: ^1.2.0
|
||||
np_common:
|
||||
path: ../np_common
|
||||
path: ^1.8.3
|
||||
quiver: ^3.2.1
|
||||
|
||||
dev_dependencies:
|
||||
ffigen: ^14.0.1
|
||||
np_lints:
|
||||
path: ../np_lints
|
29
np_exiv2_lib/.gitignore
vendored
Normal file
29
np_exiv2_lib/.gitignore
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
build/
|
30
np_exiv2_lib/.metadata
Normal file
30
np_exiv2_lib/.metadata
Normal file
|
@ -0,0 +1,30 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
|
||||
channel: "stable"
|
||||
|
||||
project_type: plugin
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||
- platform: android
|
||||
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
9
np_exiv2_lib/android/.gitignore
vendored
Normal file
9
np_exiv2_lib/android/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.cxx
|
|
@ -0,0 +1,23 @@
|
|||
package io.flutter.plugins;
|
||||
|
||||
import io.flutter.plugin.common.PluginRegistry;
|
||||
|
||||
/**
|
||||
* Generated file. Do not edit.
|
||||
*/
|
||||
public final class GeneratedPluginRegistrant {
|
||||
public static void registerWith(PluginRegistry registry) {
|
||||
if (alreadyRegisteredWith(registry)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean alreadyRegisteredWith(PluginRegistry registry) {
|
||||
final String key = GeneratedPluginRegistrant.class.getCanonicalName();
|
||||
if (registry.hasPlugin(key)) {
|
||||
return true;
|
||||
}
|
||||
registry.registrarFor(key);
|
||||
return false;
|
||||
}
|
||||
}
|
42
np_exiv2_lib/android/build.gradle
Normal file
42
np_exiv2_lib/android/build.gradle
Normal file
|
@ -0,0 +1,42 @@
|
|||
group 'com.nkming.nc_photos.np_exiv2_lib'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.8.20'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
namespace 'com.nkming.nc_photos.np_exiv2_lib'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk 23
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
1
np_exiv2_lib/android/settings.gradle
Normal file
1
np_exiv2_lib/android/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
rootProject.name = 'np_exiv2_lib'
|
2
np_exiv2_lib/android/src/main/AndroidManifest.xml
Normal file
2
np_exiv2_lib/android/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
</manifest>
|
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlicommon.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlicommon.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlidec.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlidec.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libexiv2.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libexiv2.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libnp_exiv2_c.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libnp_exiv2_c.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlicommon.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlicommon.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlidec.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlidec.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libexiv2.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libexiv2.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libnp_exiv2_c.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libnp_exiv2_c.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlicommon.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlicommon.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlidec.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlidec.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libexiv2.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libexiv2.so
Executable file
Binary file not shown.
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libnp_exiv2_c.so
Executable file
BIN
np_exiv2_lib/android/src/main/jniLibs/x86_64/libnp_exiv2_c.so
Executable file
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
package com.nkming.nc_photos.np_exiv2_lib
|
||||
|
||||
import androidx.annotation.NonNull
|
||||
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.plugin.common.MethodChannel.Result
|
||||
|
||||
/** NpExiv2LibPlugin */
|
||||
class NpExiv2LibPlugin: FlutterPlugin, MethodCallHandler {
|
||||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||
}
|
||||
|
||||
override fun onMethodCall(call: MethodCall, result: Result) {
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
}
|
||||
}
|
20
np_exiv2_lib/pubspec.yaml
Normal file
20
np_exiv2_lib/pubspec.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
name: np_exiv2_lib
|
||||
description: "A new Flutter plugin project."
|
||||
version: 0.0.1
|
||||
homepage:
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
platforms:
|
||||
android:
|
||||
package: com.nkming.nc_photos.np_exiv2_lib
|
||||
pluginClass: NpExiv2LibPlugin
|
Loading…
Reference in a new issue