├── example
├── .watchmanconfig
├── .gitattributes
├── .babelrc
├── android
│ ├── app
│ │ ├── src
│ │ │ └── main
│ │ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ └── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── example
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── MainApplication.java
│ │ │ │ └── AndroidManifest.xml
│ │ ├── BUCK
│ │ ├── proguard-rules.pro
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── keystores
│ │ ├── debug.keystore.properties
│ │ └── BUCK
│ ├── build.gradle
│ ├── settings.gradle
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── .buckconfig
├── index.ios.js
├── index.android.js
├── __tests__
│ ├── index.ios.js
│ └── index.android.js
├── ios
│ ├── example
│ │ ├── AppDelegate.h
│ │ ├── main.m
│ │ ├── Images.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── AppDelegate.m
│ │ ├── Info.plist
│ │ └── Base.lproj
│ │ │ └── LaunchScreen.xib
│ ├── exampleTests
│ │ ├── Info.plist
│ │ └── exampleTests.m
│ └── example.xcodeproj
│ │ └── xcshareddata
│ │ └── xcschemes
│ │ └── example.xcscheme
├── .gitignore
├── package.json
├── .flowconfig
├── Camera.js
└── App.js
├── .idea
├── copyright
│ └── profiles_settings.xml
├── vcs.xml
├── inspectionProfiles
│ └── profiles_settings.xml
├── jsLibraryMappings.xml
├── modules.xml
├── compiler.xml
├── misc.xml
└── workspace.xml
├── ios
├── RNMediaEditor.h
├── RNMediaEditor.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── RNMediaEditor.m
├── README.md
├── android
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── rnmediaeditor
│ │ ├── RNMediaEditorPackage.java
│ │ └── RNMediaEditorModule.java
└── build.gradle
├── .gitignore
├── package.json
├── MediaEditor.js
└── projectFilesBackup
└── .idea
└── workspace.xml
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | example
3 |
4 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/ios/RNMediaEditor.h:
--------------------------------------------------------------------------------
1 |
2 | #import "RCTBridgeModule.h"
3 | #import
4 |
5 | @interface RNMediaEditor : NSObject
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tkmct/react-native-media-editor/HEAD/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/ios/RNMediaEditor.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tkmct/react-native-media-editor/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tkmct/react-native-media-editor/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tkmct/react-native-media-editor/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tkmct/react-native-media-editor/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = 'debug',
3 | store = 'debug.keystore',
4 | properties = 'debug.keystore.properties',
5 | visibility = [
6 | 'PUBLIC',
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/index.ios.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | import React from 'react';
3 | import { AppRegistry } from 'react-native';
4 | import App from './App';
5 |
6 | AppRegistry.registerComponent('example', () => App);
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/index.android.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | import React from 'react';
3 | import { AppRegistry } from 'react-native';
4 | import App from './App';
5 |
6 | AppRegistry.registerComponent('example', () => App);
7 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jsLibraryMappings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # react-native-media-editor
3 |
4 | To edit video or image
5 |
6 | ## Features
7 | - Add text on image, video like snapchat or instagram
8 |
9 | ## Usage
10 |
11 | ## WIP
12 | - [ ] iOS add text on video
13 | - [ ] Android add text on video
14 |
15 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.apk
2 | *.ap_
3 | *.dex
4 | *.class
5 | bin/
6 | gen/
7 | local.properties
8 | .classpath
9 | .project
10 | proguard/
11 | *.iml
12 | *.ipr
13 | *.iws
14 | .gradle
15 | gradle
16 | .idea
17 | .DS_Store
18 | gradlew
19 | gradlew.bat
20 |
21 | build
22 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/__tests__/index.ios.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.ios.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/example/__tests__/index.android.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.android.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "example";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Xcode ###
2 |
3 | ## Build generated
4 | build/
5 | DerivedData/
6 |
7 | ## Various settings
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata/
17 |
18 | ## Other
19 | *.moved-aside
20 | *.xccheckout
21 | *.xcscmblueprint
22 |
23 | ### /Xcode ###
24 |
25 | ### OS X
26 | .DS_Store
27 |
28 | ### Node
29 | node_modules
30 | *.log
31 |
32 | ## Android iml
33 | *.iml
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "name": "react-native-media-editor",
4 | "description": "Media file editor for ReactNative",
5 | "version": "0.0.1",
6 | "author": "Takamichi-tsutsumi <1220t.takamichi@gmail.com>",
7 | "license": "MIT",
8 | "repository": "Takamichi-tsutsumi/react-native-media-editor",
9 | "main": "MediaEditor.js",
10 | "private": false,
11 | "scripts": {
12 | "test": "echo \"Error: no test specified\" && exit 1"
13 | },
14 | "keywords": [
15 | "react-native"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/MediaEditor.js:
--------------------------------------------------------------------------------
1 |
2 | import { NativeModules } from 'react-native';
3 |
4 | const { RNMediaEditor } = NativeModules;
5 |
6 | const DEFAULT_OPTIONS = {
7 | fontSize: 24,
8 | textColor: '#ffffff',
9 | backgroundColor: '#000000',
10 | backgroundOpacity: 0.5,
11 | top: 100,
12 | left: 100,
13 | };
14 |
15 |
16 | // module.exports = {
17 | // ...RNMediaEditor,
18 | // embedText: (options) => {
19 | // return RNMediaEditor.embedText({...DEFAULT_OPTIONS, ...options});
20 | // }
21 | // }
22 |
23 | export default RNMediaEditor;
24 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/example/ios/example/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 |
38 | # BUCK
39 | buck-out/
40 | \.buckd/
41 | android/app/libs
42 | *.keystore
43 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | maven {
20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
21 | url "$rootDir/../node_modules/react-native/android"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'example'
2 | include ':react-native-video'
3 | project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
4 | include ':react-native-media-editor'
5 | project(':react-native-media-editor').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-media-editor/android')
6 | include ':react-native-image-picker'
7 | project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android')
8 | include ':react-native-camera'
9 | project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
10 |
11 | include ':app'
12 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | jcenter()
4 | }
5 |
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:2.1.3'
8 | }
9 | }
10 |
11 | apply plugin: 'com.android.library'
12 |
13 | android {
14 | compileSdkVersion 23
15 | buildToolsVersion "23.0.1"
16 |
17 | defaultConfig {
18 | minSdkVersion 16
19 | targetSdkVersion 22
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 | lintOptions {
24 | abortOnError false
25 | warning 'InvalidPackage'
26 | }
27 | }
28 |
29 | repositories {
30 | mavenCentral()
31 | }
32 |
33 | dependencies {
34 | compile 'com.facebook.react:react-native:0.20.+'
35 | compile 'com.writingminds:FFmpegAndroid:0.3.2'
36 | }
37 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "react": "15.4.1",
11 | "react-native": "^0.39.2",
12 | "react-native-camera": "^0.4.0",
13 | "react-native-image-picker": "^0.24.1",
14 | "react-native-media-editor": "file:../",
15 | "react-native-video": "^0.9.0"
16 | },
17 | "devDependencies": {
18 | "babel-jest": "18.0.0",
19 | "babel-preset-react-native": "1.9.1",
20 | "flow-bin": "^0.37.4",
21 | "jest": "18.0.0",
22 | "react-test-renderer": "15.4.1"
23 | },
24 | "jest": {
25 | "preset": "react-native"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/rnmediaeditor/RNMediaEditorPackage.java:
--------------------------------------------------------------------------------
1 | package com.rnmediaeditor;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.ArrayList;
7 |
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.bridge.NativeModule;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.uimanager.ViewManager;
12 | import com.facebook.react.bridge.JavaScriptModule;
13 |
14 | public class RNMediaEditorPackage implements ReactPackage {
15 |
16 | @Override
17 | public List createNativeModules(ReactApplicationContext reactContext) {
18 | List modules = new ArrayList<>();
19 |
20 | modules.add(new RNMediaEditorModule(reactContext));
21 |
22 | return modules;
23 | }
24 |
25 | @Override
26 | public List> createJSModules() {
27 | return Collections.emptyList();
28 | }
29 |
30 | @Override
31 | public List createViewManagers(ReactApplicationContext reactContext) {
32 | return Collections.emptyList();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import "RCTBundleURLProvider.h"
13 | #import "RCTRootView.h"
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | NSURL *jsCodeLocation;
20 |
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
22 |
23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
24 | moduleName:@"example"
25 | initialProperties:nil
26 | launchOptions:launchOptions];
27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
30 | UIViewController *rootViewController = [UIViewController new];
31 | rootViewController.view = rootView;
32 | self.window.rootViewController = rootViewController;
33 | [self.window makeKeyAndVisible];
34 | return YES;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 | .*/Libraries/react-native/ReactNative.js
16 |
17 | [include]
18 |
19 | [libs]
20 | node_modules/react-native/Libraries/react-native/react-native-interface.js
21 | node_modules/react-native/flow
22 | flow/
23 |
24 | [options]
25 | module.system=haste
26 |
27 | experimental.strict_type_args=true
28 |
29 | munge_underscores=true
30 |
31 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
32 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
33 |
34 | suppress_type=$FlowIssue
35 | suppress_type=$FlowFixMe
36 | suppress_type=$FixMe
37 |
38 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-5]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
39 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-5]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
40 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
41 |
42 | unsafe.enable_getters_and_setters=true
43 |
44 | [version]
45 | ^0.35.0
46 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import com.facebook.react.ReactApplication;
7 | import com.brentvatne.react.ReactVideoPackage;
8 | import com.rnmediaeditor.RNMediaEditorPackage;
9 | import com.imagepicker.ImagePickerPackage;
10 | import com.lwansbrough.RCTCamera.RCTCameraPackage;
11 | import com.facebook.react.ReactInstanceManager;
12 | import com.facebook.react.ReactNativeHost;
13 | import com.facebook.react.ReactPackage;
14 | import com.facebook.react.shell.MainReactPackage;
15 | import com.facebook.soloader.SoLoader;
16 |
17 | import java.util.Arrays;
18 | import java.util.List;
19 |
20 | public class MainApplication extends Application implements ReactApplication {
21 |
22 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
23 | @Override
24 | protected boolean getUseDeveloperSupport() {
25 | return BuildConfig.DEBUG;
26 | }
27 |
28 | @Override
29 | protected List getPackages() {
30 | return Arrays.asList(
31 | new MainReactPackage(),
32 | new ReactVideoPackage(),
33 | new RNMediaEditorPackage(),
34 | new ImagePickerPackage(),
35 | new RCTCameraPackage()
36 | );
37 | }
38 | };
39 |
40 | @Override
41 | public ReactNativeHost getReactNativeHost() {
42 | return mReactNativeHost;
43 | }
44 |
45 | @Override
46 | public void onCreate() {
47 | super.onCreate();
48 | SoLoader.init(this, /* native exopackage */ false);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | # To learn about Buck see [Docs](https://buckbuild.com/).
4 | # To run your application with Buck:
5 | # - install Buck
6 | # - `npm start` - to start the packager
7 | # - `cd android`
8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
10 | # - `buck install -r android/app` - compile, install and run application
11 | #
12 |
13 | lib_deps = []
14 | for jarfile in glob(['libs/*.jar']):
15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
16 | lib_deps.append(':' + name)
17 | prebuilt_jar(
18 | name = name,
19 | binary_jar = jarfile,
20 | )
21 |
22 | for aarfile in glob(['libs/*.aar']):
23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
24 | lib_deps.append(':' + name)
25 | android_prebuilt_aar(
26 | name = name,
27 | aar = aarfile,
28 | )
29 |
30 | android_library(
31 | name = 'all-libs',
32 | exported_deps = lib_deps
33 | )
34 |
35 | android_library(
36 | name = 'app-code',
37 | srcs = glob([
38 | 'src/main/java/**/*.java',
39 | ]),
40 | deps = [
41 | ':all-libs',
42 | ':build_config',
43 | ':res',
44 | ],
45 | )
46 |
47 | android_build_config(
48 | name = 'build_config',
49 | package = 'com.example',
50 | )
51 |
52 | android_resource(
53 | name = 'res',
54 | res = 'src/main/res',
55 | package = 'com.example',
56 | )
57 |
58 | android_binary(
59 | name = 'app',
60 | package_type = 'debug',
61 | manifest = 'src/main/AndroidManifest.xml',
62 | keystore = '//android/keystores:debug',
63 | deps = [
64 | ':app-code',
65 | ],
66 | )
67 |
--------------------------------------------------------------------------------
/example/ios/example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppleMusicUsageDescription
6 | Please allow app to access media library
7 | NSPhotoLibraryUsageDescription
8 | Please allow app to access Photo Library
9 | CFBundleDevelopmentRegion
10 | en
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | 1
27 | LSRequiresIPhoneOS
28 |
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UIViewControllerBasedStatusBarAppearance
42 |
43 | NSLocationWhenInUseUsageDescription
44 |
45 | NSAppTransportSecurity
46 |
47 | NSExceptionDomains
48 |
49 | localhost
50 |
51 | NSExceptionAllowsInsecureHTTPLoads
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/example/Camera.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | View,
4 | Text,
5 | StyleSheet,
6 | Dimensions
7 | } from 'react-native';
8 | import Camera from 'react-native-camera';
9 |
10 | class CameraView extends Component {
11 | constructor(props) {
12 | super(props);
13 |
14 | this.state = {
15 | recording: false
16 | }
17 |
18 | this.takeVideo = this.takeVideo.bind(this);
19 | this.renderButton = this.renderButton.bind(this);
20 | }
21 |
22 | takeVideo() {
23 | this.setState({recording: true});
24 | this.camera.capture()
25 | .then(data => {
26 | console.log(data);
27 | this.props.onVideoReturned(data);
28 | })
29 | .catch(err => console.error(err));
30 |
31 | setTimeout(() => {
32 | this.camera.stopCapture();
33 | this.props.endCapturing();
34 | }, 5000);
35 | }
36 |
37 | renderButton() {
38 | if (this.state.recording) {
39 | return (
40 | [Capturing]
41 | )
42 | } else {
43 | return (
44 | [Capture]
45 | )
46 | }
47 | }
48 |
49 | render() {
50 | return (
51 |
52 | {
54 | this.camera = cam;
55 | }}
56 | style={styles.preview}
57 | aspect={Camera.constants.Aspect.fill}
58 | captureMode={Camera.constants.CaptureMode.video}
59 | >
60 | {
61 | this.renderButton()
62 | }
63 |
64 |
65 | )
66 | }
67 | }
68 |
69 | const styles = StyleSheet.create({
70 | container: {
71 | flex: 1
72 | },
73 | preview: {
74 | flex: 1,
75 | justifyContent: 'flex-end',
76 | alignItems: 'center',
77 | height: Dimensions.get('window').height,
78 | width: Dimensions.get('window').width
79 | },
80 | capture: {
81 | flex: 0,
82 | backgroundColor: '#fff',
83 | borderRadius: 5,
84 | color: '#000',
85 | padding: 10,
86 | margin: 40
87 | }
88 | });
89 |
90 | export default CameraView;
91 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
22 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | File Watchers
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/exampleTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import "RCTLog.h"
14 | #import "RCTRootView.h"
15 |
16 | #define TIMEOUT_SECONDS 600
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface exampleTests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation exampleTests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # okhttp
54 |
55 | -keepattributes Signature
56 | -keepattributes *Annotation*
57 | -keep class okhttp3.** { *; }
58 | -keep interface okhttp3.** { *; }
59 | -dontwarn okhttp3.**
60 |
61 | # okio
62 |
63 | -keep class sun.misc.Unsafe { *; }
64 | -dontwarn java.nio.file.*
65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
66 | -dontwarn okio.**
67 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/ios/example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
94 |
96 |
102 |
103 |
104 |
105 |
107 |
108 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // the root of your project, i.e. where "package.json" lives
37 | * root: "../../",
38 | *
39 | * // where to put the JS bundle asset in debug mode
40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
41 | *
42 | * // where to put the JS bundle asset in release mode
43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
44 | *
45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
46 | * // require('./image.png')), in debug mode
47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
48 | *
49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
50 | * // require('./image.png')), in release mode
51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
52 | *
53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
57 | * // for example, you might want to remove it from here.
58 | * inputExcludes: ["android/**", "ios/**"],
59 | *
60 | * // override which node gets called and with what additional arguments
61 | * nodeExecutableAndArgs: ["node"]
62 | *
63 | * // supply additional arguments to the packager
64 | * extraPackagerArgs: []
65 | * ]
66 | */
67 |
68 | apply from: "../../node_modules/react-native/react.gradle"
69 |
70 | /**
71 | * Set this to true to create two separate APKs instead of one:
72 | * - An APK that only works on ARM devices
73 | * - An APK that only works on x86 devices
74 | * The advantage is the size of the APK is reduced by about 4MB.
75 | * Upload all the APKs to the Play Store and people will download
76 | * the correct one based on the CPU architecture of their device.
77 | */
78 | def enableSeparateBuildPerCPUArchitecture = false
79 |
80 | /**
81 | * Run Proguard to shrink the Java bytecode in release builds.
82 | */
83 | def enableProguardInReleaseBuilds = false
84 |
85 | android {
86 | compileSdkVersion 23
87 | buildToolsVersion "23.0.1"
88 |
89 | defaultConfig {
90 | applicationId "com.example"
91 | minSdkVersion 16
92 | targetSdkVersion 22
93 | versionCode 1
94 | versionName "1.0"
95 | ndk {
96 | abiFilters "armeabi-v7a", "x86"
97 | }
98 | }
99 | splits {
100 | abi {
101 | reset()
102 | enable enableSeparateBuildPerCPUArchitecture
103 | universalApk false // If true, also generate a universal APK
104 | include "armeabi-v7a", "x86"
105 | }
106 | }
107 | buildTypes {
108 | release {
109 | minifyEnabled enableProguardInReleaseBuilds
110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
111 | }
112 | }
113 | // applicationVariants are e.g. debug, release
114 | applicationVariants.all { variant ->
115 | variant.outputs.each { output ->
116 | // For each separate APK per architecture, set a unique version code as described here:
117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
118 | def versionCodes = ["armeabi-v7a":1, "x86":2]
119 | def abi = output.getFilter(OutputFile.ABI)
120 | if (abi != null) { // null for the universal-debug, universal-release variants
121 | output.versionCodeOverride =
122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
123 | }
124 | }
125 | }
126 | }
127 |
128 | dependencies {
129 | compile project(':react-native-video')
130 | compile project(':react-native-media-editor')
131 | compile project(':react-native-image-picker')
132 | compile project(':react-native-camera')
133 | compile fileTree(dir: "libs", include: ["*.jar"])
134 | compile "com.android.support:appcompat-v7:23.0.1"
135 | compile "com.facebook.react:react-native:+" // From node_modules
136 | }
137 |
138 | // Run this once to be able to run the application with BUCK
139 | // puts all compile dependencies into folder libs for BUCK to use
140 | task copyDownloadableDepsToLibs(type: Copy) {
141 | from configurations.compile
142 | into 'libs'
143 | }
144 |
--------------------------------------------------------------------------------
/example/App.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | import React, { Component } from 'react';
4 | import {
5 | StyleSheet,
6 | Text,
7 | View,
8 | Image,
9 | Button,
10 | Dimensions,
11 | Platform,
12 | ActivityIndicator,
13 | TextInput,
14 | TouchableWithoutFeedback
15 | } from 'react-native';
16 | import ImagePicker from 'react-native-image-picker';
17 | import RNMediaEditor from 'react-native-media-editor';
18 | import Video from 'react-native-video';
19 |
20 |
21 | var options = {
22 | image: {
23 | title: 'Select Image',
24 | mediaType: 'photo',
25 | storageOptions: {
26 | skipBackup: true,
27 | },
28 | },
29 | video: {
30 | title: 'Select Video',
31 | mediaType: 'video',
32 | storageOptions: {
33 | skipBackup: true,
34 | }
35 | }
36 | };
37 |
38 | function toVerticalString(str) {
39 | let verStr = '';
40 | for (s of str) {
41 | verStr += s + '\n';
42 | }
43 | return verStr;
44 | }
45 |
46 | class App extends Component {
47 | constructor(props) {
48 | super(props);
49 |
50 | this.state = {
51 | loading: false,
52 | assetType: 'image',
53 | asset: null,
54 | text: 'Hello world',
55 | fontSize: 50,
56 | colorCode: '#ffffff',
57 | textBackgroundColor: '#ff00e0',
58 | rate: 0,
59 | camera: false,
60 | };
61 |
62 | this.onButtonPress = this.onButtonPress.bind(this);
63 | this.onEmbedButtonPress = this.onEmbedButtonPress.bind(this);
64 | this.renderMedia = this.renderMedia.bind(this);
65 | this.renderVideo = this.renderVideo.bind(this);
66 | this.renderImage = this.renderImage.bind(this);
67 | this.renderInput = this.renderInput.bind(this);
68 | this.playVideo = this.playVideo.bind(this);
69 | this.endVideo = this.endVideo.bind(this);
70 | this.log = this.log.bind(this);
71 | }
72 |
73 | log() {
74 | console.log(this.state);
75 | console.log(RNMediaEditor);
76 | }
77 |
78 | onButtonPress(type) {
79 | this.setState({
80 | assetType: type,
81 | asset: null,
82 | loading: true
83 | });
84 |
85 | ImagePicker.launchImageLibrary(options[type], (response) => {
86 | console.log('Response = ', response);
87 |
88 | if (response.didCancel) {
89 | console.log('User cancelled image picker');
90 | }
91 | else if (response.error) {
92 | console.log('ImagePicker Error: ', response.error);
93 | } else {
94 | console.log(response);
95 | // You can display the image using either data...
96 | let source = {uri: 'data:image/jpeg;base64,' + response.data, isStatic: true};
97 |
98 | // or a reference to the platform specific asset location
99 | if (Platform.OS === 'ios') {
100 | source = {
101 | ...source,
102 | path: response.uri.replace('file://', ''),
103 | assetURL: response.origURL,
104 | width: response.width,
105 | height: response.height,
106 | };
107 | } else {
108 | source = {
109 | ...source,
110 | path: response.path,
111 | width: response.width,
112 | height: response.height,
113 | };
114 | }
115 |
116 | this.setState({
117 | asset: source,
118 | loading: false,
119 | });
120 | }
121 | });
122 | }
123 |
124 | onEmbedButtonPress() {
125 | const {asset, assetType, text, subText, fontSize, colorCode, textBackgroundColor} = this.state;
126 |
127 | if (assetType === 'image') {
128 | const data = asset.uri.replace('data:image/jpeg;base64,', '');
129 | const options = {
130 | data,
131 | path: asset.path,
132 | type: assetType,
133 | firstText: {
134 | left: 200,
135 | top: 200,
136 | backgroundOpacity: 0.5,
137 | text: toVerticalString(text),
138 | fontSize,
139 | textColor: colorCode,
140 | backgroundColor: textBackgroundColor,
141 | },
142 | secondText: {
143 | left: 500,
144 | top: 500,
145 | backgroundOpacity: 0.5,
146 | text: 'Hello2',
147 | fontSize,
148 | textColor: colorCode,
149 | backgroundColor: '#000000',
150 | }
151 | };
152 |
153 | RNMediaEditor.embedText(options)
154 | .then(res => {
155 | this.setState({
156 | asset: {...this.state.asset, uri: 'data:image/jpeg;base64,' + res[1] }
157 | });
158 | console.log(res);
159 | })
160 | .catch(err => {
161 | console.log(err);
162 | });
163 |
164 | } else if (assetType === 'video') {
165 | const options = {
166 | path: asset.path,
167 | type: assetType,
168 | firstText: {
169 | left: 200,
170 | top: 200,
171 | backgroundOpacity: 0.5,
172 | text,
173 | fontSize,
174 | textColor: colorCode,
175 | backgroundColor: textBackgroundColor,
176 | },
177 | secondText: {
178 | left: 500,
179 | top: 500,
180 | backgroundOpacity: 0.5,
181 | text: '石垣島',
182 | fontSize,
183 | textColor: colorCode,
184 | backgroundColor: '#000000',
185 | },
186 | };
187 | console.log('embed text on video');
188 |
189 | RNMediaEditor.embedText(options)
190 | .then(res => {
191 | console.log(res);
192 | })
193 | .catch(err => {
194 | console.log(err);
195 | });
196 | }
197 |
198 | }
199 |
200 | renderMedia() {
201 | const { assetType } = this.state;
202 | if (assetType === 'video') {
203 | return this.renderVideo();
204 | } else if (assetType === 'image') {
205 | return this.renderImage();
206 | } else {
207 | return;
208 | }
209 | }
210 |
211 | playVideo() {
212 | console.log("play video pressed");
213 | this.setState({
214 | rate: 1
215 | });
216 | }
217 |
218 | endVideo() {
219 | console.log("end video pressed");
220 | this.setState({
221 | rate: 0
222 | });
223 | this.player.seek(0);
224 | }
225 |
226 | renderVideo() {
227 | if (this.state.asset) {
228 | return (
229 |
232 |
243 | );
244 | } else {
245 | return ;
246 | }
247 | }
248 |
249 | renderImage() {
250 | if (this.state.assetType === 'image') {
251 | return (
252 |
257 | )
258 | } else if (this.state.loading) {
259 | return ;
260 | } else {
261 | return;
262 | }
263 | }
264 |
265 | renderInput() {
266 | return (
267 |
268 |
269 | Text
270 | this.setState({text})}
273 | value={this.state.text}
274 | />
275 |
276 |
277 | Font Size
278 | this.setState({fontSize: Number(fontSize)})}
281 | keyboardType="number-pad"
282 | value={String(this.state.fontSize)}
283 | />
284 |
285 |
286 | Color
287 | this.setState({colorCode})}
290 | value={this.state.colorCode}
291 | />
292 |
293 |
294 | )
295 | }
296 |
297 | render() {
298 | return (
299 |
300 |
301 | { this.renderMedia() }
302 |
303 |
304 |
322 |
323 | );
324 | }
325 | }
326 |
327 | const styles = StyleSheet.create({
328 | container: {
329 | flex: 1,
330 | alignItems: 'center',
331 | backgroundColor: '#F5FCFF',
332 | },
333 | image: {
334 | width: Dimensions.get('window').width,
335 | height: Dimensions.get('window').height/2,
336 | },
337 | input: {
338 | height: 20,
339 | width: 200,
340 | borderWidth: 0.5,
341 | borderColor: '#0f0f0f',
342 | borderRadius: 5,
343 | fontSize: 14,
344 | padding: 4,
345 | },
346 | video: {
347 | flex: 1,
348 | width: 200,
349 | height: 300
350 | }
351 | });
352 |
353 | export default App;
354 |
--------------------------------------------------------------------------------
/ios/RNMediaEditor.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B3E7B58A1CC2AC0600A0062D /* RNMediaEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNMediaEditor.m */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = "include/$(PRODUCT_NAME)";
18 | dstSubfolderSpec = 16;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 0;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 134814201AA4EA6300B7C361 /* libRNMediaEditor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNMediaEditor.a; sourceTree = BUILT_PRODUCTS_DIR; };
27 | B3E7B5881CC2AC0600A0062D /* RNMediaEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNMediaEditor.h; sourceTree = ""; };
28 | B3E7B5891CC2AC0600A0062D /* RNMediaEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNMediaEditor.m; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 58B511D81A9E6C8500147676 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 134814211AA4EA7D00B7C361 /* Products */ = {
43 | isa = PBXGroup;
44 | children = (
45 | 134814201AA4EA6300B7C361 /* libRNMediaEditor.a */,
46 | );
47 | name = Products;
48 | sourceTree = "";
49 | };
50 | 58B511D21A9E6C8500147676 = {
51 | isa = PBXGroup;
52 | children = (
53 | B3E7B5881CC2AC0600A0062D /* RNMediaEditor.h */,
54 | B3E7B5891CC2AC0600A0062D /* RNMediaEditor.m */,
55 | 134814211AA4EA7D00B7C361 /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | /* End PBXGroup section */
60 |
61 | /* Begin PBXNativeTarget section */
62 | 58B511DA1A9E6C8500147676 /* RNMediaEditor */ = {
63 | isa = PBXNativeTarget;
64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNMediaEditor" */;
65 | buildPhases = (
66 | 58B511D71A9E6C8500147676 /* Sources */,
67 | 58B511D81A9E6C8500147676 /* Frameworks */,
68 | 58B511D91A9E6C8500147676 /* CopyFiles */,
69 | );
70 | buildRules = (
71 | );
72 | dependencies = (
73 | );
74 | name = RNMediaEditor;
75 | productName = RCTDataManager;
76 | productReference = 134814201AA4EA6300B7C361 /* libRNMediaEditor.a */;
77 | productType = "com.apple.product-type.library.static";
78 | };
79 | /* End PBXNativeTarget section */
80 |
81 | /* Begin PBXProject section */
82 | 58B511D31A9E6C8500147676 /* Project object */ = {
83 | isa = PBXProject;
84 | attributes = {
85 | LastUpgradeCheck = 0610;
86 | ORGANIZATIONNAME = Facebook;
87 | TargetAttributes = {
88 | 58B511DA1A9E6C8500147676 = {
89 | CreatedOnToolsVersion = 6.1.1;
90 | LastSwiftMigration = 0820;
91 | };
92 | };
93 | };
94 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNMediaEditor" */;
95 | compatibilityVersion = "Xcode 3.2";
96 | developmentRegion = English;
97 | hasScannedForEncodings = 0;
98 | knownRegions = (
99 | en,
100 | );
101 | mainGroup = 58B511D21A9E6C8500147676;
102 | productRefGroup = 58B511D21A9E6C8500147676;
103 | projectDirPath = "";
104 | projectRoot = "";
105 | targets = (
106 | 58B511DA1A9E6C8500147676 /* RNMediaEditor */,
107 | );
108 | };
109 | /* End PBXProject section */
110 |
111 | /* Begin PBXSourcesBuildPhase section */
112 | 58B511D71A9E6C8500147676 /* Sources */ = {
113 | isa = PBXSourcesBuildPhase;
114 | buildActionMask = 2147483647;
115 | files = (
116 | B3E7B58A1CC2AC0600A0062D /* RNMediaEditor.m in Sources */,
117 | );
118 | runOnlyForDeploymentPostprocessing = 0;
119 | };
120 | /* End PBXSourcesBuildPhase section */
121 |
122 | /* Begin XCBuildConfiguration section */
123 | 58B511ED1A9E6C8500147676 /* Debug */ = {
124 | isa = XCBuildConfiguration;
125 | buildSettings = {
126 | ALWAYS_SEARCH_USER_PATHS = NO;
127 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
128 | CLANG_CXX_LIBRARY = "libc++";
129 | CLANG_ENABLE_MODULES = YES;
130 | CLANG_ENABLE_OBJC_ARC = YES;
131 | CLANG_WARN_BOOL_CONVERSION = YES;
132 | CLANG_WARN_CONSTANT_CONVERSION = YES;
133 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
134 | CLANG_WARN_EMPTY_BODY = YES;
135 | CLANG_WARN_ENUM_CONVERSION = YES;
136 | CLANG_WARN_INT_CONVERSION = YES;
137 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
138 | CLANG_WARN_UNREACHABLE_CODE = YES;
139 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
140 | COPY_PHASE_STRIP = NO;
141 | ENABLE_STRICT_OBJC_MSGSEND = YES;
142 | GCC_C_LANGUAGE_STANDARD = gnu99;
143 | GCC_DYNAMIC_NO_PIC = NO;
144 | GCC_OPTIMIZATION_LEVEL = 0;
145 | GCC_PREPROCESSOR_DEFINITIONS = (
146 | "DEBUG=1",
147 | "$(inherited)",
148 | );
149 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
150 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
151 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
152 | GCC_WARN_UNDECLARED_SELECTOR = YES;
153 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
154 | GCC_WARN_UNUSED_FUNCTION = YES;
155 | GCC_WARN_UNUSED_VARIABLE = YES;
156 | HEADER_SEARCH_PATHS = (
157 | "$(SRCROOT)/../example/node_modules/react-native/Libraries/**",
158 | "$(SRCROOT)/../example/node_modules/react-native/React/**",
159 | );
160 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
161 | MTL_ENABLE_DEBUG_INFO = YES;
162 | ONLY_ACTIVE_ARCH = YES;
163 | SDKROOT = iphoneos;
164 | };
165 | name = Debug;
166 | };
167 | 58B511EE1A9E6C8500147676 /* Release */ = {
168 | isa = XCBuildConfiguration;
169 | buildSettings = {
170 | ALWAYS_SEARCH_USER_PATHS = NO;
171 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
172 | CLANG_CXX_LIBRARY = "libc++";
173 | CLANG_ENABLE_MODULES = YES;
174 | CLANG_ENABLE_OBJC_ARC = YES;
175 | CLANG_WARN_BOOL_CONVERSION = YES;
176 | CLANG_WARN_CONSTANT_CONVERSION = YES;
177 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
178 | CLANG_WARN_EMPTY_BODY = YES;
179 | CLANG_WARN_ENUM_CONVERSION = YES;
180 | CLANG_WARN_INT_CONVERSION = YES;
181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
182 | CLANG_WARN_UNREACHABLE_CODE = YES;
183 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
184 | COPY_PHASE_STRIP = YES;
185 | ENABLE_NS_ASSERTIONS = NO;
186 | ENABLE_STRICT_OBJC_MSGSEND = YES;
187 | GCC_C_LANGUAGE_STANDARD = gnu99;
188 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
189 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
190 | GCC_WARN_UNDECLARED_SELECTOR = YES;
191 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
192 | GCC_WARN_UNUSED_FUNCTION = YES;
193 | GCC_WARN_UNUSED_VARIABLE = YES;
194 | HEADER_SEARCH_PATHS = (
195 | "$(SRCROOT)/../example/node_modules/react-native/Libraries/**",
196 | "$(SRCROOT)/../example/node_modules/react-native/React/**",
197 | );
198 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
199 | MTL_ENABLE_DEBUG_INFO = NO;
200 | SDKROOT = iphoneos;
201 | VALIDATE_PRODUCT = YES;
202 | };
203 | name = Release;
204 | };
205 | 58B511F01A9E6C8500147676 /* Debug */ = {
206 | isa = XCBuildConfiguration;
207 | buildSettings = {
208 | CLANG_ENABLE_MODULES = YES;
209 | HEADER_SEARCH_PATHS = (
210 | "$(inherited)",
211 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
212 | "$(SRCROOT)/../../../React/**",
213 | "$(SRCROOT)/../../../Libraries/**",
214 | "$(SRCROOT)/../../react-native/React/**",
215 | "$(SRCROOT)/../../react-native/Libraries/**",
216 | "/Users/takamichi/Development/ghq/github.com/Takamichi-tsutsumi/react-native-media-editor/example/node_modules/react-native/React/**",
217 | "/Users/takamichi/Development/ghq/github.com/Takamichi-tsutsumi/react-native-media-editor/example/node_modules/react-native/Libraries/**",
218 | );
219 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
220 | LIBRARY_SEARCH_PATHS = "$(inherited)";
221 | OTHER_LDFLAGS = "-ObjC";
222 | PRODUCT_NAME = RNMediaEditor;
223 | SKIP_INSTALL = YES;
224 | SWIFT_OBJC_BRIDGING_HEADER = "../../../../ios/RNMediaEditor-Bridging-Header.h";
225 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
226 | SWIFT_VERSION = 3.0;
227 | };
228 | name = Debug;
229 | };
230 | 58B511F11A9E6C8500147676 /* Release */ = {
231 | isa = XCBuildConfiguration;
232 | buildSettings = {
233 | CLANG_ENABLE_MODULES = YES;
234 | HEADER_SEARCH_PATHS = (
235 | "$(inherited)",
236 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
237 | "$(SRCROOT)/../../../React/**",
238 | "$(SRCROOT)/../../../Libraries/**",
239 | "$(SRCROOT)/../../react-native/React/**",
240 | "$(SRCROOT)/../../react-native/Libraries/**",
241 | "/Users/takamichi/Development/ghq/github.com/Takamichi-tsutsumi/react-native-media-editor/example/node_modules/react-native/React/**",
242 | "/Users/takamichi/Development/ghq/github.com/Takamichi-tsutsumi/react-native-media-editor/example/node_modules/react-native/Libraries/**",
243 | );
244 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
245 | LIBRARY_SEARCH_PATHS = "$(inherited)";
246 | OTHER_LDFLAGS = "-ObjC";
247 | PRODUCT_NAME = RNMediaEditor;
248 | SKIP_INSTALL = YES;
249 | SWIFT_OBJC_BRIDGING_HEADER = "../../../../ios/RNMediaEditor-Bridging-Header.h";
250 | SWIFT_VERSION = 3.0;
251 | };
252 | name = Release;
253 | };
254 | /* End XCBuildConfiguration section */
255 |
256 | /* Begin XCConfigurationList section */
257 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNMediaEditor" */ = {
258 | isa = XCConfigurationList;
259 | buildConfigurations = (
260 | 58B511ED1A9E6C8500147676 /* Debug */,
261 | 58B511EE1A9E6C8500147676 /* Release */,
262 | );
263 | defaultConfigurationIsVisible = 0;
264 | defaultConfigurationName = Release;
265 | };
266 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNMediaEditor" */ = {
267 | isa = XCConfigurationList;
268 | buildConfigurations = (
269 | 58B511F01A9E6C8500147676 /* Debug */,
270 | 58B511F11A9E6C8500147676 /* Release */,
271 | );
272 | defaultConfigurationIsVisible = 0;
273 | defaultConfigurationName = Release;
274 | };
275 | /* End XCConfigurationList section */
276 | };
277 | rootObject = 58B511D31A9E6C8500147676 /* Project object */;
278 | }
279 |
--------------------------------------------------------------------------------
/android/src/main/java/com/rnmediaeditor/RNMediaEditorModule.java:
--------------------------------------------------------------------------------
1 | package com.rnmediaeditor;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Rect;
9 | import android.os.Environment;
10 | import android.provider.MediaStore;
11 | import android.support.annotation.Nullable;
12 | import android.support.annotation.RequiresPermission;
13 | import android.support.annotation.StringDef;
14 | import android.util.Log;
15 | import android.util.Base64;
16 |
17 | import com.facebook.react.bridge.ReactApplicationContext;
18 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
19 | import com.facebook.react.bridge.ReactMethod;
20 | import com.facebook.react.bridge.Callback;
21 | import com.facebook.react.bridge.Promise;
22 | import com.facebook.react.bridge.ReadableMap;
23 | import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
24 | import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
25 | import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
26 | import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegCommandAlreadyRunningException;
27 | import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;
28 |
29 | import java.io.File;
30 | import java.io.FileNotFoundException;
31 | import java.io.FileOutputStream;
32 | import java.io.IOException;
33 | import java.nio.ByteBuffer;
34 | import java.text.SimpleDateFormat;
35 | import java.util.Date;
36 |
37 |
38 | public class RNMediaEditorModule extends ReactContextBaseJavaModule {
39 |
40 | private final ReactApplicationContext _reactContext;
41 | private static final String TAG = "RNMediaEditorModule";
42 |
43 | public static final int TYPE_IMAGE = 1;
44 | public static final int TYPE_VIDEO = 2;
45 |
46 | public static Promise _promise;
47 |
48 | public RNMediaEditorModule(ReactApplicationContext reactContext) {
49 | super(reactContext);
50 | this._reactContext = reactContext;
51 | }
52 |
53 | @Override
54 | public String getName() {
55 | return "RNMediaEditor";
56 | }
57 |
58 | @ReactMethod
59 | public void embedText(final ReadableMap options, Promise promise) {
60 | String type = options.getString("type");
61 | if (type.equals("image")) {
62 | Log.d("Example", "RNMediaeditor embed text on image called");
63 | embedTextOnImage(options, promise);
64 | } else if (type.equals("video")) {
65 | embedTextOnVideo(options, promise);
66 | }
67 | }
68 |
69 | private void embedTextOnImage(final ReadableMap options, final Promise promise) {
70 | String path = options.getString("path");
71 |
72 | File img = new File(path);
73 |
74 | if (img.exists()) {
75 | ReadableMap firstText = options.getMap("firstText");
76 | // create base bitmap of input file
77 | Bitmap bitmap = BitmapFactory.decodeFile(path);
78 | Bitmap.Config bitmapConfig = bitmap.getConfig();
79 |
80 | Log.d("example", "bytes:" + Integer.toString(bitmap.getByteCount()));
81 | // set default config if config is none
82 | if (bitmapConfig == null) {
83 | bitmapConfig = Bitmap.Config.ARGB_8888;
84 | }
85 |
86 | bitmap = bitmap.copy(bitmapConfig, true);
87 | Canvas canvas = new Canvas(bitmap);
88 |
89 |
90 | String backgroundColor = firstText.getString("backgroundColor");
91 | float backgroundOpacity = (float) (firstText.getDouble("backgroundOpacity"));
92 |
93 | // draw text container container
94 | Paint containerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
95 | containerPaint.setColor(Color.parseColor(backgroundColor));
96 | containerPaint.setStyle(Paint.Style.FILL);
97 | int opacity = (int) (255 * backgroundOpacity);
98 | containerPaint.setAlpha(opacity);
99 |
100 | String fontColor = firstText.getString("textColor");
101 | int fontSize = firstText.getInt("fontSize");
102 | String text = firstText.getString("text");
103 |
104 | // draw text Paint
105 | Paint textPaint = new Paint();
106 | textPaint.setColor(Color.parseColor(fontColor));
107 |
108 | // convert pixel to sp
109 | // float scaledDensity = _reactContext.getResources().getDisplayMetrics().scaledDensity;
110 | // textPaint.setTextSize(fontSize/scaledDensity);
111 | textPaint.setTextSize(fontSize);
112 | float textSize = textPaint.getTextSize();
113 | float containerWidth = textPaint.measureText(text) + textSize * 2;
114 |
115 | int top = firstText.getInt("top");
116 | int left = firstText.getInt("left");
117 | // draw paint in canvas
118 | canvas.drawRect(left, top, left + containerWidth, top + textSize * 2, containerPaint); // left, top, right, bottom
119 | canvas.drawText(text, left + textSize, top + textSize * 4 / 3, textPaint);
120 |
121 |
122 | ReadableMap secondText = options.getMap("secondText");
123 | String backgroundColor2 = secondText.getString("backgroundColor");
124 | float backgroundOpacity2 = (float) (secondText.getDouble("backgroundOpacity"));
125 |
126 | // draw text container container
127 | Paint containerPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
128 | containerPaint2.setColor(Color.parseColor(backgroundColor2));
129 | containerPaint2.setStyle(Paint.Style.FILL);
130 | int opacity2 = (int) (255 * backgroundOpacity2);
131 | containerPaint2.setAlpha(opacity2);
132 |
133 | String fontColor2 = secondText.getString("textColor");
134 | int fontSize2 = secondText.getInt("fontSize");
135 | String text2 = secondText.getString("text");
136 |
137 | // draw text Paint
138 | Paint textPaint2 = new Paint();
139 | textPaint2.setColor(Color.parseColor(fontColor2));
140 |
141 | // convert pixel to sp
142 | // float scaledDensity = _reactContext.getResources().getDisplayMetrics().scaledDensity;
143 | // textPaint.setTextSize(fontSize/scaledDensity);
144 | textPaint2.setTextSize(fontSize2);
145 | float textSize2 = textPaint2.getTextSize();
146 | float containerWidth2 = textPaint2.measureText(text2) + textSize2 * 2;
147 |
148 | int top2 = secondText.getInt("top");
149 | int left2 = secondText.getInt("left");
150 | // draw paint in canvas
151 | canvas.drawRect(left2, top2, left2 + containerWidth2, top2 + textSize2 * 2, containerPaint2); // left, top, right, bottom
152 | canvas.drawText(text2, left2 + textSize2, top2 + textSize2 * 4 / 3, textPaint2);
153 |
154 |
155 | int bytes = bitmap.getByteCount();
156 | ByteBuffer buffer = ByteBuffer.allocate(bytes);
157 | bitmap.copyPixelsToBuffer(buffer);
158 |
159 | // Save into Camera Roll
160 | String uri = MediaStore.Images.Media.insertImage(_reactContext.getContentResolver(), bitmap, "", "");
161 |
162 | byte[] data = buffer.array();
163 | String dataString = new String(data);
164 |
165 | File out = getOutputFile(TYPE_IMAGE);
166 |
167 | writeDataToFile(data, out);
168 |
169 | promise.resolve(out.getAbsolutePath());
170 | } else {
171 | promise.reject("rejected", "Data file not found");
172 | }
173 | }
174 |
175 |
176 | @Nullable
177 | private Throwable writeDataToFile(byte[] data, File file) {
178 | try {
179 | FileOutputStream fos = new FileOutputStream(file);
180 | fos.write(data);
181 | fos.close();
182 | } catch (FileNotFoundException e) {
183 | return e;
184 | } catch (IOException e) {
185 | return e;
186 | }
187 |
188 | return null;
189 | }
190 |
191 | @Nullable
192 | private File getOutputFile(int type) {
193 | File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
194 |
195 | // Create storage dir if it does not exist
196 | if (!storageDir.exists()) {
197 | if (!storageDir.mkdirs()) {
198 | Log.e(TAG, "Failed to create directory:" + storageDir.getAbsolutePath());
199 | return null;
200 | }
201 | }
202 |
203 | // media file name
204 | String fileName = String.format("%s", new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()));
205 |
206 |
207 | if (type == TYPE_IMAGE) {
208 | fileName = String.format("IMG_%s.jpg", fileName);
209 | } else if (type == TYPE_VIDEO) {
210 | fileName = String.format("VID_%s.mp4", fileName);
211 | } else {
212 | Log.e(TAG, "Unsupported media type:" + type);
213 | return null;
214 | }
215 | Log.d("example", String.format("%s%s%s", storageDir.getPath(), File.separator, fileName));
216 |
217 | return new File(String.format("%s%s%s", storageDir.getPath(), File.separator, fileName));
218 | }
219 |
220 |
221 | public void embedTextOnVideo(ReadableMap options, Promise promise) {
222 | this._promise = promise;
223 |
224 | FFmpeg ffmpeg = FFmpeg.getInstance(_reactContext);
225 | try {
226 | ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
227 |
228 | @Override
229 | public void onStart() {
230 | }
231 |
232 | @Override
233 | public void onFailure() {
234 | }
235 |
236 | @Override
237 | public void onSuccess() {
238 | }
239 |
240 | @Override
241 | public void onFinish() {
242 | }
243 | });
244 | } catch (FFmpegNotSupportedException e) {
245 | // Handle if FFmpeg is not supported by device
246 | }
247 |
248 | String path = options.getString("path");
249 | ReadableMap firstText = options.getMap("firstText");
250 | String text = firstText.getString("text");
251 | String fontColor = firstText.getString("textColor");
252 | String backgroundColor = firstText.getString("backgroundColor");
253 | int fontSize = firstText.getInt("fontSize");
254 | float backgroundOpaciy = (float)firstText.getDouble("backgroundOpacity");
255 |
256 | ReadableMap secondText = options.getMap("secondText");
257 | String text2 = secondText.getString("text");
258 | String fontColor2 = secondText.getString("textColor");
259 | String backgroundColor2 = secondText.getString("backgroundColor");
260 | int fontSize2 = secondText.getInt("fontSize");
261 | float backgroundOpaciy2 = (float)secondText.getDouble("backgroundOpacity");
262 |
263 | File out = getOutputFile(TYPE_VIDEO);
264 |
265 | String[] cmd = new String[] {
266 | "-i", path, "-c:v", "libx264", "-preset", "ultrafast", "-filter_complex",
267 | "drawtext=fontfile=/system/fonts/Roboto-Regular.ttf:text=" +
268 | text + ":x=(w-text_w)/2:y=(h-text_h-line_h)/2" +":fontcolor=" + fontColor + ":fontsize=" + fontSize +
269 | ":box=1:boxcolor="+backgroundColor+"@"+backgroundOpaciy+":boxborderw="+(fontSize/2) + "," +
270 | "drawtext=fontfile=/system/fonts/Roboto-Regular.ttf:text=" +
271 | text2 + ":x=(w-text_w)/2:y=(h-text_h-line_h)/4" +":fontcolor=" + fontColor2 + ":fontsize=" + fontSize2 +
272 | ":box=1:boxcolor="+backgroundColor2+"@"+backgroundOpaciy2+":boxborderw="+(fontSize2/2),
273 | out.getAbsolutePath()
274 | };
275 |
276 | try {
277 | // to execute "ffmpeg -version" command you just need to pass "-version"
278 | ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
279 |
280 | @Override
281 | public void onStart() {
282 | Log.d("example", "start ffmpeg");
283 | }
284 |
285 | @Override
286 | public void onProgress(String message) {
287 | Log.d("example", "onProgress: " + message);
288 | }
289 |
290 | @Override
291 | public void onFailure(String message) {
292 | Log.e("example", "Error ffmpeg executing with message:\n\t" + message);
293 | }
294 |
295 | @Override
296 | public void onSuccess(String message) {
297 | Log.d("example", "Successfully output file with message:\n\t");
298 | RNMediaEditorModule._promise.resolve("saved video output");
299 | }
300 |
301 | @Override
302 | public void onFinish() {
303 | }
304 | });
305 | } catch (FFmpegCommandAlreadyRunningException e) {
306 | // Handle if FFmpeg is already running
307 | }
308 | }
309 |
310 | }
311 |
--------------------------------------------------------------------------------
/ios/RNMediaEditor.m:
--------------------------------------------------------------------------------
1 | #import "RNMediaEditor.h"
2 | #import "RCTImageLoader.h"
3 | #import
4 | #import
5 | #import
6 | #import
7 |
8 |
9 | @interface RNMediaEditor ()
10 |
11 | @property (nonatomic, strong) NSMutableDictionary *options;
12 |
13 | @end
14 |
15 |
16 | @implementation RNMediaEditor {
17 | NSString *_imageAssetPath;
18 | }
19 |
20 |
21 | @synthesize bridge = _bridge;
22 |
23 | - (dispatch_queue_t)methodQueue
24 | {
25 | return dispatch_get_main_queue();
26 | }
27 | RCT_EXPORT_MODULE()
28 |
29 | - (NSDictionary *)constantsToExport
30 | {
31 | return @{
32 | @"AssetType": @{
33 | @"Image": @"image",
34 | @"Video": @"video"
35 | }
36 | };
37 | }
38 |
39 |
40 | - (UIColor *)colorFromHexString:(NSString *)hexString Alpha:(float)alpha {
41 | unsigned rgbValue = 0;
42 | NSScanner *scanner = [NSScanner scannerWithString:hexString];
43 | [scanner setScanLocation:1]; // bypass '#' character
44 | [scanner scanHexInt:&rgbValue];
45 | return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 \
46 | green:((rgbValue & 0xFF00) >> 8)/255.0 \
47 | blue:(rgbValue & 0xFF)/255.0 alpha:alpha];
48 | }
49 |
50 |
51 | /*
52 | * options
53 | * @type: integer required [0,1]
54 | * @data: base64 string required
55 | * @text: string required
56 | * @subText: string optional
57 | * @fontSize: integer optional
58 | * @textColor: string optional
59 | * @backgroundColor: string optional
60 | * @backgroundOpacity: float optional
61 | * @top: integer optional
62 | * @left: integer optional
63 | * @subTop: integer optional
64 | * @subLeft: integer optional
65 | */
66 | RCT_EXPORT_METHOD
67 | (
68 | embedText:(NSDictionary *)options
69 | resolve:(RCTPromiseResolveBlock)resolve
70 | reject:(RCTPromiseRejectBlock)reject
71 | )
72 | {
73 | self.options = options;
74 | NSString *type = [self.options valueForKey:@"type"];
75 |
76 | if ([type isEqualToString:@"image"]) {
77 | [self embedTextOnImage:options resolver:resolve rejecter:reject];
78 |
79 | } else if ([type isEqualToString:@"video"]) {
80 | [self embedTextOnVideo:options resolver:resolve rejecter:reject];
81 |
82 | } else {
83 | NSError *error = [NSError errorWithDomain: @"rnmediaeditor" code:1 userInfo:nil];
84 | reject(@"invalid_options", @"argument options invalid type", error);
85 | }
86 | }
87 |
88 |
89 | -(void)
90 | embedTextOnImage:(NSDictionary *)options
91 | resolver:(RCTPromiseResolveBlock)resolve
92 | rejecter:(RCTPromiseRejectBlock)reject
93 | {
94 | self.options = options;
95 | NSDictionary *firstText = [options objectForKey:@"firstText"];
96 | NSDictionary *secondText = [options objectForKey:@"secondText"];
97 |
98 | NSString *base64str = [options objectForKey:@"data"];
99 | NSData *data = [[NSData alloc]
100 | initWithBase64EncodedString:base64str
101 | options:NSDataBase64DecodingIgnoreUnknownCharacters];
102 | UIImage *image = [UIImage imageWithData:data];
103 |
104 |
105 | NSNumber *fontSizeNumber = [firstText objectForKey:@"fontSize"];
106 | NSInteger fontSize = abs(fontSizeNumber.intValue);
107 |
108 | UIColor *textColor =
109 | [self colorFromHexString:[firstText objectForKey:@"textColor"] Alpha:1.0];
110 |
111 | NSNumber *backgroundOpacityNumber = [firstText objectForKey:@"backgroundOpacity"];
112 | float backgroundOpacity = backgroundOpacityNumber.floatValue;
113 |
114 | UIColor *backgroundColor =
115 | [self colorFromHexString:[firstText objectForKey:@"backgroundColor"] Alpha:backgroundOpacity];
116 |
117 | NSNumber *topNumber = [firstText objectForKey:@"top"];
118 | NSNumber *leftNumber = [firstText objectForKey:@"left"];
119 | CGFloat top = topNumber.floatValue;
120 | CGFloat left = leftNumber.floatValue;
121 |
122 | NSString *text = [firstText objectForKey:@"text"];
123 |
124 | // create font and size of font
125 | UIFont *font = [UIFont boldSystemFontOfSize:fontSize];
126 | CGSize size = [text sizeWithFont:font];
127 |
128 | // create rect of image
129 | UIGraphicsBeginImageContext(image.size);
130 | [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
131 |
132 | // wrapper rect
133 | CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
134 |
135 | // the base point of text rect
136 | CGPoint point = CGPointMake(left, top);
137 |
138 |
139 | [backgroundColor set];
140 |
141 |
142 | CGRect textContainer = CGRectMake(point.x, point.y, size.height * 2, size.width + fontSize * 2);
143 |
144 | CGContextFillRect(
145 | UIGraphicsGetCurrentContext(),
146 | textContainer
147 | );
148 |
149 | CGRect textRect = CGRectMake(point.x + fontSize/2, point.y + size.height / 4, size.height, size.width + fontSize * 2);
150 |
151 | [textColor set];
152 | [text drawInRect:textRect
153 | withFont:font
154 | lineBreakMode:UILineBreakModeClip
155 | alignment:UITextAlignmentLeft ];
156 |
157 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
158 | UIGraphicsEndImageContext();
159 | NSData* jpgData = [[NSData alloc] initWithData:UIImageJPEGRepresentation(newImage, 1.0f)];
160 | UIImage *image2 = [UIImage imageWithData:jpgData];
161 |
162 |
163 | // again to second text
164 | NSNumber *fontSizeNumber2 = [secondText objectForKey:@"fontSize"];
165 | NSInteger fontSize2 = abs(fontSizeNumber2.intValue);
166 |
167 | UIColor *textColor2 =
168 | [self colorFromHexString:[secondText objectForKey:@"textColor"] Alpha:1.0];
169 |
170 | NSNumber *backgroundOpacityNumber2 = [secondText objectForKey:@"backgroundOpacity"];
171 | float backgroundOpacity2 = backgroundOpacityNumber2.floatValue;
172 |
173 | UIColor *backgroundColor2 =
174 | [self colorFromHexString:[secondText objectForKey:@"backgroundColor"] Alpha:backgroundOpacity2];
175 |
176 | NSNumber *topNumber2 = [secondText objectForKey:@"top"];
177 | NSNumber *leftNumber2 = [secondText objectForKey:@"left"];
178 | CGFloat top2 = topNumber2.floatValue;
179 | CGFloat left2 = leftNumber2.floatValue;
180 |
181 | NSString *text2 = [secondText objectForKey:@"text"];
182 |
183 | // create font and size of font
184 | UIFont *font2 = [UIFont boldSystemFontOfSize:fontSize2];
185 | CGSize size2 = [text2 sizeWithFont:font2];
186 |
187 | // create rect of image
188 | UIGraphicsBeginImageContext(image.size);
189 | [image2 drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
190 |
191 | // wrapper rect
192 | CGRect rect2 = CGRectMake(0, 0, image.size.width, image.size.height);
193 |
194 | // the base point of text rect
195 | CGPoint point2 = CGPointMake(left2, top2);
196 | [backgroundColor2 set];
197 |
198 |
199 | CGRect textContainer2 = CGRectMake(point2.x, point2.y, size2.width + fontSize2*1, size2.height * 1.5);
200 |
201 | CGContextFillRect(
202 | UIGraphicsGetCurrentContext(),
203 | textContainer2
204 | );
205 |
206 | CGRect textRect2 = CGRectMake(point2.x + fontSize2/2, point2.y + textContainer2.size.height / 4, size2.width, size2.height);
207 |
208 | [textColor2 set];
209 | [text2 drawInRect:textRect2
210 | withFont:font2
211 | lineBreakMode:UILineBreakModeClip
212 | alignment:UITextAlignmentLeft ];
213 |
214 |
215 | UIImage *newImage2 = UIGraphicsGetImageFromCurrentImageContext();
216 | UIGraphicsEndImageContext();
217 | NSData* jpgData2 = [[NSData alloc] initWithData:UIImageJPEGRepresentation(newImage2, 1.0f)];
218 | NSString* jpg64Str = [jpgData2 base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
219 |
220 |
221 | resolve(@[@"embed text on image", jpg64Str]);
222 | }
223 |
224 |
225 |
226 |
227 |
228 | -(void)embedTextOnVideo:(NSDictionary *)options
229 | resolver:(RCTPromiseResolveBlock)resolve
230 | rejecter:(RCTPromiseRejectBlock)reject
231 | {
232 | self.options = options;
233 | NSDictionary *firstText = [options objectForKey:@"firstText"];
234 | NSDictionary *secondText = [options objectForKey:@"secondText"];
235 |
236 | NSString *urlStr = [options objectForKey:@"path"];
237 | NSURL *url = [NSURL fileURLWithPath:urlStr];
238 |
239 | AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
240 |
241 | AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
242 | AVMutableCompositionTrack *mutableCompositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
243 |
244 | AVAssetTrack *baseVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
245 |
246 | [mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, baseVideoTrack.timeRange.duration) ofTrack:baseVideoTrack atTime:kCMTimeZero error:nil];
247 |
248 | // prpare instruction
249 | AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
250 | mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
251 | AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack];
252 | mainInstruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
253 |
254 | // check orientation
255 | CGSize size = baseVideoTrack.naturalSize;
256 |
257 | // create text1
258 | CATextLayer *subtitle1Text = [[CATextLayer alloc] init];
259 | NSString *text1 = [firstText objectForKey:@"text"];
260 |
261 | // create font and size of font
262 | [subtitle1Text setFont:@"Helvetica-Bold"];
263 | NSNumber *fontSizeNumber1 = [firstText objectForKey:@"fontSize"];
264 | NSInteger fontSize1 = abs(fontSizeNumber1.integerValue);
265 | UIFont *font1 = [UIFont boldSystemFontOfSize:fontSize1];
266 | CGSize textSize1 = [text1 sizeWithFont:font1];
267 | NSNumber *topN1 = [firstText objectForKey:@"top"];
268 | NSNumber *leftN1 = [firstText objectForKey:@"left"];
269 | [subtitle1Text setFontSize:fontSize1];
270 |
271 | // [subtitle1Text setFrame:CGRectMake(leftN1.integerValue, topN1.integerValue, textSize1.width + fontSize1*2, textSize1.height * 2)];
272 | [subtitle1Text setFrame:CGRectMake(leftN1.integerValue, topN1.integerValue, size.width, 30)];
273 | [subtitle1Text setString:text1];
274 | [subtitle1Text setAlignmentMode:kCAAlignmentCenter];
275 |
276 | UIColor *textColor1 =
277 | [self colorFromHexString:[firstText objectForKey:@"textColor"] Alpha:1.0];
278 | [subtitle1Text setForegroundColor:[textColor1 CGColor]];
279 |
280 | NSNumber *backgroundOpacityNumber1 = [firstText objectForKey:@"backgroundOpacity"];
281 | float alpha1 = backgroundOpacityNumber1.floatValue;
282 |
283 | UIColor *backgroundColor1 = [self colorFromHexString:[firstText objectForKey:@"backgroundColor"] Alpha:alpha1];
284 | [subtitle1Text setBackgroundColor:[backgroundColor1 CGColor]];
285 |
286 |
287 | // create text2
288 | CATextLayer *subtitle2Text = [[CATextLayer alloc] init];
289 | NSString *text2 = [secondText objectForKey:@"text"];
290 |
291 | // create font and size of font
292 | [subtitle2Text setFont:@"Helvetica-Bold"];
293 | NSNumber *fontSizeNumber2 = [secondText objectForKey:@"fontSize"];
294 | NSInteger fontSize2 = abs(fontSizeNumber2.integerValue);
295 | UIFont *font2 = [UIFont boldSystemFontOfSize:fontSize2];
296 | CGSize textSize2 = [text2 sizeWithFont:font2];
297 | NSNumber *topN2 = [secondText objectForKey:@"top"];
298 | NSNumber *leftN2 = [secondText objectForKey:@"left"];
299 | [subtitle2Text setFontSize:fontSize2];
300 |
301 | // TODO 文字の場所をコントロールする
302 | // [subtitle1Text setFrame:CGRectMake(leftN1.integerValue, topN1.integerValue, textSize1.width + fontSize1*2, textSize1.height * 2)];
303 | [subtitle2Text setFrame:CGRectMake(abs(leftN2.integerValue), abs(topN2.integerValue), size.width, 30)];
304 | [subtitle2Text setString:text2];
305 | [subtitle2Text setAlignmentMode:kCAAlignmentCenter];
306 |
307 | UIColor *textColor2 =
308 | [self colorFromHexString:[secondText objectForKey:@"textColor"] Alpha:1.0];
309 | [subtitle2Text setForegroundColor:[textColor2 CGColor]];
310 |
311 | NSNumber *backgroundOpacityNumber2 = [secondText objectForKey:@"backgroundOpacity"];
312 | float alpha2 = backgroundOpacityNumber2.floatValue;
313 |
314 | UIColor *backgroundColor2 = [self colorFromHexString:[secondText objectForKey:@"backgroundColor"] Alpha:alpha2];
315 | [subtitle2Text setBackgroundColor:[backgroundColor2 CGColor]];
316 |
317 |
318 |
319 | // create overlay
320 | CALayer *overlayLayer = [CALayer layer];
321 | [overlayLayer addSublayer:subtitle1Text];
322 | [overlayLayer addSublayer:subtitle2Text];
323 | overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
324 | [overlayLayer setMasksToBounds:YES];
325 |
326 | // create parent layer
327 |
328 | CALayer *parentLayer = [CALayer layer];
329 | CALayer *videoLayer = [CALayer layer];
330 | parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
331 | videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
332 | [parentLayer addSublayer:videoLayer];
333 | [parentLayer addSublayer:overlayLayer];
334 |
335 | // create videocomposition to add textLayer on base video
336 | AVMutableVideoComposition *textLayerComposition = [AVMutableVideoComposition videoComposition];
337 | textLayerComposition.renderSize = size;
338 | textLayerComposition.frameDuration = CMTimeMake(1, 30);
339 | textLayerComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
340 | textLayerComposition.instructions = [NSArray arrayWithObject:mainInstruction];
341 |
342 |
343 | // static date formatter
344 | static NSDateFormatter *kDateFormatter;
345 | kDateFormatter = [[NSDateFormatter alloc] init];
346 | [kDateFormatter setDateFormat:@"yyyyMMddHHmmss"];
347 |
348 |
349 | // export AVComposition to CameraRoll
350 | AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
351 |
352 | exporter.videoComposition = textLayerComposition;
353 |
354 | exporter.outputURL = [[[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:@YES error:nil] URLByAppendingPathComponent:[kDateFormatter stringFromDate:[NSDate date]]] URLByAppendingPathExtension:CFBridgingRelease(UTTypeCopyPreferredTagWithClass((CFStringRef)AVFileTypeMPEG4, kUTTagClassFilenameExtension))];
355 |
356 | exporter.outputFileType = AVFileTypeMPEG4;
357 | exporter.shouldOptimizeForNetworkUse = YES;
358 |
359 | [exporter exportAsynchronouslyWithCompletionHandler:^{
360 | ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
361 | if ([assetsLibrary videoAtPathIsCompatibleWithSavedPhotosAlbum:exporter.outputURL]) {
362 | [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:exporter.outputURL completionBlock:^(NSURL *assetURL, NSError *assetError){
363 | if (assetURL) {
364 | NSLog(@"output: %@", assetURL.absoluteString);
365 | }
366 | resolve(@{@"path": exporter.outputURL.absoluteString, @"assetPath": assetURL.absoluteString});
367 | }];
368 | }
369 | }];
370 |
371 | }
372 |
373 |
374 | @end
375 |
--------------------------------------------------------------------------------
/projectFilesBackup/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
74 |
75 |
76 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | true
91 | DEFINITION_ORDER
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 | project
593 |
594 |
595 | true
596 |
597 |
598 |
599 | DIRECTORY
600 |
601 | false
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 | 1488468128507
618 |
619 |
620 | 1488468128507
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | true
127 | DEFINITION_ORDER
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 | 1488468128507
312 |
313 |
314 | 1488468128507
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
--------------------------------------------------------------------------------