@symbiote-native/image-manipulator 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.
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/build/angular/index.d.ts +2 -0
- package/build/angular/index.js +2 -0
- package/build/angular/inject-image-manipulator.d.ts +3 -0
- package/build/angular/inject-image-manipulator.js +8 -0
- package/build/core/image-manipulator.d.ts +10 -0
- package/build/core/image-manipulator.js +34 -0
- package/build/core/index.d.ts +4 -0
- package/build/core/index.js +2 -0
- package/build/core/manipulator-context-controller.d.ts +9 -0
- package/build/core/manipulator-context-controller.js +13 -0
- package/build/core/manipulator-resource-controller.d.ts +6 -0
- package/build/core/manipulator-resource-controller.js +17 -0
- package/build/core/native-module.d.ts +27 -0
- package/build/core/native-module.js +3 -0
- package/build/core/types.d.ts +47 -0
- package/build/core/types.js +11 -0
- package/build/core/validators.d.ts +5 -0
- package/build/core/validators.js +92 -0
- package/build/react/index.d.ts +2 -0
- package/build/react/index.js +2 -0
- package/build/react/use-image-manipulator.d.ts +3 -0
- package/build/react/use-image-manipulator.js +7 -0
- package/build/solid/index.d.ts +2 -0
- package/build/solid/index.js +2 -0
- package/build/solid/use-image-manipulator.d.ts +4 -0
- package/build/solid/use-image-manipulator.js +7 -0
- package/build/svelte/index.d.ts +2 -0
- package/build/svelte/index.js +2 -0
- package/build/svelte/use-image-manipulator.svelte.d.ts +5 -0
- package/build/svelte/use-image-manipulator.svelte.js +7 -0
- package/build/vue/index.d.ts +2 -0
- package/build/vue/index.js +2 -0
- package/build/vue/use-image-manipulator.d.ts +4 -0
- package/build/vue/use-image-manipulator.js +8 -0
- package/build-ngc/angular/index.d.ts +2 -0
- package/build-ngc/angular/index.js +3 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/angular/inject-image-manipulator.d.ts +3 -0
- package/build-ngc/angular/inject-image-manipulator.js +9 -0
- package/build-ngc/angular/inject-image-manipulator.js.map +1 -0
- package/build-ngc/core/image-manipulator.d.ts +10 -0
- package/build-ngc/core/image-manipulator.js +35 -0
- package/build-ngc/core/image-manipulator.js.map +1 -0
- package/build-ngc/core/index.d.ts +4 -0
- package/build-ngc/core/index.js +3 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/manipulator-context-controller.d.ts +9 -0
- package/build-ngc/core/manipulator-context-controller.js +14 -0
- package/build-ngc/core/manipulator-context-controller.js.map +1 -0
- package/build-ngc/core/manipulator-resource-controller.d.ts +6 -0
- package/build-ngc/core/manipulator-resource-controller.js +18 -0
- package/build-ngc/core/manipulator-resource-controller.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +27 -0
- package/build-ngc/core/native-module.js +4 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/types.d.ts +47 -0
- package/build-ngc/core/types.js +12 -0
- package/build-ngc/core/types.js.map +1 -0
- package/build-ngc/core/validators.d.ts +5 -0
- package/build-ngc/core/validators.js +93 -0
- package/build-ngc/core/validators.js.map +1 -0
- package/native-link.json +12 -0
- package/package.json +151 -0
- package/src/angular/index.ts +2 -0
- package/src/angular/inject-image-manipulator.ts +17 -0
- package/src/core/image-manipulator.ts +51 -0
- package/src/core/index.ts +12 -0
- package/src/core/manipulator-context-controller.ts +34 -0
- package/src/core/manipulator-resource-controller.ts +40 -0
- package/src/core/native-module.ts +40 -0
- package/src/core/types.ts +47 -0
- package/src/core/validators.ts +128 -0
- package/src/react/index.ts +2 -0
- package/src/react/use-image-manipulator.ts +14 -0
- package/src/solid/index.ts +2 -0
- package/src/solid/use-image-manipulator.ts +15 -0
- package/src/svelte/index.ts +2 -0
- package/src/svelte/svelte-ambient.d.ts +3 -0
- package/src/svelte/svelte-compile.test-helper.ts +7 -0
- package/src/svelte/use-image-manipulator.svelte.ts +19 -0
- package/src/vue/index.ts +2 -0
- package/src/vue/use-image-manipulator.ts +19 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expoImageManipulator } from './native-module';
|
|
2
|
+
import { SaveFormat } from './types';
|
|
3
|
+
import { validateArguments } from './validators';
|
|
4
|
+
/** Loads `source` and starts a new chainable manipulation context. */
|
|
5
|
+
export function manipulate(source) {
|
|
6
|
+
return expoImageManipulator.manipulate(source);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated replaced by `manipulate(source)` / the returned context's chainable methods.
|
|
10
|
+
*/
|
|
11
|
+
export async function manipulateAsync(uri, actions = [], saveOptions = {}) {
|
|
12
|
+
validateArguments(uri, actions, saveOptions);
|
|
13
|
+
const { format = SaveFormat.JPEG, ...rest } = saveOptions;
|
|
14
|
+
const context = expoImageManipulator.manipulate(uri);
|
|
15
|
+
for (const action of actions) {
|
|
16
|
+
if ('resize' in action) {
|
|
17
|
+
context.resize(action.resize);
|
|
18
|
+
}
|
|
19
|
+
else if ('rotate' in action) {
|
|
20
|
+
context.rotate(action.rotate);
|
|
21
|
+
}
|
|
22
|
+
else if ('flip' in action) {
|
|
23
|
+
context.flip(action.flip);
|
|
24
|
+
}
|
|
25
|
+
else if ('crop' in action) {
|
|
26
|
+
context.crop(action.crop);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const image = await context.renderAsync();
|
|
30
|
+
const result = await image.saveAsync({ format, ...rest });
|
|
31
|
+
context.release();
|
|
32
|
+
image.release();
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=image-manipulator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-manipulator.js","sourceRoot":"","sources":["../../src/core/image-manipulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAUjD,sEAAsE;AACtE,MAAM,UAAU,UAAU,CACxB,MAA+B;IAE/B,OAAO,oBAAoB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAW,EACX,UAAqB,EAAE,EACvB,cAA4B,EAAE;IAE9B,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAE7C,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,WAAW,CAAC;IAC1D,MAAM,OAAO,GAAG,oBAAoB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAErD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;aAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAE1D,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,KAAK,CAAC,OAAO,EAAE,CAAC;IAEhB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { manipulate, manipulateAsync } from './image-manipulator';
|
|
2
|
+
export type { IImageManipulatorContext, IImageRef } from './image-manipulator';
|
|
3
|
+
export { FlipType, SaveFormat } from './types';
|
|
4
|
+
export type { IAction, IActionCrop, IActionFlip, IActionResize, IActionRotate, IImageResult, ISaveOptions, } from './types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type IReleasableContext = {
|
|
2
|
+
release: () => void;
|
|
3
|
+
};
|
|
4
|
+
export type IManipulatorContextController<TSource, TContext extends IReleasableContext> = {
|
|
5
|
+
resolve: (source: TSource) => TContext;
|
|
6
|
+
flushRelease: () => void;
|
|
7
|
+
release: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function createManipulatorContextController<TSource, TContext extends IReleasableContext>(manipulate: (source: TSource) => TContext): IManipulatorContextController<TSource, TContext>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Thin binding of `@symbiote-native/engine`'s generic `createResourceController` to this
|
|
2
|
+
// package's own `.release()`-shaped context, kept for its own descriptive type names
|
|
3
|
+
import { createResourceController } from '@symbiote-native/engine';
|
|
4
|
+
export function createManipulatorContextController(manipulate) {
|
|
5
|
+
const controller = createResourceController(manipulate, context => {
|
|
6
|
+
context.release();
|
|
7
|
+
});
|
|
8
|
+
return {
|
|
9
|
+
resolve: controller.resolve,
|
|
10
|
+
flushRelease: controller.flushDispose,
|
|
11
|
+
release: controller.dispose,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=manipulator-context-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manipulator-context-controller.js","sourceRoot":"","sources":["../../src/core/manipulator-context-controller.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,qFAAqF;AAErF,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAanE,MAAM,UAAU,kCAAkC,CAIhD,UAAyC;IAEzC,MAAM,UAAU,GAAG,wBAAwB,CACzC,UAAU,EACV,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC,CACF,CAAC;IACF,OAAO;QACL,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,OAAO,EAAE,UAAU,CAAC,OAAO;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Adapts `createManipulatorContextController`'s `.release()`-shaped controller to the
|
|
2
|
+
// `resolve`/`flushDispose`/`dispose` shape every adapter's `createResourceHook` expects
|
|
3
|
+
import { createManipulatorContextController, } from './manipulator-context-controller';
|
|
4
|
+
import { manipulate } from './index';
|
|
5
|
+
function createManipulatorResourceController(manipulateSource) {
|
|
6
|
+
const controller = createManipulatorContextController(manipulateSource);
|
|
7
|
+
return {
|
|
8
|
+
resolve: controller.resolve,
|
|
9
|
+
flushDispose: controller.flushRelease,
|
|
10
|
+
dispose: controller.release,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
// Bakes in this package's own `manipulate`, so every adapter's `createResourceHook` binds a
|
|
14
|
+
// plain zero-arg factory instead of repeating the same arrow wrapper five times
|
|
15
|
+
export function createImageManipulatorResourceController() {
|
|
16
|
+
return createManipulatorResourceController(manipulate);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=manipulator-resource-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manipulator-resource-controller.js","sourceRoot":"","sources":["../../src/core/manipulator-resource-controller.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,wFAAwF;AAExF,OAAO,EACL,kCAAkC,GAEnC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,SAAS,mCAAmC,CAI1C,gBAA+C;IAM/C,MAAM,UAAU,GAAG,kCAAkC,CAAC,gBAAgB,CAAC,CAAC;IACxE,OAAO;QACL,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,OAAO,EAAE,UAAU,CAAC,OAAO;KAC5B,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,gFAAgF;AAChF,MAAM,UAAU,wCAAwC;IAKtD,OAAO,mCAAmC,CAGxC,UAAU,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SharedObject, SharedRef } from 'expo-modules-core';
|
|
2
|
+
import type { IImageResult, ISaveOptions } from './types';
|
|
3
|
+
export declare class NativeImageRef extends SharedRef<'image'> {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
saveAsync(options?: ISaveOptions): Promise<IImageResult>;
|
|
7
|
+
}
|
|
8
|
+
export declare class NativeImageManipulatorContext extends SharedObject {
|
|
9
|
+
resize(size: {
|
|
10
|
+
width?: number | null;
|
|
11
|
+
height?: number | null;
|
|
12
|
+
}): NativeImageManipulatorContext;
|
|
13
|
+
rotate(degrees: number): NativeImageManipulatorContext;
|
|
14
|
+
flip(flipType: 'vertical' | 'horizontal'): NativeImageManipulatorContext;
|
|
15
|
+
crop(rect: {
|
|
16
|
+
originX: number;
|
|
17
|
+
originY: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}): NativeImageManipulatorContext;
|
|
21
|
+
reset(): NativeImageManipulatorContext;
|
|
22
|
+
renderAsync(): Promise<NativeImageRef>;
|
|
23
|
+
}
|
|
24
|
+
export type INativeImageManipulatorModule = {
|
|
25
|
+
manipulate(source: string | NativeImageRef): NativeImageManipulatorContext;
|
|
26
|
+
};
|
|
27
|
+
export declare const expoImageManipulator: INativeImageManipulatorModule;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { requireNativeModule, SharedObject, SharedRef, } from 'expo-modules-core';
|
|
2
|
+
const EXPO_IMAGE_MANIPULATOR_MODULE_NAME = 'ExpoImageManipulator';
|
|
3
|
+
export const expoImageManipulator = requireNativeModule(EXPO_IMAGE_MANIPULATOR_MODULE_NAME);
|
|
4
|
+
//# sourceMappingURL=native-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,SAAS,GACV,MAAM,mBAAmB,CAAC;AAG3B,MAAM,kCAAkC,GAAG,sBAAsB,CAAC;AA6BlE,MAAM,CAAC,MAAM,oBAAoB,GAC/B,mBAAmB,CACjB,kCAAkC,CACnC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export declare enum FlipType {
|
|
2
|
+
Vertical = "vertical",
|
|
3
|
+
Horizontal = "horizontal"
|
|
4
|
+
}
|
|
5
|
+
export declare enum SaveFormat {
|
|
6
|
+
JPEG = "jpeg",
|
|
7
|
+
PNG = "png",
|
|
8
|
+
WEBP = "webp"
|
|
9
|
+
}
|
|
10
|
+
export type IActionResize = {
|
|
11
|
+
/** Provide only one of `width`/`height` to preserve the image's ratio. */
|
|
12
|
+
resize: {
|
|
13
|
+
width?: number;
|
|
14
|
+
height?: number;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export type IActionRotate = {
|
|
18
|
+
/** Degrees, clockwise when positive, counter-clockwise when negative. */
|
|
19
|
+
rotate: number;
|
|
20
|
+
};
|
|
21
|
+
export type IActionFlip = {
|
|
22
|
+
flip: FlipType;
|
|
23
|
+
};
|
|
24
|
+
export type IActionCrop = {
|
|
25
|
+
crop: {
|
|
26
|
+
originX: number;
|
|
27
|
+
originY: number;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/** @deprecated use `manipulate(source)` instead. */
|
|
33
|
+
export type IAction = IActionResize | IActionRotate | IActionFlip | IActionCrop;
|
|
34
|
+
export type ISaveOptions = {
|
|
35
|
+
base64?: boolean;
|
|
36
|
+
/** `0.0`-`1.0`; `1` is no compression (highest quality). Default `1`. */
|
|
37
|
+
compress?: number;
|
|
38
|
+
/** Default `SaveFormat.JPEG`. */
|
|
39
|
+
format?: SaveFormat;
|
|
40
|
+
};
|
|
41
|
+
export type IImageResult = {
|
|
42
|
+
uri: string;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
/** Set only when `base64` was truthy in `ISaveOptions`. */
|
|
46
|
+
base64?: string;
|
|
47
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export var FlipType;
|
|
2
|
+
(function (FlipType) {
|
|
3
|
+
FlipType["Vertical"] = "vertical";
|
|
4
|
+
FlipType["Horizontal"] = "horizontal";
|
|
5
|
+
})(FlipType || (FlipType = {}));
|
|
6
|
+
export var SaveFormat;
|
|
7
|
+
(function (SaveFormat) {
|
|
8
|
+
SaveFormat["JPEG"] = "jpeg";
|
|
9
|
+
SaveFormat["PNG"] = "png";
|
|
10
|
+
SaveFormat["WEBP"] = "webp";
|
|
11
|
+
})(SaveFormat || (SaveFormat = {}));
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,QAGX;AAHD,WAAY,QAAQ;IAClB,iCAAqB,CAAA;IACrB,qCAAyB,CAAA;AAC3B,CAAC,EAHW,QAAQ,KAAR,QAAQ,QAGnB;AAED,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,2BAAa,CAAA;IACb,yBAAW,CAAA;IACX,2BAAa,CAAA;AACf,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IAction, ISaveOptions } from './types';
|
|
2
|
+
export declare function validateArguments(uri: string, actions: IAction[], saveOptions: ISaveOptions): void;
|
|
3
|
+
export declare function validateUri(uri: string): void;
|
|
4
|
+
export declare function validateActions(actions: IAction[]): void;
|
|
5
|
+
export declare function validateSaveOptions({ base64, compress, format, }: ISaveOptions): void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { FlipType, SaveFormat } from './types';
|
|
2
|
+
const SUPPORTED_ACTION_TYPES = ['crop', 'flip', 'rotate', 'resize'];
|
|
3
|
+
export function validateArguments(uri, actions, saveOptions) {
|
|
4
|
+
validateUri(uri);
|
|
5
|
+
validateActions(actions);
|
|
6
|
+
validateSaveOptions(saveOptions);
|
|
7
|
+
}
|
|
8
|
+
export function validateUri(uri) {
|
|
9
|
+
if (typeof uri !== 'string') {
|
|
10
|
+
throw new TypeError('The "uri" argument must be a string');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function validateActions(actions) {
|
|
14
|
+
if (!Array.isArray(actions)) {
|
|
15
|
+
throw new TypeError('The "actions" argument must be an array');
|
|
16
|
+
}
|
|
17
|
+
for (const action of actions) {
|
|
18
|
+
if (typeof action !== 'object' || action === null) {
|
|
19
|
+
throw new TypeError('Action must be an object');
|
|
20
|
+
}
|
|
21
|
+
const actionKeys = Object.keys(action);
|
|
22
|
+
if (actionKeys.length !== 1) {
|
|
23
|
+
throw new TypeError(`Single action must contain exactly one transformation: ${SUPPORTED_ACTION_TYPES.join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
const actionType = actionKeys[0];
|
|
26
|
+
if (!SUPPORTED_ACTION_TYPES.includes(actionType)) {
|
|
27
|
+
throw new TypeError(`Unsupported action type: ${actionType}`);
|
|
28
|
+
}
|
|
29
|
+
if ('crop' in action) {
|
|
30
|
+
validateCropAction(action);
|
|
31
|
+
}
|
|
32
|
+
else if ('flip' in action) {
|
|
33
|
+
validateFlipAction(action);
|
|
34
|
+
}
|
|
35
|
+
else if ('rotate' in action) {
|
|
36
|
+
validateRotateAction(action);
|
|
37
|
+
}
|
|
38
|
+
else if ('resize' in action) {
|
|
39
|
+
validateResizeAction(action);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function validateCropAction(action) {
|
|
44
|
+
const isValid = typeof action.crop === 'object' &&
|
|
45
|
+
action.crop !== null &&
|
|
46
|
+
typeof action.crop.originX === 'number' &&
|
|
47
|
+
typeof action.crop.originY === 'number' &&
|
|
48
|
+
typeof action.crop.width === 'number' &&
|
|
49
|
+
typeof action.crop.height === 'number';
|
|
50
|
+
if (!isValid) {
|
|
51
|
+
throw new TypeError('Crop action must be an object of shape { originX: number; originY: number; width: number; height: number }');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function validateFlipAction(action) {
|
|
55
|
+
if (typeof action.flip !== 'string' ||
|
|
56
|
+
![FlipType.Horizontal, FlipType.Vertical].includes(action.flip)) {
|
|
57
|
+
throw new TypeError(`Unsupported flip type: ${action.flip}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function validateRotateAction(action) {
|
|
61
|
+
if (typeof action.rotate !== 'number') {
|
|
62
|
+
throw new TypeError('Rotation must be a number');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function validateResizeAction(action) {
|
|
66
|
+
const isValid = typeof action.resize === 'object' &&
|
|
67
|
+
action.resize !== null &&
|
|
68
|
+
(typeof action.resize.width === 'number' ||
|
|
69
|
+
action.resize.width === undefined) &&
|
|
70
|
+
(typeof action.resize.height === 'number' ||
|
|
71
|
+
action.resize.height === undefined);
|
|
72
|
+
if (!isValid) {
|
|
73
|
+
throw new TypeError('Resize action must be an object of shape { width?: number; height?: number }');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function validateSaveOptions({ base64, compress, format, }) {
|
|
77
|
+
if (base64 !== undefined && typeof base64 !== 'boolean') {
|
|
78
|
+
throw new TypeError('The "base64" argument must be a boolean');
|
|
79
|
+
}
|
|
80
|
+
if (compress !== undefined) {
|
|
81
|
+
if (typeof compress !== 'number') {
|
|
82
|
+
throw new TypeError('The "compress" argument must be a number');
|
|
83
|
+
}
|
|
84
|
+
if (compress < 0 || compress > 1) {
|
|
85
|
+
throw new TypeError('The "compress" argument must be a number between 0 and 1');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const allowedFormats = [SaveFormat.JPEG, SaveFormat.PNG, SaveFormat.WEBP];
|
|
89
|
+
if (format !== undefined && !allowedFormats.includes(format)) {
|
|
90
|
+
throw new TypeError(`The "format" argument must be one of: ${allowedFormats.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/core/validators.ts"],"names":[],"mappings":"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"}
|
package/native-link.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@symbiote-native/image-manipulator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "expo-image-manipulator wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Resizes, rotates, flips and crops images, rendering to a new file.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"react-native",
|
|
8
|
+
"symbiote-native",
|
|
9
|
+
"expo-image-manipulator",
|
|
10
|
+
"react",
|
|
11
|
+
"vue",
|
|
12
|
+
"svelte",
|
|
13
|
+
"solid",
|
|
14
|
+
"angular",
|
|
15
|
+
"image",
|
|
16
|
+
"crop",
|
|
17
|
+
"resize"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/OneEyed1366/symbiote-native.git",
|
|
22
|
+
"directory": "packages/image-manipulator"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/OneEyed1366/symbiote-native/tree/master/packages/image-manipulator#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/OneEyed1366/symbiote-native/issues"
|
|
27
|
+
},
|
|
28
|
+
"author": "Andrey Prokopenko <psevdoproger@gmail.com>",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./build/core/index.js",
|
|
31
|
+
"module": "./build/core/index.js",
|
|
32
|
+
"types": "./build/core/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./build/core/index.d.ts",
|
|
36
|
+
"default": "./build/core/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./vue": {
|
|
39
|
+
"types": "./build/vue/index.d.ts",
|
|
40
|
+
"default": "./build/vue/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"types": "./build/react/index.d.ts",
|
|
44
|
+
"default": "./build/react/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./svelte": {
|
|
47
|
+
"types": "./build/svelte/index.d.ts",
|
|
48
|
+
"default": "./build/svelte/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./solid": {
|
|
51
|
+
"types": "./build/solid/index.d.ts",
|
|
52
|
+
"default": "./build/solid/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./angular": {
|
|
55
|
+
"types": "./build-ngc/angular/index.d.ts",
|
|
56
|
+
"react-native": "./build-ngc/angular/index.js",
|
|
57
|
+
"default": "./src/angular/index.ts"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"files": [
|
|
61
|
+
"src",
|
|
62
|
+
"build",
|
|
63
|
+
"build-ngc",
|
|
64
|
+
"native-link.json",
|
|
65
|
+
"!src/**/*.test.*",
|
|
66
|
+
"!src/**/*.spec.*",
|
|
67
|
+
"!src/**/*.detox.*"
|
|
68
|
+
],
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"expo-image-manipulator": "57.0.20",
|
|
74
|
+
"expo-modules-core": "57.0.20"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@angular/core": ">=20",
|
|
78
|
+
"@vue/runtime-core": "^3.5.13",
|
|
79
|
+
"react": ">=19.0.0",
|
|
80
|
+
"react-native": ">=0.86",
|
|
81
|
+
"solid-js": ">=1.9.0",
|
|
82
|
+
"svelte": ">=5.56.0",
|
|
83
|
+
"vue": ">=3.5.0",
|
|
84
|
+
"@symbiote-native/engine": "^1.4.0",
|
|
85
|
+
"@symbiote-native/react": "^3.1.0",
|
|
86
|
+
"@symbiote-native/angular": "^3.1.3",
|
|
87
|
+
"@symbiote-native/solid": "^3.0.5",
|
|
88
|
+
"@symbiote-native/svelte": "^3.0.5",
|
|
89
|
+
"@symbiote-native/vue": "^3.1.0"
|
|
90
|
+
},
|
|
91
|
+
"peerDependenciesMeta": {
|
|
92
|
+
"@symbiote-native/angular": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"@symbiote-native/react": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@symbiote-native/solid": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@symbiote-native/svelte": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@symbiote-native/vue": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@angular/core": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"@vue/runtime-core": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
113
|
+
"react": {
|
|
114
|
+
"optional": true
|
|
115
|
+
},
|
|
116
|
+
"solid-js": {
|
|
117
|
+
"optional": true
|
|
118
|
+
},
|
|
119
|
+
"svelte": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
122
|
+
"vue": {
|
|
123
|
+
"optional": true
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"devDependencies": {
|
|
127
|
+
"@angular/compiler": "~22.0.8",
|
|
128
|
+
"@angular/compiler-cli": "~22.0.8",
|
|
129
|
+
"@angular/core": "~22.0.8",
|
|
130
|
+
"@types/node": "^26.0.0",
|
|
131
|
+
"@types/react": "^19.2.0",
|
|
132
|
+
"@vue/runtime-core": "^3.5.13",
|
|
133
|
+
"react": "19.2.3",
|
|
134
|
+
"solid-js": "^1.9.14",
|
|
135
|
+
"svelte": "^5.56.0",
|
|
136
|
+
"typescript": "~6.0.0",
|
|
137
|
+
"@symbiote-native/engine": "1.4.0",
|
|
138
|
+
"@symbiote-native/angular": "3.1.3",
|
|
139
|
+
"@symbiote-native/react": "3.1.0",
|
|
140
|
+
"@symbiote-native/svelte": "3.0.5",
|
|
141
|
+
"@symbiote-native/vue": "3.1.0",
|
|
142
|
+
"@symbiote-native/solid": "3.0.5",
|
|
143
|
+
"@symbiote-native/test-utils": "0.4.5"
|
|
144
|
+
},
|
|
145
|
+
"scripts": {
|
|
146
|
+
"typecheck": "tsc --build",
|
|
147
|
+
"clean": "rm -rf build-ngc",
|
|
148
|
+
"ng:build": "pnpm run clean && ngc -p tsconfig.angular.json",
|
|
149
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Angular twin of `useImageManipulator`, `injectX` shape matching
|
|
2
|
+
// `@symbiote-native/navigation`'s `injectLinkingIntegration`
|
|
3
|
+
|
|
4
|
+
import type { Signal } from '@angular/core';
|
|
5
|
+
import { createResourceHook } from '@symbiote-native/angular';
|
|
6
|
+
import type { IImageManipulatorContext, IImageRef } from '../core';
|
|
7
|
+
import { createImageManipulatorResourceController } from '../core/manipulator-resource-controller';
|
|
8
|
+
|
|
9
|
+
const injectManipulatorResource = createResourceHook(
|
|
10
|
+
createImageManipulatorResourceController,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export function injectImageManipulator(
|
|
14
|
+
source: () => string | IImageRef,
|
|
15
|
+
): Signal<IImageManipulatorContext> {
|
|
16
|
+
return injectManipulatorResource(() => [source()]);
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { expoImageManipulator } from './native-module';
|
|
2
|
+
import { SaveFormat } from './types';
|
|
3
|
+
import { validateArguments } from './validators';
|
|
4
|
+
import type {
|
|
5
|
+
NativeImageManipulatorContext,
|
|
6
|
+
NativeImageRef,
|
|
7
|
+
} from './native-module';
|
|
8
|
+
import type { IAction, IImageResult, ISaveOptions } from './types';
|
|
9
|
+
|
|
10
|
+
export type { NativeImageManipulatorContext as IImageManipulatorContext };
|
|
11
|
+
export type { NativeImageRef as IImageRef };
|
|
12
|
+
|
|
13
|
+
/** Loads `source` and starts a new chainable manipulation context. */
|
|
14
|
+
export function manipulate(
|
|
15
|
+
source: string | NativeImageRef,
|
|
16
|
+
): NativeImageManipulatorContext {
|
|
17
|
+
return expoImageManipulator.manipulate(source);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated replaced by `manipulate(source)` / the returned context's chainable methods.
|
|
22
|
+
*/
|
|
23
|
+
export async function manipulateAsync(
|
|
24
|
+
uri: string,
|
|
25
|
+
actions: IAction[] = [],
|
|
26
|
+
saveOptions: ISaveOptions = {},
|
|
27
|
+
): Promise<IImageResult> {
|
|
28
|
+
validateArguments(uri, actions, saveOptions);
|
|
29
|
+
|
|
30
|
+
const { format = SaveFormat.JPEG, ...rest } = saveOptions;
|
|
31
|
+
const context = expoImageManipulator.manipulate(uri);
|
|
32
|
+
|
|
33
|
+
for (const action of actions) {
|
|
34
|
+
if ('resize' in action) {
|
|
35
|
+
context.resize(action.resize);
|
|
36
|
+
} else if ('rotate' in action) {
|
|
37
|
+
context.rotate(action.rotate);
|
|
38
|
+
} else if ('flip' in action) {
|
|
39
|
+
context.flip(action.flip);
|
|
40
|
+
} else if ('crop' in action) {
|
|
41
|
+
context.crop(action.crop);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const image = await context.renderAsync();
|
|
45
|
+
const result = await image.saveAsync({ format, ...rest });
|
|
46
|
+
|
|
47
|
+
context.release();
|
|
48
|
+
image.release();
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { manipulate, manipulateAsync } from './image-manipulator';
|
|
2
|
+
export type { IImageManipulatorContext, IImageRef } from './image-manipulator';
|
|
3
|
+
export { FlipType, SaveFormat } from './types';
|
|
4
|
+
export type {
|
|
5
|
+
IAction,
|
|
6
|
+
IActionCrop,
|
|
7
|
+
IActionFlip,
|
|
8
|
+
IActionResize,
|
|
9
|
+
IActionRotate,
|
|
10
|
+
IImageResult,
|
|
11
|
+
ISaveOptions,
|
|
12
|
+
} from './types';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Thin binding of `@symbiote-native/engine`'s generic `createResourceController` to this
|
|
2
|
+
// package's own `.release()`-shaped context, kept for its own descriptive type names
|
|
3
|
+
|
|
4
|
+
import { createResourceController } from '@symbiote-native/engine';
|
|
5
|
+
|
|
6
|
+
export type IReleasableContext = { release: () => void };
|
|
7
|
+
|
|
8
|
+
export type IManipulatorContextController<
|
|
9
|
+
TSource,
|
|
10
|
+
TContext extends IReleasableContext,
|
|
11
|
+
> = {
|
|
12
|
+
resolve: (source: TSource) => TContext;
|
|
13
|
+
flushRelease: () => void;
|
|
14
|
+
release: () => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function createManipulatorContextController<
|
|
18
|
+
TSource,
|
|
19
|
+
TContext extends IReleasableContext,
|
|
20
|
+
>(
|
|
21
|
+
manipulate: (source: TSource) => TContext,
|
|
22
|
+
): IManipulatorContextController<TSource, TContext> {
|
|
23
|
+
const controller = createResourceController<TSource, TContext>(
|
|
24
|
+
manipulate,
|
|
25
|
+
context => {
|
|
26
|
+
context.release();
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
return {
|
|
30
|
+
resolve: controller.resolve,
|
|
31
|
+
flushRelease: controller.flushDispose,
|
|
32
|
+
release: controller.dispose,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Adapts `createManipulatorContextController`'s `.release()`-shaped controller to the
|
|
2
|
+
// `resolve`/`flushDispose`/`dispose` shape every adapter's `createResourceHook` expects
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createManipulatorContextController,
|
|
6
|
+
type IReleasableContext,
|
|
7
|
+
} from './manipulator-context-controller';
|
|
8
|
+
import { manipulate } from './index';
|
|
9
|
+
import type { IImageManipulatorContext, IImageRef } from './index';
|
|
10
|
+
|
|
11
|
+
function createManipulatorResourceController<
|
|
12
|
+
TSource,
|
|
13
|
+
TContext extends IReleasableContext,
|
|
14
|
+
>(
|
|
15
|
+
manipulateSource: (source: TSource) => TContext,
|
|
16
|
+
): {
|
|
17
|
+
resolve: (source: TSource) => TContext;
|
|
18
|
+
flushDispose: () => void;
|
|
19
|
+
dispose: () => void;
|
|
20
|
+
} {
|
|
21
|
+
const controller = createManipulatorContextController(manipulateSource);
|
|
22
|
+
return {
|
|
23
|
+
resolve: controller.resolve,
|
|
24
|
+
flushDispose: controller.flushRelease,
|
|
25
|
+
dispose: controller.release,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Bakes in this package's own `manipulate`, so every adapter's `createResourceHook` binds a
|
|
30
|
+
// plain zero-arg factory instead of repeating the same arrow wrapper five times
|
|
31
|
+
export function createImageManipulatorResourceController(): {
|
|
32
|
+
resolve: (source: string | IImageRef) => IImageManipulatorContext;
|
|
33
|
+
flushDispose: () => void;
|
|
34
|
+
dispose: () => void;
|
|
35
|
+
} {
|
|
36
|
+
return createManipulatorResourceController<
|
|
37
|
+
string | IImageRef,
|
|
38
|
+
IImageManipulatorContext
|
|
39
|
+
>(manipulate);
|
|
40
|
+
}
|