react-native-photoeditorsdk
Version:
A React Native module for PhotoEditor SDK. Integrate the photo editor into your own HTML5, iOS or Android app - in minutes!
198 lines (184 loc) • 7.55 kB
JavaScript
import { Component } from 'react';
import { Image, NativeModules, Platform } from 'react-native';
import { Configuration } from './configuration';
const { RNPhotoEditorSDK } = NativeModules;
function resolveStaticAsset(assetSource, extractURI = true) {
const resolvedSource = Image.resolveAssetSource(assetSource);
const source = (resolvedSource != null) ? resolvedSource : assetSource;
if (extractURI) {
return (source == null) ? null : ((source.uri != null) ? source.uri : source);
}
return source
}
function getNestedObject(nestedObject, pathArray) {
return pathArray.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObject);
}
function resolveNestedAsset(nestedObject, pathArray) {
let asset = getNestedObject(nestedObject, pathArray);
// Resolve `asset` if it is a number (opaque type returned by require('./foo.png'))
if (asset && typeof asset === 'number') {
let key = pathArray.pop();
let obj = getNestedObject(nestedObject, pathArray);
obj[key] = resolveStaticAsset(asset);
}
}
function resolveStaticAssets(configuration) {
let videoClipCategories = getNestedObject(configuration, ["composition", "categories"]);
if (videoClipCategories) {
for (let category of videoClipCategories) {
resolveNestedAsset(category, ["thumbnailURI"]);
let videoClips = getNestedObject(category, ["items"]);
if (videoClips) {
for (let videoClip of videoClips) {
resolveNestedAsset(videoClip, ["thumbnailURI"]);
resolveNestedAsset(videoClip, ["videoURI"]);
}
}
}
}
let audioClipCategories = getNestedObject(configuration, ["audio", "categories"]);
if (audioClipCategories) {
for (let category of audioClipCategories) {
resolveNestedAsset(category, ["thumbnailURI"]);
let audioClips = getNestedObject(category, ["items"]);
if (audioClips) {
for (let audioClip of audioClips) {
resolveNestedAsset(audioClip, ["thumbnailURI"]);
resolveNestedAsset(audioClip, ["audioURI"]);
}
}
}
}
let filterCategories = getNestedObject(configuration, ["filter", "categories"]);
if (filterCategories) {
for (let category of filterCategories) {
resolveNestedAsset(category, ["thumbnailURI"]);
let filters = getNestedObject(category, ["items"]);
if (filters) {
for (let filter of filters) {
resolveNestedAsset(filter, ["lutURI"]);
}
}
}
}
let stickerCategories = getNestedObject(configuration, ["sticker", "categories"]);
if (stickerCategories) {
for (let category of stickerCategories) {
resolveNestedAsset(category, ["thumbnailURI"]);
let stickers = getNestedObject(category, ["items"]);
if (stickers) {
for (let sticker of stickers) {
resolveNestedAsset(sticker, ["thumbnailURI"]);
resolveNestedAsset(sticker, ["stickerURI"]);
}
}
}
}
let fonts = getNestedObject(configuration, ["text", "fonts"]);
if (fonts) {
for (let font of fonts) {
resolveNestedAsset(font, ["fontURI"]);
}
}
let overlays = getNestedObject(configuration, ["overlay", "items"]);
if (overlays) {
for (let overlay of overlays) {
resolveNestedAsset(overlay, ["thumbnailURI"]);
resolveNestedAsset(overlay, ["overlayURI"]);
}
}
let frames = getNestedObject(configuration, ["frame", "items"]);
if (frames) {
for (let frame of frames) {
resolveNestedAsset(frame, ["thumbnailURI"]);
resolveNestedAsset(frame, ["imageGroups", "top", "startURI"]);
resolveNestedAsset(frame, ["imageGroups", "top", "midURI"]);
resolveNestedAsset(frame, ["imageGroups", "top", "endURI"]);
resolveNestedAsset(frame, ["imageGroups", "left", "startURI"]);
resolveNestedAsset(frame, ["imageGroups", "left", "midURI"]);
resolveNestedAsset(frame, ["imageGroups", "left", "endURI"]);
resolveNestedAsset(frame, ["imageGroups", "right", "startURI"]);
resolveNestedAsset(frame, ["imageGroups", "right", "midURI"]);
resolveNestedAsset(frame, ["imageGroups", "right", "endURI"]);
resolveNestedAsset(frame, ["imageGroups", "bottom", "startURI"]);
resolveNestedAsset(frame, ["imageGroups", "bottom", "midURI"]);
resolveNestedAsset(frame, ["imageGroups", "bottom", "endURI"]);
}
}
let watermark = getNestedObject(configuration, ["watermark"]);
if (watermark) {
resolveNestedAsset(watermark, ["watermarkURI"]);
}
}
class PESDK {
/**
* Modally present a photo editor.
* @note EXIF meta data is only preserved in the edited image if and only if the source
* image is loaded from a local `file://` resource.
*
* @param {string | {uri: string} | number} image The source of the image to be edited.
* Can be either an URI (local, remote, data resource, or any other registered scheme for the
* React Native image loader), an object with a member `uri`, or an asset reference which can
* be optained by, e.g., `require('./image.png')` as `number`. If this parameter is `null`,
* the `serialization` parameter must not be `null` and it must contain an embedded source image.
* @param {Configuration} configuration The configuration used to initialize the editor.
* @param {object} serialization The serialization used to initialize the editor. This
* restores a previous state of the editor by re-applying all modifications to the loaded
* image.
*
* @return {Promise<PhotoEditorResult | null>} Returns a `PhotoEditorResult` or `null` if the editor
* is dismissed without exporting the edited image.
*/
static openEditor(image = null, configuration = null, serialization = null) {
resolveStaticAssets(configuration)
const source = resolveStaticAsset(image, Platform.OS == 'android');
if (Platform.OS == 'android') {
return RNPhotoEditorSDK.present(source, configuration, serialization != null ? JSON.stringify(serialization) : null);
} else {
return RNPhotoEditorSDK.present(source, configuration, serialization);
}
}
/**
* Unlock PhotoEditor SDK with a license.
*
* @param {string | object} license The license used to unlock the SDK. Can be either an URI
* pointing to a local `file://` resource that contains the license, the license as a string,
* or the license as an object which can be optained by, e.g., `require('./pesdk_license')`
* where the required license files must be named `./pesdk_license.ios.json` for the iOS license
* and `./pesdk_license.android.json` for the Android license file in order to get automatically
* resolved by the packager.
*/
static unlockWithLicense(license) {
return RNPhotoEditorSDK.unlockWithLicense(JSON.stringify(license));
}
}
class PhotoEditorModal extends Component {
state = {
visible: false
}
static getDerivedStateFromProps = (props, state) => {
const { image, configuration, serialization, onExport, onCancel, onError } = props;
if (props.visible && !state.visible) {
PESDK.openEditor(image, configuration, serialization).then(result => {
if (result !== null) {
onExport(result);
} else {
if (onCancel) {
onCancel();
}
}
}).catch((error) => {
if (onError) {
onError(error);
}
});
}
return ({ visible: props.visible })
}
render() {
return null;
}
}
export * from './configuration';
export { PESDK, PhotoEditorModal };