diff --git a/np_exiv2/.gitignore b/np_exiv2/.gitignore new file mode 100644 index 00000000..3cceda55 --- /dev/null +++ b/np_exiv2/.gitignore @@ -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 diff --git a/np_exiv2/analysis_options.yaml b/np_exiv2/analysis_options.yaml new file mode 100644 index 00000000..f92d2567 --- /dev/null +++ b/np_exiv2/analysis_options.yaml @@ -0,0 +1 @@ +include: package:np_lints/np.yaml diff --git a/np_exiv2/ffigen.yaml b/np_exiv2/ffigen.yaml new file mode 100644 index 00000000..fc88a058 --- /dev/null +++ b/np_exiv2/ffigen.yaml @@ -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 diff --git a/np_exiv2/headers/np_exiv2_c.h b/np_exiv2/headers/np_exiv2_c.h new file mode 100644 index 00000000..5f58bccd --- /dev/null +++ b/np_exiv2/headers/np_exiv2_c.h @@ -0,0 +1,91 @@ +#pragma once +#pragma GCC visibility push(default) + +#include +#include + +#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 diff --git a/np_exiv2/lib/np_exiv2.dart b/np_exiv2/lib/np_exiv2.dart new file mode 100644 index 00000000..2a3bc226 --- /dev/null +++ b/np_exiv2/lib/np_exiv2.dart @@ -0,0 +1,3 @@ +library np_exiv2; + +export 'src/api.dart'; diff --git a/np_exiv2/lib/src/api.dart b/np_exiv2/lib/src/api.dart new file mode 100644 index 00000000..3bdf5216 --- /dev/null +++ b/np_exiv2/lib/src/api.dart @@ -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() => 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 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().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 = []; + for (var i = 0; i < src.iptc_count; ++i) { + iptcData.add(Metadatum.fromNative(src.iptc_data[i])); + } + final exifData = []; + 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 iptcData; + final List 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? cbuffer; + try { + _log.fine("[readBuffer] Allocating buffer with size: ${buffer.length}"); + cbuffer = ffi.malloc.allocate(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"); diff --git a/np_exiv2/lib/src/generated_bindings.g.dart b/np_exiv2/lib/src/generated_bindings.g.dart new file mode 100644 index 00000000..6aa1c116 --- /dev/null +++ b/np_exiv2/lib/src/generated_bindings.g.dart @@ -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 Function(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 Function(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 exiv2_read_file( + ffi.Pointer path, + ) { + return _exiv2_read_file( + path, + ); + } + + late final _exiv2_read_filePtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer)>>('exiv2_read_file'); + late final _exiv2_read_file = _exiv2_read_filePtr.asFunction< + ffi.Pointer Function(ffi.Pointer)>(); + + /// Extract metadata from a buffer + /// + /// @return A handle to retrieve actual results, 0 if failed + ffi.Pointer exiv2_read_buffer( + ffi.Pointer buffer, + int size, + ) { + return _exiv2_read_buffer( + buffer, + size, + ); + } + + late final _exiv2_read_bufferPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, ffi.Size)>>('exiv2_read_buffer'); + late final _exiv2_read_buffer = _exiv2_read_bufferPtr.asFunction< + ffi.Pointer Function(ffi.Pointer, int)>(); + + /// Release the resources of a Exiv2ReadResult object returned by + /// @a exiv2_read_file + void exiv2_result_free( + ffi.Pointer that, + ) { + return _exiv2_result_free( + that, + ); + } + + late final _exiv2_result_freePtr = _lookup< + ffi.NativeFunction)>>( + 'exiv2_result_free'); + late final _exiv2_result_free = _exiv2_result_freePtr + .asFunction)>(); +} + +final class __mbstate_t extends ffi.Union { + @ffi.Array.multi([128]) + external ffi.Array __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 tag_key; + + @ffi.UnsignedInt() + external int type_idAsInt; + + Exiv2TypeId get type_id => Exiv2TypeId.fromValue(type_idAsInt); + + external ffi.Pointer 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 iptc_data; + + @ffi.Size() + external int iptc_count; + + external ffi.Pointer exif_data; + + @ffi.Size() + external int exif_count; + + external ffi.Pointer 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; diff --git a/np_exiv2/pubspec.yaml b/np_exiv2/pubspec.yaml new file mode 100644 index 00000000..68f68a99 --- /dev/null +++ b/np_exiv2/pubspec.yaml @@ -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 diff --git a/np_exiv2_lib/.gitignore b/np_exiv2_lib/.gitignore new file mode 100644 index 00000000..ac5aa989 --- /dev/null +++ b/np_exiv2_lib/.gitignore @@ -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/ diff --git a/np_exiv2_lib/.metadata b/np_exiv2_lib/.metadata new file mode 100644 index 00000000..efbb05a3 --- /dev/null +++ b/np_exiv2_lib/.metadata @@ -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' diff --git a/np_exiv2_lib/android/.gitignore b/np_exiv2_lib/android/.gitignore new file mode 100644 index 00000000..161bdcda --- /dev/null +++ b/np_exiv2_lib/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/np_exiv2_lib/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/np_exiv2_lib/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 00000000..d007606a --- /dev/null +++ b/np_exiv2_lib/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -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; + } +} diff --git a/np_exiv2_lib/android/build.gradle b/np_exiv2_lib/android/build.gradle new file mode 100644 index 00000000..37c5ef53 --- /dev/null +++ b/np_exiv2_lib/android/build.gradle @@ -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' + } +} diff --git a/np_exiv2_lib/android/settings.gradle b/np_exiv2_lib/android/settings.gradle new file mode 100644 index 00000000..cfc71ad0 --- /dev/null +++ b/np_exiv2_lib/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'np_exiv2_lib' diff --git a/np_exiv2_lib/android/src/main/AndroidManifest.xml b/np_exiv2_lib/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..a2f47b60 --- /dev/null +++ b/np_exiv2_lib/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlicommon.so b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlicommon.so new file mode 100755 index 00000000..4b138ac1 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlicommon.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlidec.so b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlidec.so new file mode 100755 index 00000000..a0f899ad Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libbrotlidec.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libexiv2.so b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libexiv2.so new file mode 100755 index 00000000..24fca8f9 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libexiv2.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libnp_exiv2_c.so b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libnp_exiv2_c.so new file mode 100755 index 00000000..36d4fc83 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/arm64-v8a/libnp_exiv2_c.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlicommon.so b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlicommon.so new file mode 100755 index 00000000..92526daf Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlicommon.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlidec.so b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlidec.so new file mode 100755 index 00000000..59bfb91c Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libbrotlidec.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libexiv2.so b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libexiv2.so new file mode 100755 index 00000000..462a782b Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libexiv2.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libnp_exiv2_c.so b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libnp_exiv2_c.so new file mode 100755 index 00000000..3ca828d1 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/armeabi-v7a/libnp_exiv2_c.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlicommon.so b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlicommon.so new file mode 100755 index 00000000..9d086677 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlicommon.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlidec.so b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlidec.so new file mode 100755 index 00000000..6b2f0cd7 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libbrotlidec.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/x86_64/libexiv2.so b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libexiv2.so new file mode 100755 index 00000000..4cfca4f0 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libexiv2.so differ diff --git a/np_exiv2_lib/android/src/main/jniLibs/x86_64/libnp_exiv2_c.so b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libnp_exiv2_c.so new file mode 100755 index 00000000..84b7fc32 Binary files /dev/null and b/np_exiv2_lib/android/src/main/jniLibs/x86_64/libnp_exiv2_c.so differ diff --git a/np_exiv2_lib/android/src/main/kotlin/com/nkming/nc_photos/np_exiv2_lib/NpExiv2LibPlugin.kt b/np_exiv2_lib/android/src/main/kotlin/com/nkming/nc_photos/np_exiv2_lib/NpExiv2LibPlugin.kt new file mode 100644 index 00000000..552b97e3 --- /dev/null +++ b/np_exiv2_lib/android/src/main/kotlin/com/nkming/nc_photos/np_exiv2_lib/NpExiv2LibPlugin.kt @@ -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) { + } +} diff --git a/np_exiv2_lib/pubspec.yaml b/np_exiv2_lib/pubspec.yaml new file mode 100644 index 00000000..990e92bd --- /dev/null +++ b/np_exiv2_lib/pubspec.yaml @@ -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