react-native-image-compression-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +562 -0
  3. package/android/build.gradle +63 -0
  4. package/android/src/main/AndroidManifest.xml +1 -0
  5. package/android/src/main/java/com/imagecompressionkit/ImageCompressionKitModule.kt +1127 -0
  6. package/android/src/main/java/com/imagecompressionkit/ImageCompressionKitPackage.kt +33 -0
  7. package/android/src/main/java/com/imagecompressionkit/ImageCompressionOutput.kt +396 -0
  8. package/android/src/main/java/com/imagecompressionkit/JpegExifMetadata.kt +233 -0
  9. package/ios/RCTImageCompressionKit.h +10 -0
  10. package/ios/RCTImageCompressionKit.mm +72 -0
  11. package/lib/NativeImageCompressionKit.d.ts +55 -0
  12. package/lib/NativeImageCompressionKit.d.ts.map +1 -0
  13. package/lib/NativeImageCompressionKit.js +5 -0
  14. package/lib/NativeImageCompressionKit.js.map +1 -0
  15. package/lib/api.d.ts +4 -0
  16. package/lib/api.d.ts.map +1 -0
  17. package/lib/api.js +25 -0
  18. package/lib/api.js.map +1 -0
  19. package/lib/errors.d.ts +9 -0
  20. package/lib/errors.d.ts.map +1 -0
  21. package/lib/errors.js +53 -0
  22. package/lib/errors.js.map +1 -0
  23. package/lib/index.d.ts +5 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +14 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/nativeModule.d.ts +7 -0
  28. package/lib/nativeModule.d.ts.map +1 -0
  29. package/lib/nativeModule.js +73 -0
  30. package/lib/nativeModule.js.map +1 -0
  31. package/lib/types.d.ts +59 -0
  32. package/lib/types.d.ts.map +1 -0
  33. package/lib/types.js +23 -0
  34. package/lib/types.js.map +1 -0
  35. package/lib/validation.d.ts +3 -0
  36. package/lib/validation.d.ts.map +1 -0
  37. package/lib/validation.js +108 -0
  38. package/lib/validation.js.map +1 -0
  39. package/package.json +106 -0
  40. package/react-native-image-compression-kit.podspec +21 -0
  41. package/react-native.config.js +12 -0
  42. package/src/NativeImageCompressionKit.ts +81 -0
  43. package/src/api.ts +28 -0
  44. package/src/errors.ts +91 -0
  45. package/src/index.ts +25 -0
  46. package/src/nativeModule.ts +130 -0
  47. package/src/types.ts +88 -0
  48. package/src/validation.ts +181 -0
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "react-native-image-compression-kit",
3
+ "version": "0.1.0",
4
+ "description": "Native-first image compression and transcoding pipeline for React Native.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/GGULBAE/react-native-image-compression-kit.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/GGULBAE/react-native-image-compression-kit/issues"
12
+ },
13
+ "homepage": "https://github.com/GGULBAE/react-native-image-compression-kit#readme",
14
+ "main": "lib/index.js",
15
+ "types": "lib/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "android/build.gradle",
24
+ "android/src/main",
25
+ "ios",
26
+ "lib",
27
+ "src",
28
+ "README.md",
29
+ "LICENSE",
30
+ "react-native-image-compression-kit.podspec",
31
+ "react-native.config.js"
32
+ ],
33
+ "keywords": [
34
+ "react-native",
35
+ "image",
36
+ "image-processing",
37
+ "compression",
38
+ "resize",
39
+ "transcode",
40
+ "jpeg",
41
+ "png",
42
+ "webp",
43
+ "heic",
44
+ "heif",
45
+ "avif"
46
+ ],
47
+ "peerDependencies": {
48
+ "react-native": ">=0.73 <1.0"
49
+ },
50
+ "codegenConfig": {
51
+ "name": "RNImageCompressionKitSpec",
52
+ "type": "modules",
53
+ "jsSrcsDir": "src",
54
+ "outputDir": {
55
+ "ios": "ios/generated",
56
+ "android": "android/generated"
57
+ },
58
+ "android": {
59
+ "javaPackageName": "com.imagecompressionkit"
60
+ },
61
+ "ios": {
62
+ "modulesProvider": {
63
+ "ImageCompressionKit": "RCTImageCompressionKit"
64
+ }
65
+ }
66
+ },
67
+ "devDependencies": {
68
+ "typescript": "^5.9.3",
69
+ "vitest": "^4.0.16"
70
+ },
71
+ "engines": {
72
+ "node": ">=18"
73
+ },
74
+ "scripts": {
75
+ "build": "tsc -p tsconfig.build.json",
76
+ "example:android": "pnpm --filter image-compression-kit-example android",
77
+ "example:build": "RNICK_ANDROID_APP_DIR=example/android pnpm android:build",
78
+ "example:codegen": "RNICK_ANDROID_APP_DIR=example/android pnpm android:codegen",
79
+ "example:android-instrumentation": "RNICK_ANDROID_APP_DIR=example/android RNICK_ANDROID_GRADLE_TASK=:react-native-image-compression-kit:connectedDebugAndroidTest pnpm android:build",
80
+ "example:android-unit-test": "RNICK_ANDROID_APP_DIR=example/android RNICK_ANDROID_GRADLE_TASK=:react-native-image-compression-kit:testDebugUnitTest pnpm android:build",
81
+ "example:start": "pnpm --filter image-compression-kit-example start",
82
+ "example:typecheck": "pnpm --filter image-compression-kit-example typecheck",
83
+ "fixtures:avif": "node scripts/generate-avif-fixtures.mjs",
84
+ "fixtures:avif:check": "node scripts/generate-avif-fixtures.mjs --check",
85
+ "fixtures:heic-heif": "node scripts/generate-heic-heif-fixtures.mjs",
86
+ "fixtures:heic-heif:check": "node scripts/generate-heic-heif-fixtures.mjs --check",
87
+ "hooks:install": "node scripts/install-git-hooks.mjs",
88
+ "release:dry-run": "node scripts/release-dry-run.mjs",
89
+ "smoke:consumer": "pnpm build && node scripts/consumer-smoke-test.mjs",
90
+ "verify": "pnpm typecheck && pnpm test && pnpm build && pnpm android:doctor",
91
+ "android:doctor": "node scripts/android-verification.mjs doctor",
92
+ "android:codegen": "node scripts/android-verification.mjs codegen",
93
+ "android:build": "node scripts/android-verification.mjs build",
94
+ "docker:android:build": "node scripts/docker-android.mjs build",
95
+ "docker:android:verify": "node scripts/docker-android.mjs verify",
96
+ "docker:android:example:typecheck": "node scripts/docker-android.mjs example:typecheck",
97
+ "docker:android:example:codegen": "node scripts/docker-android.mjs example:codegen",
98
+ "docker:android:example:android-unit-test": "node scripts/docker-android.mjs example:android-unit-test",
99
+ "docker:android:example:build": "node scripts/docker-android.mjs example:build",
100
+ "docker:android:ci": "node scripts/docker-android.mjs ci",
101
+ "docker:android:shell": "node scripts/docker-android.mjs shell",
102
+ "typecheck": "tsc -p tsconfig.json --noEmit",
103
+ "test": "vitest run",
104
+ "test:watch": "vitest"
105
+ }
106
+ }
@@ -0,0 +1,21 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-image-compression-kit"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.license = package["license"]
10
+ s.homepage = "https://github.com/GGULBAE/react-native-image-compression-kit"
11
+ s.authors = "react-native-image-compression-kit contributors"
12
+ s.source = { :git => "https://github.com/GGULBAE/react-native-image-compression-kit.git", :tag => "#{s.version}" }
13
+ s.platforms = { :ios => "13.4" }
14
+ s.source_files = "ios/**/*.{h,m,mm}"
15
+
16
+ if respond_to?(:install_modules_dependencies, true)
17
+ install_modules_dependencies(s)
18
+ else
19
+ s.dependency "React-Core"
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ android: {
5
+ sourceDir: './android',
6
+ packageImportPath:
7
+ 'import com.imagecompressionkit.ImageCompressionKitPackage;',
8
+ packageInstance: 'new ImageCompressionKitPackage()',
9
+ },
10
+ },
11
+ },
12
+ };
@@ -0,0 +1,81 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+
4
+ export type NativeImageFormat =
5
+ | 'jpeg'
6
+ | 'png'
7
+ | 'webp'
8
+ | 'heic'
9
+ | 'heif'
10
+ | 'avif'
11
+ | 'gif';
12
+
13
+ export type NativeOutputFormat =
14
+ | 'jpeg'
15
+ | 'png'
16
+ | 'webp'
17
+ | 'heic'
18
+ | 'heif'
19
+ | 'avif';
20
+
21
+ export type NativeMetadataPolicy = 'preserve' | 'safe' | 'strip';
22
+ export type NativeResizeMode = 'contain' | 'cover' | 'stretch';
23
+
24
+ export type NativeCompressionSource = {
25
+ uri: string;
26
+ };
27
+
28
+ export type NativeResizeOptions = {
29
+ maxWidth?: number;
30
+ maxHeight?: number;
31
+ mode: NativeResizeMode;
32
+ };
33
+
34
+ export type NativeOutputOptions = {
35
+ format: NativeOutputFormat;
36
+ quality?: number;
37
+ maxBytes?: number;
38
+ };
39
+
40
+ export type NativeCompressionOptions = {
41
+ source: NativeCompressionSource;
42
+ resize?: NativeResizeOptions;
43
+ output: NativeOutputOptions;
44
+ metadata: NativeMetadataPolicy;
45
+ };
46
+
47
+ export type NativeCompressionResult = {
48
+ uri: string;
49
+ format: NativeOutputFormat;
50
+ width: number;
51
+ height: number;
52
+ byteSize: number;
53
+ originalByteSize: number;
54
+ compressionRatio: number;
55
+ };
56
+
57
+ export type NativeFormatCapability = {
58
+ format: NativeImageFormat;
59
+ input: boolean;
60
+ output: boolean;
61
+ supportsAlpha: boolean;
62
+ supportsAnimation: boolean;
63
+ notes?: Array<string>;
64
+ };
65
+
66
+ export type NativeImageCompressionCapabilities = {
67
+ platform: 'android' | 'ios' | 'unknown';
68
+ formats: Array<NativeFormatCapability>;
69
+ metadataPolicies: Array<NativeMetadataPolicy>;
70
+ supportsTargetSizeCompression: boolean;
71
+ supportsCancellation: boolean;
72
+ };
73
+
74
+ export interface Spec extends TurboModule {
75
+ compressImage(
76
+ options: NativeCompressionOptions
77
+ ): Promise<NativeCompressionResult>;
78
+ getImageCompressionCapabilities(): Promise<NativeImageCompressionCapabilities>;
79
+ }
80
+
81
+ export default TurboModuleRegistry.get<Spec>('ImageCompressionKit');
package/src/api.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { normalizeNativeError } from './errors';
2
+ import { getNativeModule } from './nativeModule';
3
+ import type {
4
+ CompressionOptions,
5
+ CompressionResult,
6
+ ImageCompressionCapabilities,
7
+ } from './types';
8
+ import { normalizeCompressionOptions } from './validation';
9
+
10
+ export async function compressImage(
11
+ options: CompressionOptions
12
+ ): Promise<CompressionResult> {
13
+ const normalizedOptions = normalizeCompressionOptions(options);
14
+
15
+ try {
16
+ return await getNativeModule().compressImage(normalizedOptions);
17
+ } catch (error) {
18
+ throw normalizeNativeError(error);
19
+ }
20
+ }
21
+
22
+ export async function getImageCompressionCapabilities(): Promise<ImageCompressionCapabilities> {
23
+ try {
24
+ return await getNativeModule().getImageCompressionCapabilities();
25
+ } catch (error) {
26
+ throw normalizeNativeError(error);
27
+ }
28
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,91 @@
1
+ export type ImageCompressionKitErrorCode =
2
+ | 'ERR_INVALID_OPTIONS'
3
+ | 'ERR_UNSUPPORTED_SOURCE'
4
+ | 'ERR_UNSUPPORTED_FORMAT'
5
+ | 'ERR_NATIVE_MODULE_UNAVAILABLE'
6
+ | 'ERR_NOT_IMPLEMENTED'
7
+ | 'ERR_FILE_ACCESS'
8
+ | 'ERR_DECODE_FAILED'
9
+ | 'ERR_ENCODE_FAILED'
10
+ | 'ERR_NATIVE_OPERATION_FAILED';
11
+
12
+ export class ImageCompressionKitError extends Error {
13
+ readonly code: ImageCompressionKitErrorCode;
14
+
15
+ constructor(
16
+ code: ImageCompressionKitErrorCode,
17
+ message: string,
18
+ options?: { cause?: unknown }
19
+ ) {
20
+ super(message);
21
+ this.name = 'ImageCompressionKitError';
22
+ this.code = code;
23
+
24
+ if (options && 'cause' in options) {
25
+ (this as Error & { cause?: unknown }).cause = options.cause;
26
+ }
27
+ }
28
+ }
29
+
30
+ export function normalizeNativeError(error: unknown): Error {
31
+ if (error instanceof ImageCompressionKitError) {
32
+ return error;
33
+ }
34
+
35
+ if (error instanceof Error) {
36
+ return new ImageCompressionKitError(
37
+ getNativeErrorCode(error),
38
+ error.message || 'Native image compression failed.',
39
+ { cause: error }
40
+ );
41
+ }
42
+
43
+ if (isRecord(error)) {
44
+ const message =
45
+ typeof error.message === 'string'
46
+ ? error.message
47
+ : 'Native image compression failed.';
48
+
49
+ return new ImageCompressionKitError(
50
+ getNativeErrorCode(error),
51
+ message,
52
+ { cause: error }
53
+ );
54
+ }
55
+
56
+ return new ImageCompressionKitError(
57
+ 'ERR_NATIVE_OPERATION_FAILED',
58
+ 'Native image compression failed.',
59
+ { cause: error }
60
+ );
61
+ }
62
+
63
+ function isRecord(value: unknown): value is Record<string, unknown> {
64
+ return typeof value === 'object' && value !== null;
65
+ }
66
+
67
+ function getNativeErrorCode(value: unknown): ImageCompressionKitErrorCode {
68
+ if (!isRecord(value) || typeof value.code !== 'string') {
69
+ return 'ERR_NATIVE_OPERATION_FAILED';
70
+ }
71
+
72
+ return isImageCompressionKitErrorCode(value.code)
73
+ ? value.code
74
+ : 'ERR_NATIVE_OPERATION_FAILED';
75
+ }
76
+
77
+ function isImageCompressionKitErrorCode(
78
+ code: string
79
+ ): code is ImageCompressionKitErrorCode {
80
+ return (
81
+ code === 'ERR_INVALID_OPTIONS' ||
82
+ code === 'ERR_UNSUPPORTED_SOURCE' ||
83
+ code === 'ERR_UNSUPPORTED_FORMAT' ||
84
+ code === 'ERR_NATIVE_MODULE_UNAVAILABLE' ||
85
+ code === 'ERR_NOT_IMPLEMENTED' ||
86
+ code === 'ERR_FILE_ACCESS' ||
87
+ code === 'ERR_DECODE_FAILED' ||
88
+ code === 'ERR_ENCODE_FAILED' ||
89
+ code === 'ERR_NATIVE_OPERATION_FAILED'
90
+ );
91
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ export {
2
+ compressImage,
3
+ getImageCompressionCapabilities,
4
+ } from './api';
5
+ export { ImageCompressionKitError } from './errors';
6
+ export {
7
+ IMAGE_FORMATS,
8
+ METADATA_POLICIES,
9
+ OUTPUT_FORMATS,
10
+ RESIZE_MODES,
11
+ } from './types';
12
+ export type {
13
+ CompressionOptions,
14
+ CompressionResult,
15
+ CompressionSource,
16
+ FormatCapability,
17
+ ImageCompressionCapabilities,
18
+ ImageFormat,
19
+ MetadataPolicy,
20
+ NormalizedCompressionOptions,
21
+ OutputFormat,
22
+ OutputOptions,
23
+ ResizeMode,
24
+ ResizeOptions,
25
+ } from './types';
@@ -0,0 +1,130 @@
1
+ import { ImageCompressionKitError } from './errors';
2
+ import type { Spec as NativeImageCompressionKitSpec } from './NativeImageCompressionKit';
3
+ import type {
4
+ CompressionResult,
5
+ ImageCompressionCapabilities,
6
+ NormalizedCompressionOptions,
7
+ } from './types';
8
+
9
+ export const NATIVE_MODULE_NAME = 'ImageCompressionKit';
10
+
11
+ export type NativeImageCompressionKitModule = NativeImageCompressionKitSpec;
12
+
13
+ type NativeModuleContractCheck = {
14
+ compressImage(
15
+ options: NormalizedCompressionOptions
16
+ ): Promise<CompressionResult>;
17
+ getImageCompressionCapabilities(): Promise<ImageCompressionCapabilities>;
18
+ };
19
+
20
+ const _nativeModuleContractCheck: NativeImageCompressionKitModule extends NativeModuleContractCheck
21
+ ? true
22
+ : never = true;
23
+
24
+ type ReactNativeRuntime = {
25
+ NativeModules?: Record<string, unknown>;
26
+ TurboModuleRegistry?: {
27
+ get?: <T>(name: string) => T | null;
28
+ };
29
+ };
30
+
31
+ declare const require: ((moduleName: string) => unknown) | undefined;
32
+
33
+ let testNativeModule: NativeImageCompressionKitModule | null | undefined;
34
+
35
+ export function getNativeModule(): NativeImageCompressionKitModule {
36
+ const nativeModule =
37
+ testNativeModule !== undefined
38
+ ? testNativeModule
39
+ : resolveNativeModuleFromReactNative();
40
+
41
+ if (nativeModule) {
42
+ return nativeModule;
43
+ }
44
+
45
+ throw new ImageCompressionKitError(
46
+ 'ERR_NATIVE_MODULE_UNAVAILABLE',
47
+ `Native module ${NATIVE_MODULE_NAME} is unavailable. The TypeScript API is scaffolded, but Android and iOS implementations have not been added yet.`
48
+ );
49
+ }
50
+
51
+ export function setNativeModuleForTesting(
52
+ nativeModule: NativeImageCompressionKitModule | null
53
+ ): void {
54
+ testNativeModule = nativeModule;
55
+ }
56
+
57
+ export function resetNativeModuleForTesting(): void {
58
+ testNativeModule = undefined;
59
+ }
60
+
61
+ function resolveNativeModuleFromReactNative():
62
+ | NativeImageCompressionKitModule
63
+ | null {
64
+ const codegenModule = resolveNativeModuleFromCodegenSpec();
65
+
66
+ if (codegenModule) {
67
+ return codegenModule;
68
+ }
69
+
70
+ const reactNative = loadReactNativeRuntime();
71
+
72
+ const turboModule = reactNative?.TurboModuleRegistry?.get?.<
73
+ NativeImageCompressionKitModule
74
+ >(NATIVE_MODULE_NAME);
75
+
76
+ if (isNativeModule(turboModule)) {
77
+ return turboModule;
78
+ }
79
+
80
+ const legacyModule = reactNative?.NativeModules?.[NATIVE_MODULE_NAME];
81
+
82
+ if (isNativeModule(legacyModule)) {
83
+ return legacyModule;
84
+ }
85
+
86
+ return null;
87
+ }
88
+
89
+ function resolveNativeModuleFromCodegenSpec():
90
+ | NativeImageCompressionKitModule
91
+ | null {
92
+ if (typeof require !== 'function') {
93
+ return null;
94
+ }
95
+
96
+ try {
97
+ const codegenSpec = require('./NativeImageCompressionKit') as {
98
+ default?: unknown;
99
+ };
100
+
101
+ return isNativeModule(codegenSpec.default) ? codegenSpec.default : null;
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+
107
+ function loadReactNativeRuntime(): ReactNativeRuntime | null {
108
+ if (typeof require !== 'function') {
109
+ return null;
110
+ }
111
+
112
+ try {
113
+ return require('react-native') as ReactNativeRuntime;
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+
119
+ function isNativeModule(
120
+ value: unknown
121
+ ): value is NativeImageCompressionKitModule {
122
+ return (
123
+ typeof value === 'object' &&
124
+ value !== null &&
125
+ typeof (value as NativeImageCompressionKitModule).compressImage ===
126
+ 'function' &&
127
+ typeof (value as NativeImageCompressionKitModule)
128
+ .getImageCompressionCapabilities === 'function'
129
+ );
130
+ }
package/src/types.ts ADDED
@@ -0,0 +1,88 @@
1
+ export const IMAGE_FORMATS = [
2
+ 'jpeg',
3
+ 'png',
4
+ 'webp',
5
+ 'heic',
6
+ 'heif',
7
+ 'avif',
8
+ 'gif',
9
+ ] as const;
10
+
11
+ export const OUTPUT_FORMATS = [
12
+ 'jpeg',
13
+ 'png',
14
+ 'webp',
15
+ 'heic',
16
+ 'heif',
17
+ 'avif',
18
+ ] as const;
19
+
20
+ export const METADATA_POLICIES = ['preserve', 'safe', 'strip'] as const;
21
+
22
+ export const RESIZE_MODES = ['contain', 'cover', 'stretch'] as const;
23
+
24
+ export type ImageFormat = (typeof IMAGE_FORMATS)[number];
25
+ export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
26
+ export type MetadataPolicy = (typeof METADATA_POLICIES)[number];
27
+ export type ResizeMode = (typeof RESIZE_MODES)[number];
28
+
29
+ export interface CompressionSource {
30
+ uri: string;
31
+ }
32
+
33
+ export interface ResizeOptions {
34
+ maxWidth?: number;
35
+ maxHeight?: number;
36
+ mode?: ResizeMode;
37
+ }
38
+
39
+ export interface OutputOptions {
40
+ format: OutputFormat;
41
+ quality?: number;
42
+ maxBytes?: number;
43
+ }
44
+
45
+ export interface CompressionOptions {
46
+ source: CompressionSource;
47
+ resize?: ResizeOptions;
48
+ output: OutputOptions;
49
+ metadata?: MetadataPolicy;
50
+ }
51
+
52
+ export interface NormalizedResizeOptions
53
+ extends Omit<ResizeOptions, 'mode'> {
54
+ mode: ResizeMode;
55
+ }
56
+
57
+ export interface NormalizedCompressionOptions
58
+ extends Omit<CompressionOptions, 'metadata' | 'resize'> {
59
+ metadata: MetadataPolicy;
60
+ resize?: NormalizedResizeOptions;
61
+ }
62
+
63
+ export interface CompressionResult {
64
+ uri: string;
65
+ format: OutputFormat;
66
+ width: number;
67
+ height: number;
68
+ byteSize: number;
69
+ originalByteSize: number;
70
+ compressionRatio: number;
71
+ }
72
+
73
+ export interface FormatCapability {
74
+ format: ImageFormat;
75
+ input: boolean;
76
+ output: boolean;
77
+ supportsAlpha: boolean;
78
+ supportsAnimation: boolean;
79
+ notes?: string[];
80
+ }
81
+
82
+ export interface ImageCompressionCapabilities {
83
+ platform: 'android' | 'ios' | 'unknown';
84
+ formats: FormatCapability[];
85
+ metadataPolicies: MetadataPolicy[];
86
+ supportsTargetSizeCompression: boolean;
87
+ supportsCancellation: boolean;
88
+ }