C/C++ Quickstart
Getting started with Perfectly Clear SDK in C/C++
This guide walks you through correcting your first image using the Perfectly Clear SDK. This is a very simple example - it AI Scene Detection with the default Universal model. See the Sample projects section later in this guide for more complex examples, including using single presets, re-processing the same image with different correction parameters, and different I/O methods.
Project structure
Set up your project directory with the SDK extracted alongside your source files. Your project structure should look like this:
my-project/
├── main.cpp
├── Makefile
├── sample.jpg
└── perfectly-clear-sdk/
└── Linux/
├── header/
│ ├── PerfectlyClearPro.h
│ └── PFCImageFile.h
├── bin/
│ ├── (all necessary .pnn model files)
│ ├── libPerfectlyClearPro.a
│ ├── libPFCImageFile.a
│ ├── libwebp.a
│ ├── liblcms2.so.2
│ └── libexiv2.so.26
└── sdk_license/
└── (license files)Activate the SDK license
Before processing images, activate your SDK license using PFC_SetProtectionPath(). Point it to the directory containing your license files.
#include "PerfectlyClearPro.h"
int licenseStatus = PFC_SetProtectionPath("./perfectly-clear-sdk/sdk_license");
if (licenseStatus == 0 || licenseStatus == 102 || licenseStatus == 103) {
printf("SDK license activated successfully\n");
} else {
printf("License activation failed (status: %d)\n", licenseStatus);
return 1;
}Status codes 0, 102 (active license), and 103 (active trial) indicate success. Any other code means that activation failed.
When you're done, call PFC_ReleaseProtectionPath() to release license resources.
Load an image
Use PFCImageFile to load an image from disk, then populate a PFCIMAGE structure for processing.
#include "PFCImageFile.h"
PFCImageFile imageFile;
if (imageFile.LoadImageFile("input.jpg", true, NULL) != LOAD_OK) {
printf("Failed to load image\n");
return 1;
}
PFCIMAGE image = {
imageFile.width,
imageFile.height,
imageFile.stride,
(PFCPIXELFORMAT)imageFile.pfcImageFormat(),
imageFile.raw_image
};
// rotate image according to EXIF orientation tag
PFC_TransposeExif(&image, imageFile.exifOrientation()); The second parameter (true) converts the image to sRGB color space, which is recommended for best results.
Apply auto-correction with Universal AI Model
Create an engine and call PFC_AutoCorrect().
PFCENGINE* pEngine = PFC_CreateEngine();
// Load AI engine (assuming all dlls and models are in exe folder):
std::string exePath = std::string(argv[0]);
std::string binPath = exePath.substr(0, exePath.find_last_of('/')).c_str();
int aistatus = PFC_LoadAIEngine(pAiEngine, AI_SCENE_DETECTION | AI_CORRECTIONS | AI_COLOR | AI_FACEMESH, binPath.c_str());
// We set params within AutoCorrect(), so this can start out empty.
PFCPARAM ignoredParam;
int result = PFC_AutoCorrect(&image, NULL, ignoredParam, -1, NULL, false, NULL, pEngine, false);
if (result < APPLY_SUCCESS) {
printf("Correction failed: %d\n", result);
PFC_DestroyEngine(pEngine);
PFC_ReleaseProtectionPath();
return 1;
}
PFC_DestroyEngine(pEngine);Save output
Save the corrected image using SaveImageFile().
// return image to original orientation before saving
PFC_TransposeExif(&image, -imageFile.exifOrientation());
if (imageFile.SaveImageFile("output.jpg", 90, true, true)) {
printf("Saved to: output.jpg\n");
} else {
printf("Failed to save output\n");
return 1;
}Parameters are: output path, JPEG quality (0-100), convert back to original color space, and preserve metadata.
Complete example
Create main.cpp:
#include <stdio.h>
extern "C" {
#include "PerfectlyClearPro.h"
}
#include "PFCImageFile.h"
int main(int argc, char* argv[]) {
if (argc < 3) {
printf("Usage: %s <input.jpg> <output.jpg>\n", argv[0]);
return 1;
}
const char* inputFile = argv[1];
const char* outputFile = argv[2];
// Activate SDK license
int licenseStatus = PFC_SetProtectionPath("./perfectly-clear-sdk/sdk_license");
if (licenseStatus == 0 || licenseStatus == 102 || licenseStatus == 103) {
printf("SDK license activated successfully\n");
} else {
printf("License activation failed (status: %d)\n", licenseStatus);
return 1;
}
// Load image
PFCImageFile imageFile;
if (imageFile.LoadImageFile(inputFile, true, NULL) != LOAD_OK) {
printf("Failed to load image: %s\n", inputFile);
return 1;
}
// Set up image structure
PFCIMAGE image = {
imageFile.width,
imageFile.height,
imageFile.stride,
(PFCPIXELFORMAT)imageFile.pfcImageFormat(),
imageFile.raw_image
};
// rotate image according to EXIF orientation tag
PFC_TransposeExif(&image, imageFile.exifOrientation());
PFCENGINE* pEngine = PFC_CreateEngine();
// Load AI engine (assuming all dlls and models are in exe folder):
std::string exePath = std::string(argv[0]);
std::string binPath = exePath.substr(0, exePath.find_last_of('/')).c_str();
int aistatus = PFC_LoadAIEngine(pAiEngine, AI_SCENE_DETECTION | AI_CORRECTIONS | AI_COLOR | AI_FACEMESH, binPath.c_str());
// We set params within AutoCorrect(), so this can start out empty.
PFCPARAM ignoredParam;
int result = PFC_AutoCorrect(&image, NULL, ignoredParam, -1, NULL, false, NULL, pEngine, false);
if (result < APPLY_SUCCESS) {
printf("Correction failed: %d\n", result);
PFC_DestroyEngine(pEngine);
PFC_ReleaseProtectionPath();
return 1;
}
PFC_DestroyEngine(pEngine);
printf("Image corrected successfully\n");
// Cleanup
PFC_DestroyEngine(pEngine);
PFC_ReleaseProtectionPath();
// Save output
// return image to original orientation before saving
PFC_TransposeExif(&image, -imageFile.exifOrientation());
if (imageFile.SaveImageFile(outputFile, 90, true, true)) {
printf("Saved to: %s\n", outputFile);
} else {
printf("Failed to save: %s\n", outputFile);
return 1;
}
return 0;
}Create Makefile:
CC = g++
SDK_ROOT = ./perfectly-clear-sdk
SDK_BIN = $(SDK_ROOT)/Linux/bin
SDK_HEADER = $(SDK_ROOT)/Linux/header
CFLAGS = -O2 -pthread -D_LINUX -I$(SDK_HEADER) -Wl,-R'$$ORIGIN/perfectly-clear-sdk/Linux/bin'
all: quick-cpp copy-deps
quick-cpp: main.cpp
$(CC) $(CFLAGS) -m64 -o $@ main.cpp \
$(SDK_BIN)/libPerfectlyClearPro.a \
$(SDK_BIN)/libPFCImageFile.a \
$(SDK_BIN)/libwebp.a \
$(SDK_BIN)/liblcms2.so.2 \
$(SDK_BIN)/libexiv2.so.26 \
-ldl
copy-deps:
@echo "Copying dependencies..."
cp $(SDK_BIN)/liblcms2.so.2 .
cp $(SDK_BIN)/libexiv2.so.26 .
cp $(SDK_BIN)/*pnn .
@echo "Build complete!"
clean:
rm -f quick-cpp *.so*
.PHONY: all copy-deps cleanBuild and run:
make
./quick-cpp sample.jpg corrected.jpgExpected output:
Copying dependencies...
Build complete!
SDK license activated successfully
Image corrected successfully
Saved to: corrected.jpgPFC-SDK Version 10.7.3.1317 built from df9dbc8727c92fb9b1d2c68b21e60ea9c7229e1a on 03-23-2026.
Copyright © 2026 EyeQ Imaging Inc. All rights reserved.