@technotoil/image-video-editor 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/ImageVideoEditor.podspec +21 -0
- package/README.md +136 -0
- package/android/build.gradle +76 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +13 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/FrameGrabberModule.kt +67 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaEditorModule.kt +548 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaFileUtils.kt +29 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaLibraryModule.kt +305 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaPackage.kt +26 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaPickerModule.kt +111 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/MediaPlayerModule.kt +34 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/RNCameraViewManager.kt +761 -0
- package/android/src/main/java/com/technotoil/image_videoeditor/RNVideoPreviewManager.kt +317 -0
- package/ios/PrivacyInfo.xcprivacy +38 -0
- package/ios/RNCameraViewManager.m +420 -0
- package/ios/RNFrameGrabber.m +61 -0
- package/ios/RNMediaEditor.m +905 -0
- package/ios/RNMediaLibrary.m +389 -0
- package/ios/RNMediaPicker.m +144 -0
- package/ios/RNMediaPlayer.m +73 -0
- package/ios/RNVideoPreviewManager.m +263 -0
- package/ios/frames/film_vintage.png +0 -0
- package/ios/frames/floral_gold.png +0 -0
- package/ios/frames/minimal_double.png +0 -0
- package/ios/frames/polaroid_white.png +0 -0
- package/ios/frames/watercolor_floral.png +0 -0
- package/lib/module/assets/frames/film_vintage.png +0 -0
- package/lib/module/assets/frames/floral_gold.png +0 -0
- package/lib/module/assets/frames/minimal_double.png +0 -0
- package/lib/module/assets/frames/polaroid_white.png +0 -0
- package/lib/module/assets/frames/watercolor_floral.png +0 -0
- package/lib/module/components/VideoEditor.js +156 -0
- package/lib/module/components/VideoEditor.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/CameraView.js +104 -0
- package/lib/module/native/CameraView.js.map +1 -0
- package/lib/module/native/FrameGrabber.js +13 -0
- package/lib/module/native/FrameGrabber.js.map +1 -0
- package/lib/module/native/MediaEditor.js +19 -0
- package/lib/module/native/MediaEditor.js.map +1 -0
- package/lib/module/native/MediaLibrary.js +37 -0
- package/lib/module/native/MediaLibrary.js.map +1 -0
- package/lib/module/native/MediaPicker.js +13 -0
- package/lib/module/native/MediaPicker.js.map +1 -0
- package/lib/module/native/MediaPlayer.js +13 -0
- package/lib/module/native/MediaPlayer.js.map +1 -0
- package/lib/module/native/VideoPreview.js +12 -0
- package/lib/module/native/VideoPreview.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/screens/CropScreen.js +1211 -0
- package/lib/module/screens/CropScreen.js.map +1 -0
- package/lib/module/screens/EditorScreen.js +5752 -0
- package/lib/module/screens/EditorScreen.js.map +1 -0
- package/lib/module/screens/ExportScreen.js +289 -0
- package/lib/module/screens/ExportScreen.js.map +1 -0
- package/lib/module/screens/GalleryScreen.js +505 -0
- package/lib/module/screens/GalleryScreen.js.map +1 -0
- package/lib/module/screens/PickScreen.js +1195 -0
- package/lib/module/screens/PickScreen.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/src/components/VideoEditor.d.ts +13 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/native/CameraView.d.ts +23 -0
- package/lib/typescript/src/native/FrameGrabber.d.ts +2 -0
- package/lib/typescript/src/native/MediaEditor.d.ts +3 -0
- package/lib/typescript/src/native/MediaLibrary.d.ts +16 -0
- package/lib/typescript/src/native/MediaPicker.d.ts +2 -0
- package/lib/typescript/src/native/MediaPlayer.d.ts +1 -0
- package/lib/typescript/src/native/VideoPreview.d.ts +19 -0
- package/lib/typescript/src/screens/CropScreen.d.ts +9 -0
- package/lib/typescript/src/screens/EditorScreen.d.ts +10 -0
- package/lib/typescript/src/screens/ExportScreen.d.ts +9 -0
- package/lib/typescript/src/screens/GalleryScreen.d.ts +8 -0
- package/lib/typescript/src/screens/PickScreen.d.ts +13 -0
- package/lib/typescript/src/types.d.ts +58 -0
- package/package.json +101 -0
- package/src/assets/frames/film_vintage.png +0 -0
- package/src/assets/frames/floral_gold.png +0 -0
- package/src/assets/frames/minimal_double.png +0 -0
- package/src/assets/frames/polaroid_white.png +0 -0
- package/src/assets/frames/watercolor_floral.png +0 -0
- package/src/components/VideoEditor.tsx +182 -0
- package/src/index.tsx +2 -0
- package/src/native/CameraView.tsx +95 -0
- package/src/native/FrameGrabber.ts +21 -0
- package/src/native/MediaEditor.ts +33 -0
- package/src/native/MediaLibrary.ts +69 -0
- package/src/native/MediaPicker.ts +17 -0
- package/src/native/MediaPlayer.ts +16 -0
- package/src/native/VideoPreview.tsx +20 -0
- package/src/screens/CropScreen.tsx +968 -0
- package/src/screens/EditorScreen.tsx +4517 -0
- package/src/screens/ExportScreen.tsx +282 -0
- package/src/screens/GalleryScreen.tsx +412 -0
- package/src/screens/PickScreen.tsx +1094 -0
- package/src/types.ts +58 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
|
|
2
|
+
import { requireNativeComponent, ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type NativeProps = {
|
|
5
|
+
facing: 'front' | 'back';
|
|
6
|
+
flashMode?: 'on' | 'off';
|
|
7
|
+
style?: ViewStyle;
|
|
8
|
+
photoTrigger?: string;
|
|
9
|
+
recordTrigger?: string;
|
|
10
|
+
onPhotoCaptured?: (event: any) => void;
|
|
11
|
+
onRecordStarted?: (event: any) => void;
|
|
12
|
+
onRecordStopped?: (event: any) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const NativeCameraView = requireNativeComponent<NativeProps>('RNCameraView');
|
|
16
|
+
|
|
17
|
+
export interface CameraViewRef {
|
|
18
|
+
capturePhoto(): Promise<{ uri: string; width: number; height: number }>;
|
|
19
|
+
startRecording(): Promise<void>;
|
|
20
|
+
stopRecording(): Promise<{ uri: string; durationMs: number; width: number; height: number }>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
facing: 'front' | 'back';
|
|
25
|
+
flashMode?: 'on' | 'off';
|
|
26
|
+
style?: ViewStyle;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const CameraView = forwardRef<CameraViewRef, Props>(({ facing, flashMode = 'off', style }, ref) => {
|
|
30
|
+
const [photoTrigger, setPhotoTrigger] = useState<string>('');
|
|
31
|
+
const [recordTrigger, setRecordTrigger] = useState<'start' | 'stop' | 'idle'>('idle');
|
|
32
|
+
|
|
33
|
+
const photoPromiseRef = useRef<{ resolve: Function; reject: Function } | null>(null);
|
|
34
|
+
const recordStartPromiseRef = useRef<{ resolve: Function; reject: Function } | null>(null);
|
|
35
|
+
const recordStopPromiseRef = useRef<{ resolve: Function; reject: Function } | null>(null);
|
|
36
|
+
|
|
37
|
+
useImperativeHandle(ref, () => ({
|
|
38
|
+
capturePhoto: () => {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
photoPromiseRef.current = { resolve, reject };
|
|
41
|
+
setPhotoTrigger(Date.now().toString());
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
startRecording: () => {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
recordStartPromiseRef.current = { resolve, reject };
|
|
47
|
+
setRecordTrigger('start');
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
stopRecording: () => {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
recordStopPromiseRef.current = { resolve, reject };
|
|
53
|
+
setRecordTrigger('stop');
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<NativeCameraView
|
|
60
|
+
facing={facing}
|
|
61
|
+
flashMode={flashMode}
|
|
62
|
+
style={style}
|
|
63
|
+
photoTrigger={photoTrigger}
|
|
64
|
+
recordTrigger={recordTrigger}
|
|
65
|
+
onPhotoCaptured={(e: any) => {
|
|
66
|
+
const { uri, width, height, error } = e.nativeEvent;
|
|
67
|
+
if (error) {
|
|
68
|
+
photoPromiseRef.current?.reject(new Error(error));
|
|
69
|
+
} else {
|
|
70
|
+
photoPromiseRef.current?.resolve({ uri, width, height });
|
|
71
|
+
}
|
|
72
|
+
photoPromiseRef.current = null;
|
|
73
|
+
}}
|
|
74
|
+
onRecordStarted={(e: any) => {
|
|
75
|
+
const { error } = e.nativeEvent;
|
|
76
|
+
if (error) {
|
|
77
|
+
recordStartPromiseRef.current?.reject(new Error(error));
|
|
78
|
+
} else {
|
|
79
|
+
recordStartPromiseRef.current?.resolve();
|
|
80
|
+
}
|
|
81
|
+
recordStartPromiseRef.current = null;
|
|
82
|
+
}}
|
|
83
|
+
onRecordStopped={(e: any) => {
|
|
84
|
+
const { uri, durationMs, width, height, error } = e.nativeEvent;
|
|
85
|
+
if (error) {
|
|
86
|
+
recordStopPromiseRef.current?.reject(new Error(error));
|
|
87
|
+
} else {
|
|
88
|
+
recordStopPromiseRef.current?.resolve({ uri, durationMs, width, height });
|
|
89
|
+
}
|
|
90
|
+
recordStopPromiseRef.current = null;
|
|
91
|
+
setRecordTrigger('idle');
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import type { FrameCaptureOptions } from '../types';
|
|
3
|
+
|
|
4
|
+
const { RNFrameGrabber } = NativeModules as {
|
|
5
|
+
RNFrameGrabber?: {
|
|
6
|
+
captureFrame: (uri: string, options: FrameCaptureOptions) => Promise<string>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export async function captureFrame(
|
|
11
|
+
uri: string,
|
|
12
|
+
options: FrameCaptureOptions
|
|
13
|
+
): Promise<string> {
|
|
14
|
+
if (!RNFrameGrabber?.captureFrame) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`RNFrameGrabber.captureFrame is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return RNFrameGrabber.captureFrame(uri, options);
|
|
20
|
+
}
|
|
21
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import type { ImageEditOptions, VideoTrimOptions } from '../types';
|
|
3
|
+
|
|
4
|
+
const { RNMediaEditor } = NativeModules as {
|
|
5
|
+
RNMediaEditor?: {
|
|
6
|
+
editImage: (uri: string, options: ImageEditOptions) => Promise<string>;
|
|
7
|
+
trimVideo: (uri: string, options: VideoTrimOptions) => Promise<string>;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export async function editImage(
|
|
12
|
+
uri: string,
|
|
13
|
+
options: ImageEditOptions
|
|
14
|
+
): Promise<string> {
|
|
15
|
+
if (!RNMediaEditor?.editImage) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`RNMediaEditor.editImage is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
return RNMediaEditor.editImage(uri, options);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function trimVideo(
|
|
24
|
+
uri: string,
|
|
25
|
+
options: VideoTrimOptions
|
|
26
|
+
): Promise<string> {
|
|
27
|
+
if (!RNMediaEditor?.trimVideo) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`RNMediaEditor.trimVideo is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return RNMediaEditor.trimVideo(uri, options);
|
|
33
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import type { MediaItem, MediaType } from '../types';
|
|
3
|
+
|
|
4
|
+
export type Album = {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type MediaQuery = {
|
|
10
|
+
limit?: number;
|
|
11
|
+
offset?: number;
|
|
12
|
+
type?: MediaType | 'all';
|
|
13
|
+
albumId?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const { RNMediaLibrary } = NativeModules as {
|
|
17
|
+
RNMediaLibrary?: {
|
|
18
|
+
requestAccess: () => Promise<boolean>;
|
|
19
|
+
listAlbums: () => Promise<Album[]>;
|
|
20
|
+
listMedia: (query: MediaQuery) => Promise<MediaItem[]>;
|
|
21
|
+
exportAsset: (localId: string) => Promise<string>;
|
|
22
|
+
saveToGallery: (uri: string, type: string) => Promise<boolean>;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export async function requestMediaAccess(): Promise<boolean> {
|
|
27
|
+
if (!RNMediaLibrary?.requestAccess) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`RNMediaLibrary is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return RNMediaLibrary.requestAccess();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function listAlbums(): Promise<Album[]> {
|
|
36
|
+
if (!RNMediaLibrary?.listAlbums) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`RNMediaLibrary.listAlbums is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return RNMediaLibrary.listAlbums();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function listMedia(query: MediaQuery): Promise<MediaItem[]> {
|
|
45
|
+
if (!RNMediaLibrary?.listMedia) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`RNMediaLibrary.listMedia is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return RNMediaLibrary.listMedia(query);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function exportAsset(localId: string): Promise<string> {
|
|
54
|
+
if (!RNMediaLibrary?.exportAsset) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`RNMediaLibrary.exportAsset is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return RNMediaLibrary.exportAsset(localId);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function saveToGallery(uri: string, type: string): Promise<boolean> {
|
|
63
|
+
if (!RNMediaLibrary?.saveToGallery) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`RNMediaLibrary.saveToGallery is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return RNMediaLibrary.saveToGallery(uri, type);
|
|
69
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import type { MediaItem } from '../types';
|
|
3
|
+
|
|
4
|
+
const { RNMediaPicker } = NativeModules as {
|
|
5
|
+
RNMediaPicker?: {
|
|
6
|
+
pickMedia: () => Promise<MediaItem[]>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export async function pickMedia(): Promise<MediaItem[]> {
|
|
11
|
+
if (!RNMediaPicker?.pickMedia) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`RNMediaPicker is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return RNMediaPicker.pickMedia();
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
const { RNMediaPlayer } = NativeModules as {
|
|
4
|
+
RNMediaPlayer?: {
|
|
5
|
+
playVideo: (uri: string) => Promise<boolean>;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export async function playVideo(uri: string): Promise<boolean> {
|
|
10
|
+
if (!RNMediaPlayer?.playVideo) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`RNMediaPlayer is not available on ${Platform.OS}. Make sure the native module is linked.`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return RNMediaPlayer.playVideo(uri);
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { requireNativeComponent, ViewStyle, StyleProp } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
uri: string;
|
|
6
|
+
paused?: boolean;
|
|
7
|
+
muted?: boolean;
|
|
8
|
+
style?: StyleProp<ViewStyle>;
|
|
9
|
+
resizeMode?: string;
|
|
10
|
+
trimStartMs?: number;
|
|
11
|
+
trimEndMs?: number;
|
|
12
|
+
seekToMs?: number;
|
|
13
|
+
onChange?: (e: { nativeEvent: { currentTimeMs: number } }) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const NativeVideoPreview = requireNativeComponent<Props>('RNVideoPreview');
|
|
17
|
+
|
|
18
|
+
export function VideoPreview(props: Props) {
|
|
19
|
+
return <NativeVideoPreview {...props} />;
|
|
20
|
+
}
|