EyeQ Docs
Getting Started

Java (JNI) Quickstart

Getting started with Perfectly Clear SDK in Java using JNI

This guide walks you through correcting your first image using the Perfectly Clear SDK with Java via JNI. The JNI interface provides native performance with Java convenience, suitable for server-side processing and desktop applications.

The JNI API mirrors the Android SDK closely, making it easy to share code between mobile and server applications.

Project structure

Set up your project directory with the SDK extracted alongside your Java source files.

my-project/
├── Test.java
├── sample.jpg
└── perfectly-clear-sdk/
    └── Linux/
        ├── jni/
        │   ├── PfC.java
        │   ├── PFCParam.java
        │   ├── PFCImageFile.java
        │   ├── PFCFaceRect.java
        │   ├── FaceInfo.java
        │   └── SelectiveColor.java
        ├── bin/
        │   ├── libPerfectlyClearProJNI.so
        │   ├── libPerfectlyClearPro.so
        │   ├── libPFCImageFile.so
        │   ├── (all necessary .pnn model files)
        │   └── libonnxruntime.so.1.5.1
        ├── presets/
        │   └── universal.preset
        └── sdk_license/
            └── (license files)

Load native libraries

The JNI wrapper requires loading native libraries before use. On Windows, load dependencies explicitly; on Linux/macOS, load just the JNI library.

import photos.eyeq.pfcsdk.perfectlyclear.*;

static {
    String os = System.getProperty("os.name").toLowerCase();

    if (os.contains("win")) {
        // Windows: manually load dependencies in order
        System.loadLibrary("PerfectlyClearPro");
        System.loadLibrary("exiv2");
        System.loadLibrary("PFCImageFile");
        System.loadLibrary("onnxrunt151");
    }

    System.loadLibrary("PerfectlyClearProJNI");
}

Ensure the library path includes your SDK bin directory. Run with:

java -Djava.library.path=./perfectly-clear-sdk/Linux/bin Test

Create an engine and load AI models

Create an engine instance and load AI models for scene detection and corrections.

PfC sdk = new PfC();
ByteBuffer engine = sdk.createEngine();

// AI feature flags: 1=Scene Detection, 2=Corrections, 32=FaceMesh
int aiFeatures = 1 + 2 + 32;
String binPath = "./perfectly-clear-sdk/Linux/bin";

int status = sdk.loadAIEngine(engine, aiFeatures, binPath);
if (status != aiFeatures) {
    System.out.println("Warning: not all AI features loaded, status=" + status);
}

Load scene presets

Load scene detection presets from a .preset file using memory-mapped I/O.

import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.io.RandomAccessFile;

try (RandomAccessFile file = new RandomAccessFile("presets/universal.preset", "r")) {
    FileChannel channel = file.getChannel();
    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());

    int result = sdk.loadScenePresets(engine, buffer);
    if (result != 0) {
        System.out.println("Failed to load scene presets: " + result);
    }
}

Load and process an image

Use PFCImageFile to load an image, analyze it, and apply corrections.

// Load image
PFCImageFile image = new PFCImageFile();
ByteBuffer pixels = image.LoadImageFile("input.jpg");

// Analyze image
ByteBuffer profile = sdk.calc(
    image.width, image.height, image.stride, image.pixelFormat,
    pixels,
    0, 0, 0, null,  // no downsampled image
    engine,
    1,  // fast FAE
    1   // skip tint calc
);

// Check for detected scene
int detectedScene = sdk.getDetectedScene(profile);
System.out.println("Detected scene: " + detectedScene);

// Load parameters for detected scene
PFCParam param = new PFCParam();
sdk.readScenePreset(param, engine, detectedScene);

// Apply corrections
int applyStatus = sdk.apply(
    image.width, image.height, image.stride, image.pixelFormat,
    pixels, engine, profile, param
);

if (applyStatus != 0) {
    System.out.println("Apply failed: " + applyStatus);
}

Save the corrected image

Save the processed image back to disk.

boolean saved = image.SaveImageFile("output.jpg");
if (saved) {
    System.out.println("Saved corrected image to output.jpg");
} else {
    System.out.println("Failed to save image");
}

Clean up resources

Release native resources when finished.

image.deletePFCImageFile();
sdk.releaseProfile(profile);
sdk.releaseAddonPath();
sdk.destroyEngine(engine);

Complete example

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import photos.eyeq.pfcsdk.perfectlyclear.*;

public class QuickStart {

    static {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            System.loadLibrary("PerfectlyClearPro");
            System.loadLibrary("exiv2");
            System.loadLibrary("PFCImageFile");
            System.loadLibrary("onnxrunt151");
        }
        System.loadLibrary("PerfectlyClearProJNI");
    }

    public static void main(String[] args) throws Exception {
        if (args.length < 1) {
            System.out.println("Usage: java QuickStart <input-image>");
            return;
        }

        String inputPath = args[0];
        String binPath = "./perfectly-clear-sdk/Linux/bin";

        // Initialize SDK
        PfC sdk = new PfC();
        ByteBuffer engine = sdk.createEngine();

        // Load AI models
        int aiFeatures = 1 + 2 + 32;  // SD + Corrections + FaceMesh
        sdk.loadAIEngine(engine, aiFeatures, binPath);

        // Load scene presets
        try (RandomAccessFile file = new RandomAccessFile("presets/universal.preset", "r")) {
            FileChannel channel = file.getChannel();
            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
            sdk.loadScenePresets(engine, buffer);
        }

        // Load image
        PFCImageFile image = new PFCImageFile();
        ByteBuffer pixels = image.LoadImageFile(inputPath);

        // Analyze
        ByteBuffer profile = sdk.calc(
            image.width, image.height, image.stride, image.pixelFormat,
            pixels, 0, 0, 0, null, engine, 1, 1
        );

        // Get scene and load preset
        int scene = sdk.getDetectedScene(profile);
        System.out.println("Detected scene: " + scene);

        PFCParam param = new PFCParam();
        sdk.readScenePreset(param, engine, scene);

        // Apply corrections
        sdk.apply(image.width, image.height, image.stride, image.pixelFormat,
            pixels, engine, profile, param);

        // Save output
        image.SaveImageFile("output.jpg");
        System.out.println("Saved corrected image to output.jpg");

        // Cleanup
        image.deletePFCImageFile();
        sdk.releaseProfile(profile);
        sdk.destroyEngine(engine);
    }
}

Compile and run:

# Compile (adjust classpath to include SDK Java files)
javac -cp ./perfectly-clear-sdk/Linux/jni:. QuickStart.java

# Run
java -Djava.library.path=./perfectly-clear-sdk/Linux/bin \
     -cp ./perfectly-clear-sdk/Linux/jni:. \
     QuickStart sample.jpg

Expected output:

Detected scene: 12
Saved corrected image to output.jpg

Next steps

PFC-SDK Version 11.0.0.1389 built from cc658dab3c675a529b3df2fa6421d4550810d77d on 06-29-2026.

Copyright © 2026 EyeQ Imaging Inc. All rights reserved.

On this page