Skip to main content

Getting Started

A quick guide on how to easily get started with the PhotoEditor SDK for Android. Your kick-off to delight your users with top-notch editing capabilities.

This document guides you through the process of integrating the PhotoEditor SDK into your Android application.

Free Trial#

Our tech is modified to be used for testing purposes without a license key. To start testing just follow this Get Started guide and set the license path to `null` instead of entering the commercial license path. The editor will simply render a watermark over the preview and final results. And in case you need any technical assistance, make sure to reach out to us: https://img.ly/support. We'll be glad to help.

Update for AndroidX#

You are now able to use AndroidX without affecting our PhotoEditor SDK. Google provides a new build tools version which fixes the bug. So please use buildToolsVersion '29.0.2' or higher when you are using AndroidX.

Integration Tutorial#

We made an awesome video tutorial for you.

Prerequisites#

The following software is required:

  • Mac OS X, Windows, or Linux
  • Android Studio 3.0+
  • Android Minimum SDK 16+ (Android 4.1.0 released 27. Juni 2012)
  • Gradle Plugin Version 3.5+
  • Gradle Version 6.1.1+
  • Android Build Tools 29.0.2+
  • Android Support Repository 28.0.0+
  • Kotlin Version 1.4.10+
  • License*

*The license is required to commercially use our tech in your application. Yet while testing no license file is required. For more information please see the FREE TRIAL note further up on this guide.

Supported Android versions#

The PhotoEditor SDK supports Android 4.1.0+ API 16 as the minSdkVersion, but it must be compiled with Build-API and targetSdkVersion Level 27+ to support Android 8.1 and above.

Add your license file#

Before using any components of the PhotoEditor SDK, you have to add your license file to your applications assets folder. The expected default name of the license file is “LICENSE”. In order to change this, see licencePath option of PESDKConfig in your gradle file. The license is digitally signed and can’t be altered without becoming invalid. Once the license file has been added the application will validate its presence upon launch.

Setting up the workspace#

Please ensure that our artifactory repository is listed in your repositories in the project's build.gradle file:

// Add the PESDK repository and plugin dependency
buildscript {
    repositories {
        google()
        gradlePluginPortal()
        maven { url 'https://artifactory.img.ly/artifactory/imgly' }
    }
    dependencies {
        // Insert the latest SDK version number here. You will find it here https://github.com/imgly/pesdk-android-demo/releases
        classpath 'ly.img.android.pesdk:plugin:8.3.0'
        // Add the Kotlin plugin
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10'
    }
}

You will also have to add the pesdk plugin and PESDKConfig into your module's build.gradle file:

// Apply the Android Plugin
apply plugin: 'com.android.application'

// Apply the PESDKPlugin
apply plugin: 'ly.img.android.sdk'
// Apply Kotlin Plugin
apply plugin: 'kotlin-android'

// Configure the PESDKPlugin
imglyConfig {

    pesdk {
        enabled true
        licencePath 'pesdk_android_license'
    }

    // Define the modules you are need
    modules {
        // Add all the UI modules you are need
        include 'ui:core'
        include 'ui:text'
        include 'ui:focus'
        include 'ui:frame'
        include 'ui:brush'
        include 'ui:filter'
        include 'ui:camera'
        include 'ui:sticker'
        include 'ui:overlay'
        include 'ui:transform'
        include 'ui:adjustment'
        include 'ui:text-design'


        // Add the serializer if you need
        include 'backend:serializer'

        // Add asset packs if you need
        include 'assets:font-basic'
        include 'assets:frame-basic'
        include 'assets:filter-basic'
        include 'assets:overlay-basic'
        include 'assets:sticker-shapes'
        include 'assets:sticker-emoticons'
    }
}

// Do your Android Configurations... ex.
android {
    /* Set the compile SDK and the Build SDK min. at SDK 29 or grater.
     * We can't provide support for Bugs, that are the result of older SDK versions.
     */
    compileSdkVersion 29
    buildToolsVersion '29.0.2'

    defaultConfig {
        /*
         * Replace with your App-ID and keep sure that it match with your license!
         * @see http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename
         */
        applicationId "my.domain.application"

        /* Set the minimum supported SDK Version to 18 (Android 4.3.0) or higher */
        minSdkVersion 18

        /* Set the target SDK Version at minimum to 29 or higher */
        targetSdkVersion 29

    }

    /* Set Java Language level to Java 1.8+ */
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

Sync your project with the Gradle files after every edit! For more information about Gradle, please take a look at the Android Developer Documentation

Android Permissions#

The PhotoEditor SDK requires two permissions: The "Write access to external storage" and the "Camera" permission (if you include the Camera module). You can grant this permissions yourself otherwise the SDK will automatically grant these permissions

Please take a look at the hint in the next step in order to integrate the Android 6.0 permission request correct!

Integration#

In order to open the camera preview and pass the resulting image to the editor, create a CameraPreviewBuilder and start the CameraPreviewActivity with startActivityForResult(android.app.Activity, int):

Please make sure you delegate the onRequestPermissionsResult() to onRequestPermissionsResult() as demonstrated in the following example. This ensures correct behavior on Android 6.0 and above.

class KCameraDemoActivity : Activity(), PermissionRequest.Response {

    companion object {
        const val PESDK_RESULT = 1
    }

    // Important permission request for Android 6.0 and above, don't forget to add this!
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        PermissionRequest.onRequestPermissionsResult(requestCode, permissions, grantResults)
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

    override fun permissionGranted() {}

    override fun permissionDenied() {
        /* TODO: The Permission was rejected by the user. The Editor was not opened,
         * Show a hint to the user and try again. */
    }

    // Create a empty new SettingsList and apply the changes on this referance.
    // If you have included our asset Packs and you want to use our default UI you also need to add them to the UI config,
    // otherwise they are only available for the backend link serialisation.
    // See the specific feature sections of our guides if you want to know how to add your own assets.
    private fun createPESDKSettingsList() = PhotoEditorSettingsList()
      .configure<UiConfigFilter> {
          it.setFilterList(FilterPackBasic.getFilterPack())
      }
      .configure<UiConfigText> {
          it.setFontList(FontPackBasic.getFontPack())
      }
      .configure<UiConfigFrame> {
          it.setFrameList(FramePackBasic.getFramePack())
      }
      .configure<UiConfigOverlay> {
          it.setOverlayList(OverlayPackBasic.getOverlayPack())
      }
      .configure<UiConfigSticker> {
          it.setStickerLists(
            StickerPackEmoticons.getStickerCategory(),
            StickerPackShapes.getStickerCategory()
          )
      }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        openCamera()
    }

    private fun openCamera() {
        val settingsList = createPESDKSettingsList()

        CameraPreviewBuilder(this)
          .setSettingsList(settingsList)
          .startActivityForResult(this, PESDK_RESULT)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent) {
        super.onActivityResult(requestCode, resultCode, intent)

        if (resultCode == RESULT_OK && requestCode == PESDK_RESULT) {
            // Editor has saved an Image.
            val data = EditorSDKResult(intent)

            Log.i("PESDK", "Source image is located here ${data.sourceUri}")
            Log.i("PESDK", "Result image is located here ${data.resultUri}")

            // TODO: Do something with the result image

            // OPTIONAL: read the latest state to save it as a serialisation
            val lastState = data.settingsList
            try {
                IMGLYFileWriter(lastState).writeJson(File(
                  Environment.getExternalStorageDirectory(),
                  "serialisationReadyToReadWithPESDKFileReader.json"
                ))
            } catch (e: IOException) {
                e.printStackTrace()
            }

        } else if (resultCode == RESULT_CANCELED && requestCode == PESDK_RESULT) {
            // Editor was canceled
            val data = EditorSDKResult(intent)

            val sourceURI = data.sourceUri
            // TODO: Do something...
        }
    }


}

Start Editor standalone (without camera).#

If you want to open the editor directly with an existing image look at this example:

class KEditorDemoActivity : Activity(), PermissionRequest.Response {

    companion object {
        const val PESDK_RESULT = 1
        const val GALLERY_RESULT = 2
    }

    // Important permission request for Android 6.0 and above, don't forget to add this!
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        PermissionRequest.onRequestPermissionsResult(requestCode, permissions, grantResults)
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

    override fun permissionGranted() {}

    override fun permissionDenied() {
        /* TODO: The Permission was rejected by the user. The Editor was not opened,
         * Show a hint to the user and try again. */
    }

    // Create a empty new SettingsList and apply the changes on this referance.
    // If you include our asset Packs and use our UI you also need to add them to the UI,
    // otherwise they are only available for the backend (like Serialisation)
    // See the specific feature sections of our guides if you want to know how to add our own Assets.
    private fun createPESDKSettingsList() =
      PhotoEditorSettingsList()
        .configure<UiConfigFilter> {
            it.setFilterList(FilterPackBasic.getFilterPack())
        }
        .configure<UiConfigText> {
            it.setFontList(FontPackBasic.getFontPack())
        }
        .configure<UiConfigFrame> {
            it.setFrameList(FramePackBasic.getFramePack())
        }
        .configure<UiConfigOverlay> {
            it.setOverlayList(OverlayPackBasic.getOverlayPack())
        }
        .configure<UiConfigSticker> {
          it.setStickerLists(
            StickerPackEmoticons.getStickerCategory(),
            StickerPackShapes.getStickerCategory()
          )
        }
        .configure<PhotoEditorSaveSettings> {
            it.setOutputToGallery(Environment.DIRECTORY_DCIM)
        }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        openSystemGalleryToSelectAnImage()
    }

    fun openSystemGalleryToSelectAnImage() {
        val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        if (intent.resolveActivity(packageManager) != null) {
            startActivityForResult(intent, GALLERY_RESULT)
        } else {
            Toast.makeText(
              this,
              "No Gallery APP installed",
              Toast.LENGTH_LONG
            ).show()
        }
    }

    fun openEditor(inputImage: Uri?) {
        val settingsList = createPESDKSettingsList()

        settingsList.configure<LoadSettings> {
            it.source = inputImage
        }

        settingsList[LoadSettings::class].source = inputImage

        PhotoEditorBuilder(this)
          .setSettingsList(settingsList)
          .startActivityForResult(this, PESDK_RESULT)
    }


    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent) {
        super.onActivityResult(requestCode, resultCode, intent)

        if (resultCode == RESULT_OK && requestCode == GALLERY_RESULT) {
            // Open Editor with some uri in this case with an image selected from the system gallery.
            openEditor(intent.data)

        } else if (resultCode == RESULT_OK && requestCode == PESDK_RESULT) {
            // Editor has saved an Image.
            val data = EditorSDKResult(intent)

            Log.i("PESDK", "Source image is located here ${data.sourceUri}")
            Log.i("PESDK", "Result image is located here ${data.resultUri}")

            // TODO: Do something with the result image

            // OPTIONAL: read the latest state to save it as a serialisation
            val lastState = data.settingsList
            try {
                IMGLYFileWriter(lastState).writeJson(File(
                  Environment.getExternalStorageDirectory(),
                  "serialisationReadyToReadWithPESDKFileReader.json"
                ))
            } catch (e: IOException) {
                e.printStackTrace()
            }

        } else if (resultCode == RESULT_CANCELED && requestCode == PESDK_RESULT) {
            // Editor was canceled
            val data = EditorSDKResult(intent)

            val sourceURI = data.sourceUri
            // TODO: Do something with the source...
        }
    }

    private lateinit var videoUri1: Uri // Example code dummy
    private lateinit var videoUri2: Uri // Example code dummy

    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private fun openVideoComposition() {
        thread {
            val settingsList = ExampleConfigUtility.createInitialVESDKSettingsList()
            settingsList.configure<VideoCompositionSettings> {
                // Add a video
                it.addCompositionPart(
                    VideoCompositionSettings.VideoPart(videoUri1)
                )
                // Add another video, which is already trimmed from 3 until 10 seconds
                it.addCompositionPart(
                    VideoCompositionSettings.VideoPart(
                        videoUri2,
                        trimStartInNanoseconds = 3.convert(TimeUnit.SECONDS, TimeUnit.NANOSECONDS),
                        trimEndInNanoseconds = 10.convert(TimeUnit.SECONDS, TimeUnit.NANOSECONDS)
                    )
                )
            }
            // ATTENTION: You need to set a loading source the size and fps is taken from!
            settingsList.configure<LoadSettings> {
                // You could use a video or a empty composition source which is recommended.
                it.source = LoadSettings.compositionSource(
                    width = 1024, height = 1920,
                    framesPerSecond = 60
                )
            }

            // OPTIONAL: Set the entry point to VideoCompositionToolPanel
            settingsList.configure<UiConfigMainMenu> {
                it.setInitialTool(VideoCompositionToolPanel.TOOL_ID)

            }
        }
    }
}

Sample Application#

You can access the source code for our demo application from our demo repository.